summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2019-01-17 14:40:46 +0200
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-01-17 16:52:47 +0200
commit655da52e50a77f38241d6752cd5f641300059527 (patch)
tree15bacea3bc9a3bdc6f1cd0c8ac80847fbe212d82
parent31f115324b64aea83bdcb64e2f15d6363119d216 (diff)
parent1bd669b3a3ec9e7d8e5407d777ced79800fe677e (diff)
Merge branch 'master' into wip/runtime2
-rw-r--r--doc/qt3dstudio-project.qdocconf2
-rw-r--r--doc/src/00-concepts.qdoc45
-rw-r--r--doc/src/03-studio/0-menu.qdoc33
-rw-r--r--doc/src/03-studio/2-scene-view-and-matte.qdoc35
-rw-r--r--doc/src/03-studio/5-timeline-palette.qdoc85
-rw-r--r--doc/src/03-studio/7-inspector-palette.qdoc95
-rw-r--r--doc/src/03-studio/9-keyboard-shortcuts.qdoc10
-rw-r--r--doc/src/04-viewer/1-keyboard.qdoc49
-rw-r--r--doc/src/10-best-practices/practices-index.qdoc5
-rw-r--r--doc/src/11-quick-start-guides/quick-start-guide.qdoc (renamed from doc/src/11-quick-start-guides/10-getting-started.qdoc)5
-rw-r--r--doc/src/animations.qdoc205
-rw-r--r--doc/src/deployment.qdoc42
-rw-r--r--doc/src/getting-help.qdoc46
-rw-r--r--doc/src/getting-started.qdoc66
-rw-r--r--doc/src/graphics.qdoc68
-rw-r--r--doc/src/images/ApplicationPreferences.pngbin20613 -> 36068 bytes
-rw-r--r--doc/src/images/DisableDepthTest.pngbin6343 -> 20265 bytes
-rw-r--r--doc/src/images/Studio-Action.pngbin6286 -> 27240 bytes
-rw-r--r--doc/src/images/Studio-SceneView.pngbin51085 -> 87860 bytes
-rw-r--r--doc/src/images/Studio-Timeline-Breadcrumb.pngbin7494 -> 21763 bytes
-rw-r--r--doc/src/images/Studio-Timeline-Interpolation.pngbin10306 -> 6921 bytes
-rw-r--r--doc/src/images/Studio-Timeline-Overview.pngbin27960 -> 41312 bytes
-rw-r--r--doc/src/images/Studio-Timeline-SceneGraph.pngbin7890 -> 22222 bytes
-rw-r--r--doc/src/images/addAssets.pngbin41720 -> 76220 bytes
-rw-r--r--doc/src/images/component_timeline.pngbin2928 -> 18195 bytes
-rw-r--r--doc/src/images/copy-transform-settings.pngbin30970 -> 31500 bytes
-rw-r--r--doc/src/images/create-guides.pngbin0 -> 4197 bytes
-rw-r--r--doc/src/images/data-inputs.pngbin22818 -> 31536 bytes
-rw-r--r--doc/src/images/datainput-property-active-icon.pngbin3714 -> 17566 bytes
-rw-r--r--doc/src/images/dyn-keyframes-make-dynamic.pngbin5624 -> 22437 bytes
-rw-r--r--doc/src/images/dyn-keyframes-position.pngbin13320 -> 23339 bytes
-rw-r--r--doc/src/images/dyn-keyframes-slide.pngbin19429 -> 23178 bytes
-rw-r--r--doc/src/images/guide-properties.pngbin0 -> 21231 bytes
-rw-r--r--doc/src/images/import-assetes-dnd.pngbin15764 -> 29854 bytes
-rw-r--r--doc/src/images/light-properties.pngbin0 -> 40521 bytes
-rw-r--r--doc/src/images/material-open-in-inspector.pngbin0 -> 9303 bytes
-rw-r--r--doc/src/images/open-presentation.pngbin26450 -> 33038 bytes
-rw-r--r--doc/src/images/presentation-size.pngbin6233 -> 20975 bytes
-rw-r--r--doc/src/images/slide-palette-data-input-active.pngbin11216 -> 25004 bytes
-rw-r--r--doc/src/images/slide-palette-data-input-inactive.pngbin29487 -> 29017 bytes
-rw-r--r--doc/src/images/slidePalette.pngbin5328 -> 19416 bytes
-rw-r--r--doc/src/images/slidePlayMode.pngbin8095 -> 22045 bytes
-rw-r--r--doc/src/images/subpresentation-layer-inspector.pngbin27009 -> 31240 bytes
-rw-r--r--doc/src/images/subpresentation-project-structure.pngbin29543 -> 29234 bytes
-rw-r--r--doc/src/images/timeline-datainput.pngbin8385 -> 22729 bytes
-rw-r--r--doc/src/images/timeline-text-edit.pngbin21705 -> 22282 bytes
-rw-r--r--doc/src/images/timeline-texts-icon.pngbin500 -> 14779 bytes
-rw-r--r--doc/src/images/timeline.pngbin14456 -> 28485 bytes
-rw-r--r--doc/src/images/view-scale-mode.pngbin5348 -> 7159 bytes
-rw-r--r--doc/src/scripting.qdoc53
-rw-r--r--doc/src/tutorials.qdoc57
-rw-r--r--doc/style/qt5-sidebar.html12
-rw-r--r--src/Authoring/Client/Code/Core/Commands/CmdDataModel.cpp30
-rw-r--r--src/Authoring/Client/Code/Core/Commands/CmdDataModel.h4
-rw-r--r--src/Authoring/Client/Code/Core/Commands/CmdStack.cpp27
-rw-r--r--src/Authoring/Client/Code/Core/Commands/CmdStack.h6
-rw-r--r--src/Authoring/Client/Code/Core/Doc/ComposerEditorInterface.cpp24
-rw-r--r--src/Authoring/Client/Code/Core/Doc/Doc.cpp104
-rw-r--r--src/Authoring/Client/Code/Core/Doc/Doc.h6
-rw-r--r--src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp58
-rw-r--r--src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp24
-rw-r--r--src/Authoring/Client/Code/Core/Doc/IDoc.h3
-rw-r--r--src/Authoring/Client/Code/Core/Utility/StudioPreferences.h2
-rw-r--r--src/Authoring/Client/Code/Core/Utility/q3dsdirwatcher.cpp9
-rw-r--r--src/Authoring/Common/Code/Qt3DSFileTools.cpp32
-rw-r--r--src/Authoring/Common/Code/Qt3DSFileTools.h2
-rw-r--r--src/Authoring/QT3DSDM/Systems/Qt3DSDMActionInfo.h4
-rw-r--r--src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp9
-rw-r--r--src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h3
-rw-r--r--src/Authoring/QT3DSDM/Systems/Qt3DSDMDataCore.h4
-rw-r--r--src/Authoring/QT3DSDM/Systems/Qt3DSDMTransactions.h9
-rw-r--r--src/Authoring/QT3DSDM/Systems/StudioPropertySystem.cpp20
-rw-r--r--src/Authoring/QT3DSDM/Systems/StudioPropertySystem.h3
-rw-r--r--src/Authoring/QT3DSIMP/Qt3DSImportLib/Qt3DSImportComposerTypes.cpp20
-rw-r--r--src/Authoring/QT3DSIMP/Qt3DSImportLib/Qt3DSImportComposerTypes.h16
-rw-r--r--src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportColladaSGTranslation.cpp147
-rw-r--r--src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportFbxSGTranslation.cpp171
-rw-r--r--src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportSceneGraphTranslation.cpp81
-rw-r--r--src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportSceneGraphTranslation.h8
-rw-r--r--src/Authoring/Studio/Application/DataInputListDlg.cpp76
-rw-r--r--src/Authoring/Studio/Application/DataInputListDlg.h2
-rw-r--r--src/Authoring/Studio/Application/DataInputSelectView.cpp18
-rw-r--r--src/Authoring/Studio/Application/DataInputSelectView.h16
-rw-r--r--src/Authoring/Studio/Application/ProjectFile.cpp54
-rw-r--r--src/Authoring/Studio/Application/ProjectFile.h2
-rw-r--r--src/Authoring/Studio/Application/StudioApp.cpp101
-rw-r--r--src/Authoring/Studio/Application/StudioApp.h4
-rw-r--r--src/Authoring/Studio/MainFrm.cpp74
-rw-r--r--src/Authoring/Studio/MainFrm.h4
-rw-r--r--src/Authoring/Studio/MainFrm.ui38
-rw-r--r--src/Authoring/Studio/Palettes/Action/ActionView.cpp184
-rw-r--r--src/Authoring/Studio/Palettes/Action/ActionView.h3
-rw-r--r--src/Authoring/Studio/Palettes/Action/EventsBrowser.qml110
-rw-r--r--src/Authoring/Studio/Palettes/Action/EventsBrowserView.cpp10
-rw-r--r--src/Authoring/Studio/Palettes/Action/EventsBrowserView.h8
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ChooserDelegate.qml2
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/DataInputChooser.qml8
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/FileChooserView.cpp29
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/FileChooserView.h4
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/GuideInspectable.cpp21
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/GuideInspectable.h2
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.cpp13
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.h1
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ImageChooserView.cpp12
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ImageChooserView.h4
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp284
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h8
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp156
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h36
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/MaterialRefView.cpp31
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/MaterialRefView.h7
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/MeshChooser.qml5
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/MeshChooserView.cpp39
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/MeshChooserView.h9
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp11
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.h4
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/TextureChooserView.cpp13
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/TextureChooserView.h4
-rw-r--r--src/Authoring/Studio/Palettes/PaletteManager.cpp1
-rw-r--r--src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.cpp49
-rw-r--r--src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.h7
-rw-r--r--src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.ui8
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectContextMenu.cpp15
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectContextMenu.h1
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp40
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectView.cpp5
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectView.h1
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideView.cpp2
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideView.qml18
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp6
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp38
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h5
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp9
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h1
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.cpp42
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.h2
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineToolbar.cpp2
-rw-r--r--src/Authoring/Studio/Render/IStudioRenderer.h2
-rw-r--r--src/Authoring/Studio/Render/Q3DStudioRenderer.cpp9
-rw-r--r--src/Authoring/Studio/Render/Q3DStudioRenderer.h2
-rw-r--r--src/Authoring/Studio/Render/StudioRenderer.cpp8
-rw-r--r--src/Authoring/Studio/Render/StudioRendererTranslation.cpp9
-rw-r--r--src/Authoring/Studio/Render/StudioSubPresentationRenderer.cpp17
-rw-r--r--src/Authoring/Studio/UI/StudioProjectSettingsPage.cpp3
-rw-r--r--src/Authoring/Studio/Workspace/Dialogs.cpp76
-rw-r--r--src/Authoring/Studio/Workspace/Dialogs.h3
m---------src/Runtime/qt3d-runtime0
147 files changed, 2608 insertions, 919 deletions
diff --git a/doc/qt3dstudio-project.qdocconf b/doc/qt3dstudio-project.qdocconf
index 78717d92..219af785 100644
--- a/doc/qt3dstudio-project.qdocconf
+++ b/doc/qt3dstudio-project.qdocconf
@@ -19,7 +19,7 @@ qhp.projects = Qt3DStudio
qhp.Qt3DStudio.file = qt3dstudio.qhp
qhp.Qt3DStudio.namespace = io.qt.qt3dstudio.$QT_VERSION_TAG
qhp.Qt3DStudio.virtualFolder = qt3dstudio
-qhp.Qt3DStudio.indexTitle = Qt 3D Studio
+qhp.Qt3DStudio.indexTitle = Qt 3D Studio Manual
qhp.Qt3DStudio.indexRoot =
qhp.Qt3DStudio.filterAttributes = qt3dstudio $QT_VERSION
diff --git a/doc/src/00-concepts.qdoc b/doc/src/00-concepts.qdoc
index a9f9d2d9..fa16e676 100644
--- a/doc/src/00-concepts.qdoc
+++ b/doc/src/00-concepts.qdoc
@@ -27,8 +27,8 @@
****************************************************************************/
/*!
-\keyword Qt 3D Studio
-\title Qt 3D Studio Index
+\keyword Qt 3D Studio Index
+\title Qt 3D Studio Manual
\page qt3dstudio-index.html
Qt 3D Studio is a compositing tool where you import 3D models, images and other assets to create
@@ -48,20 +48,18 @@ interactive presentations, UIs and applications.
\div {align="center"}
\image animation-index.png
\enddiv
- \li
- \div {align="center"}
- \image scripting-index.png
- \enddiv
+
\row
- \li \b {Getting Started}
+ \li \b {\l{Getting Started}}
\list
\li \l{About Qt 3D Studio}
- \li \l{Getting Started}{Quick Start Guide}
+ \li \l{Quick Start Guide}
+ \li \l{Tutorials}
\li \l{Best Practices}
\li \l{Studio Index}
\li \l{Viewer Index}
\endlist
- \li \b {Graphics}
+ \li \b {\l{Graphics}}
\list
\li \l{Working with 3D Content}{3D Assets}
\li \l{Layers}
@@ -70,42 +68,43 @@ interactive presentations, UIs and applications.
\li \l{Using Sub-Presentations}{Sub-Presentations}
\li \l{Stereoscopic Rendering}
\endlist
- \li \b {Animations}
+ \li \b {\l{Animations}}
\list
\li \l{Studio: Timeline Palette}{The Timeline}
\li \l{Dynamic Keyframes}
\endlist
- \li \b {Scripting}
- \list
- \li \l{Using Data Inputs}{Data Input}
- \li \l{Using Behavior Scripts}{Behavior}
- \li \l{File Formats}
- \endlist
\row
\li
\div {align="center"}
+ \image scripting-index.png
+ \enddiv
+ \li
+ \div {align="center"}
\image deployment-index.png
\enddiv
\li
\div {align="center"}
\image help-index.png
\enddiv
- \li
- \li
\row
- \li \b {Deployment}
+ \li \b {\l{Scripting}}
+ \list
+ \li \l{Using Data Inputs}{Data Input}
+ \li \l{Using Behavior Scripts}{Behavior}
+ \li \l{File Formats}
+ \endlist
+ \li \b {\l{Deployment}}
\list
\li \l{Viewer Remote Deployment}
\endlist
- \li \b {Getting Help}
+ \li \b {\l{Getting Help}}
\list
\li \l{Studio Keyboard Shortcuts}
\li \l{Viewer Keyboard Shortcuts}
\endlist
- \li
- \li
+
\row
- \li {4,1} \note To report bugs and suggestions to the Qt Bug
+ \li {3,1} \note To report bugs and suggestions to the Qt Bug
Tracker, visit \l https://bugreports.qt.io.
\endtable
diff --git a/doc/src/03-studio/0-menu.qdoc b/doc/src/03-studio/0-menu.qdoc
index 62cb85e0..d949f52f 100644
--- a/doc/src/03-studio/0-menu.qdoc
+++ b/doc/src/03-studio/0-menu.qdoc
@@ -46,34 +46,29 @@
Default location is the \e{presentations} folder in current project.
\endlist
\li
- \uicontrol{Open} - Opens a \c{.uip} presentation file.
-\li
- \uicontrol{Save} - Saves changes to the open presentation.
-\omit
+ \uicontrol{Duplicate Presentation} - Saves a copy of the open presentation to
+ the same folder and adds it to the project. The assets are not duplicated as they are
+ available via the same relative paths already.
\li
- \uicontrol{Save As} - Saves the presentation to a new location.
- No \c{.uia} file will be created or modified in the new location.
+ \uicontrol{Open} - Opens a \c{.uip} presentation file.
\li
- \uicontrol{Save a Copy} - Saves a copy of the presentation to a
- new location (but keep working on the current presentation). No
- \c{.uia} file will be created or modified in the new location.
-\endomit
+ \uicontrol{Recent Presentations} - Provides quick access to the last 10
+ presentations opened in Studio.
\li
- \uicontrol{Revert} - With confirmation, abandons all in-memory
+ \uicontrol{Revert to Last Save} - With confirmation, abandons all in-memory
changes to the presentation and re-opens it from disk.
\note this resets the state of Studio (resetting all components to the first
slide, playheads to time 0, etc.). This command is also a convenient
way to re-open a presentation that may have changed on disk, for
example via hand editing or source control updating.
\li
- \uicontrol{Import Assets} - Opens the assets library folder to import assets to your project.
+ \uicontrol{Save Presentation} - Saves changes to the open presentation.
\li
- \uicontrol{Data Inputs} - Manage \l{Using Data Inputs}{data inputs}.
+ \uicontrol{Save Project As} - Saves the open project and all its assets to a new location.
\li
- \uicontrol{Connect to Device} - Opens a dialog to connect to a remote device.
+ \uicontrol{Import} - Opens the assets library folder to import assets to your project.
\li
- \uicontrol{Recent Projects} - Provides quick access to the last 10
- projects opened in Studio.
+ \uicontrol{Data Inputs} - Manage \l{Using Data Inputs}{data inputs}.
\li
\uicontrol{Exit} - Quits Studio (prompting to save changes).
\endlist
@@ -100,6 +95,8 @@
\li
\uicontrol{Group Objects} - Creates a group and moves selected objects into that group.
\li
+ \uicontrol{Connect to Device} - Opens a dialog to connect to a remote device.
+\li
\uicontrol{Studio Preferences} - Opens the Studio Preferences dialog.
\image ApplicationPreferences.png
\list
@@ -109,7 +106,7 @@
\li
\uicontrol{Default Interpolation} - Controls whether new animation
keyframes are created with
- \l{studio-timeline-palette.html#interpolation}{linear or smooth interpolation}.
+ \l{animations.html#interpolation}{linear or smooth interpolation}.
\li
\uicontrol{Timeline Snapping Grid} - When using snapping in the
timeline, controls which ticks to snap to.
@@ -239,7 +236,7 @@
press the \c{Delete} key after selecting the keyframes to delete them.
\li
\uicontrol{Set Interpolation} - Changes the in and out
- \l{studio-timeline-palette.html#interpolation}{interpolation}
+ \l{animations.html#interpolation}{interpolation}
setting for the selected keyframes. This command is
also available from the context menu when right-clicking in the
animation portion of the \e{timeline palette}.
diff --git a/doc/src/03-studio/2-scene-view-and-matte.qdoc b/doc/src/03-studio/2-scene-view-and-matte.qdoc
index a84a613b..e312f0e7 100644
--- a/doc/src/03-studio/2-scene-view-and-matte.qdoc
+++ b/doc/src/03-studio/2-scene-view-and-matte.qdoc
@@ -109,6 +109,41 @@ In \b{Scale} mode:
scale.
\endlist
+\section2 Using Guides
+
+Guides help you position elements in the scene view. They appear as yellow lines overlaying the
+scene.
+
+\section3 Create a guide
+
+To create a guide, simply grab the ruler at the edge of the scene view and drag into the scene view.
+Dragging from the horizontal ruler will create a horizontal guide, while dragging from the vertical
+ruler will create a vertical guide.
+
+\image create-guides.png
+
+\section3 Delete a guide
+
+To delete a guide, grab it and drag it back to the ruler outside of the scene view. It is possible
+to delete all guides by selecting \uicontrol {View > Clear Guides} from the menu.
+
+\section3 Edit a guide
+
+To change the position of a guide, do one of the following:
+
+\list
+ \li
+ Drag and drop it to the new position using the mouse.
+ \li
+ Left-click it in the scene view. Then, in the inspector palette, enter the desired position in
+ pixels. (0,0) is the lower left corner of the scene view.
+\endlist
+
+\image guide-properties.png
+
+Additional properties available in the inspector palette allow you to set orientation and width for
+the selected guide.
+
\section1 Matte
Clicking the matte will deselect all selected objects in the presentation.
diff --git a/doc/src/03-studio/5-timeline-palette.qdoc b/doc/src/03-studio/5-timeline-palette.qdoc
index 2f1a4803..f385ebbd 100644
--- a/doc/src/03-studio/5-timeline-palette.qdoc
+++ b/doc/src/03-studio/5-timeline-palette.qdoc
@@ -309,86 +309,9 @@ palette. Clicking on these numbers will open the Go To Time palette,
where you may type in an exact time, down to milliseconds, to set
the playhead to.
-\section2 Adjusting Animation
+\section2 Working with Animations
-\image Studio-Timeline-Animation-Keyframes.png
-
-Most good visual effects do not "pop" into place, but provide a visual
-transition, even if brief, to help the user understand what happened.
-This is an example on what you can achieve with animations.
-
-\section3 Creating Keyframes
-
-To animate a property of an element, turn on the
-\l{studio-inspector-palette.html#animating-properties}{animation toggle
-in the Inspector palette}. This will add a new keyframe for that
-property at the current playhead time. If the property is not linked to
-the master slide (as with the position shown in the picture above) the
-animation will only be created on the current slide.
-
-To create a new keyframe, move the playhead to a new time and then
-do one of the following:
-
-\list
-\li
- Ensure that \l{studio-toolbar.html#keyframing}{Autoset Keyframes} is
- turned on (via the Toolbar, Timeline menu, or by pressing \c{K}),
- and then change the value of the property (via the Inspector palette
- or dragging the transform of the element), or
-\li
- Change the value of the property and then invoke the
- \l{studio-menu.html#timeline}{Set Changed Keyframes} command (from the
- Timeline menu, or the keyboard shortcut \c{Ctrl + Shift + K}).
-\endlist
-
-This will create a new keyframe at the current time. You can drag the
-keyframe in the Timeline palette to adjust its time, or double-click it
-to show the Set Keyframe Time dialog where you can enter an exact timing
-value.
-
-Keyframes displayed in green are "dynamic keyframes". For more
-information, see the page
-\e{\l{best-practices-dynamic-keyframes.html}{Dynamic Keyframes}}.
-
-\section3 Copying Keyframes
-
-To copy keyframes from one element to another, follow the steps below.
-
-\list 1
-\li
- Select the keyframe(s) to copy on an element.
-\li
- Right-click on one of the selected keyframes and choose \uicontrol {Copy Selected Keyframes}.
-\li
- Position the playhead at the time where the first keyframe should be
- placed.
-\li
- Right click on the time bar for the element and choose \uicontrol{Paste Keyframes}.
-\endlist
-
-\section3 Interpolation
-
-\image Studio-Timeline-Interpolation.png
-
-As the playhead moves from one keyframe to the next, the Qt 3D Studio
-Runtime can perform \e {linear interpolation}, \e {smooth
-interpolation}, or a custom blending somewhere in-between. With linear
-interpolation the value changes at the same rate from one value to the
-next. With smooth interpolation the value starts off holding the
-previous keyframe value, 'accelerates' towards the next keyframe value,
-and then 'decelerates' to stop at the new value.
-
-To set the interpolation, first select the keyframe(s) that you want to
-adjust, then right-click on one of the selected keyframes, and from the
-context menu choose \b {Set Interpolation}. The \b {Ease In} setting
-controls how the value behaves as it approaches the keyframe and the
-\b {Ease Out} setting controls how the value behaves when leaving the
-keyframe.
-
-\note If you find that you are constantly setting your keyframes from
-Smooth to Linear, or vice-versa, you may wish to change the
-\b{Default Interpolation} setting for new keyframes in the
-\l{studio-menu.html#edit}{Application Preferences}.
+For more information on how to work with animations, see the \l Animations documentation.
\section2 Adjusting Time Bars
@@ -423,7 +346,6 @@ first time to select the scene or active component, set the playhead
to a particular time, and then press \c{]} to crop the entire
slide to that duration.
-
\section2 Customizing Time Bars
To help you keep track of your assets, Studio allows you to apply custom
@@ -468,7 +390,8 @@ animations and slide transitions without leaving Studio.
or causing Studio to switch to an new slide when the end time for the
current slide is reached.
\li
- The \uicontrol{Stop} command stops any playback. \uicontrol{Stop} replaces \uicontrol{Play} when animation is playing.
+ The \uicontrol{Stop} command stops any playback. \uicontrol{Stop} replaces \uicontrol{Play}
+ when animation is playing.
\li
The \uicontrol{Fast-forward} command sets the playhead to the timeline end.
\li
diff --git a/doc/src/03-studio/7-inspector-palette.qdoc b/doc/src/03-studio/7-inspector-palette.qdoc
index b19c73c3..354d0580 100644
--- a/doc/src/03-studio/7-inspector-palette.qdoc
+++ b/doc/src/03-studio/7-inspector-palette.qdoc
@@ -126,7 +126,7 @@ shown in the Inspector palette \e{specific to the active slide}:
scene or component will switch to a new slide. This is useful to have
an intro animation that then leads into a looping animation (on a
separate slide). You may specify a specific slide to play through to,
- or simply the next/previous slide in the Slide palette. \^{}
+ or simply the next/previous slide in the Slide palette.
\endlist
\li
\b{Initial Play State} - When entering this slide, should the
@@ -232,17 +232,10 @@ in the Inspector palette:
presentation and the layer, either in pixels or as a percentage of the
presentation's height.
\li
- \b{Sub-Presentation} - If you specify a value here, it is
- intepreted to be the \c{id} attribute of another presentation in
- \omit
- TODO: Not really usable right now.
- \l{file-formats-uia.html}{the \c{.uia} application file}.
- \endomit
- the \c{.uia} application file.
- Instead of rendering the contents of this layer,
- the specified presentation will be rendered and composited in place of
- this layer. For more information, see the discussion on the
- \e{\l{best-practices-using-sub-presentations.html}{Using Sub-Presentations}} page.
+ \b{Sub-Presentation} - Select a presentation (\.uip) or QML (\c.qml) file to render as a
+ sub-presentation on this layer. Other objects on the layer will not render when a sub-presentation
+ is applied. For more information, see
+ \e{\l{Using Sub-Presentations}}.
\li
\b{Ambient Occlusion} - Controls the strength of ambient
occlusion (AO). AO is a form of approximated global illumination which
@@ -344,7 +337,7 @@ in the Inspector palette:
\b{Light Probe} - Select an image (preferably a high dynamic
range image (\c{.hdr})) to use to light the scene, either instead of or
in addition to standard lights. If selected, note that this image will
- be used as the environment for any custom \c{.material}, instead
+ be used as the environment for any custom \c{.shader}, instead
of the environment often associated with them. For details see \l{Using Image-based Lighting}.
\li
\b{IBL Brightness} - The amount of light emitted by the light probe.
@@ -450,18 +443,12 @@ no foreshortening artifacts.
This occurs at the pixel level, not the element level: a model that
crosses the clipping plane may be only partially rendered.
\endlist
-\omit
-TODO: Replace the following paragraph with this once AO is back.
+
\e{The default values are intended to cause anything within the view
of the camera to be rendered. Aside from special clipping effects, you
may need to adjust these values to more closely contain your content for
better results with Ambient Occlusion, or with a layer effect that uses
the depth buffer of the camera, such as the
-\endomit
-\e{The default values are intended to cause anything within the view
-of the camera to be rendered. Aside from special clipping effects, you
-may need to adjust these values to more closely contain your content for
-better results with a layer effect that uses the depth buffer of the camera, such as the
\l{Depth of Field}{Depth of Field effect}.}
\list
@@ -545,7 +532,7 @@ in the Inspector palette (in addition to the
\b{Ambient Color} - The diffuse color (and intensity) applied to
materials before being lit by this light.
\li
- \b{Brightness} (point light only) - An overall multiplier for the
+ \b{Brightness} - An overall multiplier for the
light's effects.
\li
\b{Linear Fade} (point light only) - Turn up this value to
@@ -572,8 +559,6 @@ in the Inspector palette (in addition to the
\li
\b{Shadow Far Clip} - Maximum distance for the shadow map;
smaller values may improve the precision and effects of the map.
-\li
- \b{Shadow Field of View} - Shadow camera field of view.
\endlist
\b Notes:
@@ -626,16 +611,13 @@ in the Inspector palette (in addition to the
\target material-properties
\section1 Material Properties
-A material selected in the Timeline palette shows the different
-properties in the Inspector palette depending on the type of the
-material, chosen in the top-most property:
+Editing a material shows the different properties in the Inspector palette. For more information
+about working with materials, see \l {Materials and Shaders}.
\list
\li
\b{Material Type} - Controls the type of material to be used. The
- values are \"Standard Material\" and \"Referenced Material\", followed
- by a list of any custom \c{.material} files present your
- application folder.
+ values are Basic Material, Animatable Material and Referenced Material.
\li
\e{Tip: Material Type is a special type of property that cannot be
unlinked or changed at runtime. If you want to change the type of
@@ -646,14 +628,18 @@ material, chosen in the top-most property:
\endlist
\target standard-materials
-\section2 Standard Materials
+\section2 Basic Materials
\list
\li
+ \b{Name} - Name of the material.
+\li
\b{IBL override} - IBL probe to use in place of the layer probe.
\endlist
\list
\li
+ \b{Shader} - Choose a customer shader (\c{.shader}) file to use for the material.
+\li
\b{Lighting} - Choose the type of lighting calculations used for
this material:
\list
@@ -847,20 +833,23 @@ Note that the Runtime custom-compiles shaders for each unique
combination of material properties used. Each additional material
feature that you use results in a (slight) additional performance hit.
+\target animated-materials
+\section2 Animated Materials
+
+Animatable materials are used when you want to animate properties of a material. The properties in
+the inspector palette are the same as for a basic material.
+
\target referenced-materials
\section2 Referenced Materials
-A \"referenced material\" uses whatever settings are present on another
-material element. This both allows you to have 'master'
-materials - changing the settings on one material affects all the
-others - and also provides a mechanism for quickly switching between
-different material types (in either Studio or at runtime). When you
-select this type of material, the Inspector palette shows only a single
-property:
+A \"referenced material\" uses the material properties on another
+material. These are used when you want to re-use an animatable material on another
+object. Changing material properties on one object will affect all object using the material
+The Inspector palette shows only a single property:
\list
\li
- \b{Referenced Material} - a picker for selecting another material
+ \b{Referenced Material} - a picker for selecting an animatable material
within the presentation.
\li
\e{Tip: the material you reference does \b{not} have to be
@@ -870,11 +859,16 @@ property:
\endlist
\section1 Image Properties
-When image maps are applied to a material (e.g. Diffuse, Specular,
-Opacity, etc.) a new element appears in the Timeline palette as a child
-of the material. This element represents the properties that control
-that image, allowing them to be animated over time. Selecting one of
-these images shows the following properties in the Inspector palette:
+When image maps (e.g. Diffuse, Specular, Opacity, etc.) are applied to an animated material,
+a new element appears in the scene graph as a child of the material. This element represents
+the properties that control that image, allowing them to be animated over time. Selecting one of
+these images shows the image properties in the Inspector palette.
+
+For basic and referenced materials, you need to first select the material in the scene graph. Then,
+right-click the map property name in the inspector and select \uicontrol {Open in inspector} from
+the context menu. Now the properties of the image map will show in the inspector palette.
+
+\image material-open-in-inspector.png
\list
\li
@@ -985,6 +979,21 @@ TODO: Only one font for now. More to be added?
horizontal spacing between every character pair.
\endlist
+
+\section1 Guide Properties
+
+A guide selected in the scene view shows the following properties in the inspector palette:
+
+\list
+\li
+ \b Position - Position of the guide, in pixels. (0,0) is the lower left corner of the
+ scene view.
+\li
+ \b Orientation - Orientation of the guide.
+\li
+ \b Width - Width of the guide, in pixels.
+\endlist
+
\omit
\section1 Path Properties
diff --git a/doc/src/03-studio/9-keyboard-shortcuts.qdoc b/doc/src/03-studio/9-keyboard-shortcuts.qdoc
index bd7a0001..97131b80 100644
--- a/doc/src/03-studio/9-keyboard-shortcuts.qdoc
+++ b/doc/src/03-studio/9-keyboard-shortcuts.qdoc
@@ -54,20 +54,14 @@
\li \c{Ctrl + O}
\li \c{Cmd + O}
\row
- \li Save
+ \li Save Presentation
\li \c{Ctrl + S}
\li \c{Cmd + S}
-\omit
\row
- \li Save as...
+ \li Save Project As...
\li \c{Ctrl + Shift + S}
\li \c{Cmd + Shift + S}
\row
- \li Save a copy
- \li \c{Ctrl + Alt + S}
- \li \c{Cmd + Option + S}
-\endomit
- \row
\li Exit
\li \c{Ctrl + Q}
\li \c{Cmd + Q}
diff --git a/doc/src/04-viewer/1-keyboard.qdoc b/doc/src/04-viewer/1-keyboard.qdoc
index eb2ba03f..444f4de9 100644
--- a/doc/src/04-viewer/1-keyboard.qdoc
+++ b/doc/src/04-viewer/1-keyboard.qdoc
@@ -50,11 +50,6 @@
\li \c{F5}
\li \c{Ctrl + R}
\li \c{F5}
- \row
- \li Exit
- \li \c{Ctrl + Q}
- \li \c{Ctrl + Q}
- \li \c{Cmd + Q}
\endtable
\section1 View Menu
@@ -66,7 +61,32 @@
\li Linux
\li macOS
\row
- \li Full Screen
+ \li Show matte
+ \li \c{Ctrl + D}
+ \li \c{Ctrl + D}
+ \li \c{Cmd + D}
+ \row
+ \li Scale mode (toggle)
+ \li \c{Ctrl + Shift + S}
+ \li \c{Ctrl + Shift + S}
+ \li \c{Cmd + Shift + S}
+ \row
+ \li Stereo mode (toggle)
+ \li \c{Ctrl + Shift + T}
+ \li \c{Ctrl + Shift + T}
+ \li \c{Cmd + Shift + T}
+ \row
+ \li Increase separation (in stereo mode)
+ \li \c{Ctrl + Shift + +}
+ \li \c{Ctrl + Shift + +}
+ \li \c{Cmd + Shift + +}
+ \row
+ \li Decrease separation (in stereo mode)
+ \li \c{Ctrl + Shift + -}
+ \li \c{Ctrl + Shift + -}
+ \li \c{Cmd + Shift + -}
+ \row
+ \li Full screen
\li \c{F11}
\li \c{Ctrl + F11}
\li \c{F11}
@@ -74,10 +94,25 @@
\li
\li {3, 1} To exit full screen, \c {F11}, \c {ESC} or swipe down gesture can be used.
\row
- \li Toggle debug view
+ \li Toggle in-scene debug view
\li \c{F10}
\li \c{F10}
\li \c{F10}
+ \row
+ \li Toggle console
+ \li \c{`}
+ \li \c{`}
+ \li \c{`}
+ \row
+ \li Scale in-scene debug up
+ \li \c{Ctrl + F10}
+ \li \c{Ctrl + F10}
+ \li \c{Cmd + F10}
+ \row
+ \li Scale in-scene debug down
+ \li \c{Alt + F10}
+ \li \c{Alt + F10}
+ \li \c{Option + F10}
\endtable
*/
diff --git a/doc/src/10-best-practices/practices-index.qdoc b/doc/src/10-best-practices/practices-index.qdoc
index 8f941889..758c8ed7 100644
--- a/doc/src/10-best-practices/practices-index.qdoc
+++ b/doc/src/10-best-practices/practices-index.qdoc
@@ -35,19 +35,14 @@
\section1 Contents
//! [toc]
\list
-\li \l {Dynamic Keyframes}
\li \l {Optimizing Images}
\li \l {Anti-Aliasing}
\li \l {Creating Optimized Presentations}
-\li \l {Using Sub-Presentations}
\li \l {Using Scale Modes}
\li \l {Disable Depth Test}
\li \l {Blend Mode}
\li \l {Working with 3D Content}
\li \l {Applying Layer Effects}
-\li \l {Using Image-based Lighting}
-\li \l {Using Data Inputs}
-\li \l {Using Behavior Scripts}
\endlist
//! [toc]
diff --git a/doc/src/11-quick-start-guides/10-getting-started.qdoc b/doc/src/11-quick-start-guides/quick-start-guide.qdoc
index 9d9cf8a7..7b5a4362 100644
--- a/doc/src/11-quick-start-guides/10-getting-started.qdoc
+++ b/doc/src/11-quick-start-guides/quick-start-guide.qdoc
@@ -27,9 +27,8 @@
/*!
-\title Getting Started
-\page getting-started.html
-\ingroup qt3dstudio-quick-start-guides
+\title Quick Start Guide
+\page quick-start-guide.html
\section1 Introduction
This guide will teach you how to create your first Qt 3D Studio project. Additionally it will
diff --git a/doc/src/animations.qdoc b/doc/src/animations.qdoc
new file mode 100644
index 00000000..64eac60d
--- /dev/null
+++ b/doc/src/animations.qdoc
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\title Animations
+\page animations.html
+
+In Studio, it is easy to create keyframe animations to object and material properties. It is also
+possible to import animations from 3D creation tools such as Maya, 3D Studio Max, or Blender.
+
+A keyframe is a a time marker that stores the value of a property. A keyframe can for example
+define the X position for an element. To create an animation, add another keyframe for the X
+position of the same element but in another position on the timeline. Studio will determine the
+correct X position for all frames between the two keyframes.
+
+You can animate almost any object or material property. Animatable properties have the
+\inlineimage animationIconInactive.png
+icon next to their name in the inspector palette.
+
+\image light-properties.png
+
+\section1 Create Animations
+
+To animate a property, follow the steps below:
+
+\list 1
+ \li
+ Ensure that \l{studio-toolbar.html#keyframing}{autoset keyframes} is toggled on.
+ \li
+ Select the element in the timeline palette, and set the desire starting value for the
+ animated property.
+ \li
+ Move the playhead to the position in the timeline where you want the animation to start.
+ \li
+ Enable animation for the property by clicking the \inlineimage animationIconInactive.png
+ icon next to the property name in the inspector palette.
+ \li
+ Move the playhead to a new position, then change the value for the animated property.
+\endlist
+
+\image Studio-Timeline-Breadcrumb.png
+
+Now that you have two keyframes in the timeline, you can preview the animation by dragging the
+playhead in the timeline palette, or by running the presentation in the Studio or the Viewer.
+
+Moving the playhead to a new position, and then changing the value of a property with animation
+enabled will create a new keyframe.
+
+\section1 Edit Animations
+
+\section2 Insert Keyframes
+
+As mentioned above, changing the value of an animated property will create a new keyframe if there
+isn't already a keyframe in the same position. This requires that \uicontrol {Autoset Keyframes}
+is toggled on.
+
+To manually insert a keyframe, first place the playhead in the position where you want to create the
+keyframe. Next, do one of the following:
+\list
+ \li
+ Right-click the timebar of the animated element, next select \uicontrol {Insert Keyframe}
+ from the context menu.
+ \li
+ Left-click the timebar of the animated element, next press \uicontrol {S}.
+\endlist
+
+Keyframes will be created for all animated properties for the selected element.
+
+\section2 Delete Keyframes
+
+To delete a keyframe, first select it (\uicontrol {Ctrl + left mouse click} to multi select). Next,
+do one of the following:
+\list
+ \li
+ Press \uicontrol {Del}.
+ \li Right-click the keyframe and select \uicontrol{Delete Selected Keyframe} from the
+ context menu.
+\endlist
+
+To delete all keyframes of an element, do one of the following:
+\list
+ \li
+ Right-click the timebar and select \uicontrol {Delete All Channel Keyframes}.
+ \li
+ Left-click the timebar, next press \uicontrol {Ctrl + Alt + K}.
+\endlist
+
+\section2 Move Keyframes
+
+To move a keyframe to a desired position in the timeline, do one of the following:
+\list
+ \li
+ With the left mouse button, drag and drop it.
+ \note Hold \uicontrol {Shift} while dragging to snap to timeline markers.
+ \li
+ Double-click the keyframe and enter the desired timeline position in the dialog window.
+ \li
+ Right-click the keyframe and select \uicontrol {Set Keyframe Time}. Next, enter the desired
+ timeline position in the dialog window.
+\endlist
+
+\section2 Change Property Values
+
+To change a property value for a keyframe, follow the steps below:
+
+\list 1
+ \li
+ Move the playhead to the keyframe, hold \c {Shift} to snap the playhead to the keyframe.
+ \li
+ Select the desired element in the timeline palette.
+ \li
+ In the inspector palette, change the value of the desired animated property.
+\endlist
+
+\section2 Copy Keyframes
+
+To copy keyframes from one element to another, follow the steps below:
+
+\list 1
+ \li
+ Select the keyframe(s) to copy on an element.
+ \li
+ Right-click on one of the selected keyframes and select \uicontrol{Copy Selected Keyframes} from
+ the context menu.
+ \li
+ Position the playhead at the time where the first keyframe should be placed.
+ \li
+ Right click on the time bar for the element and select \uicontrol {Paste Keyframes} from.
+ the context menu.
+\endlist
+
+\section2 Interpolation
+
+As the playhead moves from one keyframe to the next, the Qt 3D Studio
+Runtime can perform \e {linear interpolation}, \e {smooth
+interpolation}, or a custom blending somewhere in-between. With linear
+interpolation the value changes at the same rate from one value to the
+next. With smooth interpolation the value starts off holding the
+previous keyframe value, accelerates towards the next keyframe value,
+and then decelerates to stop at the new value.
+
+To set the interpolation, first select the keyframe(s) that you want to
+adjust, then right-click one of the selected keyframes, and from the
+context menu choose \uicontrol {Set Interpolation}. The \uicontrol {Ease In} setting
+controls how the value behaves as it approaches the keyframe and the
+\uicontrol {Ease Out} setting controls how the value behaves when leaving the
+keyframe.
+
+\image Studio-Timeline-Interpolation.png
+
+\note If you find that you are constantly setting your keyframes from
+Smooth to Linear, or vice-versa, you may wish to change the
+\uicontrol{Default Interpolation} setting for new keyframes in the
+\l{studio-menu.html#edit}{Application Preferences}.
+
+\section1 Import Animations
+
+You can import transform (scale/rotation/location) animations from 3D creation tools
+such as Maya, Blender, 3D Studio Max and Modo.
+
+Read more in the \l {Working with 3D Content} section.
+
+\section1 Further Topics
+
+\list
+ \li
+ \l{Studio: Timeline Palette}{The Timeline}
+
+ The timeline palette provides direct access to all elements in your scene, and also gives you
+ control over the animation and timing within a slide.
+
+ \li
+ \l{Dynamic Keyframes}
+
+ Dynamic keyframes are a powerful feature that allow you to smoothly interpolate between different
+ animated values on different slides.
+
+\endlist
+
+*/
diff --git a/doc/src/deployment.qdoc b/doc/src/deployment.qdoc
new file mode 100644
index 00000000..6332832b
--- /dev/null
+++ b/doc/src/deployment.qdoc
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\title Deployment
+\page deployment.html
+
+\list
+ \li
+ \l{Viewer Remote Deployment}
+
+ Qt 3D Studio supports remote deployment to Qt 3D Studio Viewer. This enables seeing design
+ changes live in the target device, for example an Android tablet.
+
+\endlist
+
+*/
diff --git a/doc/src/getting-help.qdoc b/doc/src/getting-help.qdoc
new file mode 100644
index 00000000..9e5d5685
--- /dev/null
+++ b/doc/src/getting-help.qdoc
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\title Getting Help
+\page getting-help.html
+
+\list
+ \li
+ \l{Studio Keyboard Shortcuts}
+
+ A list of all keyboard shortcuts for the Studio.
+
+ \li
+ \l{Viewer Keyboard Shortcuts}
+
+ A list of all keyboard shortcuts for the Viewer.
+
+\endlist
+
+*/
diff --git a/doc/src/getting-started.qdoc b/doc/src/getting-started.qdoc
new file mode 100644
index 00000000..928bedf4
--- /dev/null
+++ b/doc/src/getting-started.qdoc
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\title Getting Started
+\page getting-started.html
+
+\list
+ \li
+ \l{About Qt 3D Studio}
+
+ All about the Qt 3D Studio suite concept including requirements, copyright notices and known
+ issues.
+
+ \li
+ \l{Quick Start Guide}
+
+ The quick start guide is the best way to get started if you are new to Qt 3D Studio.
+
+ \li
+ \l{Tutorials}
+
+ A collection of tutorials.
+
+ \li
+ \l{Best Practices}
+
+ A collection of best practices guides.
+
+ \li
+ \l{Studio Index}
+
+ A more in-depth introduction to the Qt 3D Studio editor.
+
+ \li
+ \l{Viewer Index}
+
+ A more in-depth introduction to the Qt 3D Studio viewer.
+\endlist
+
+*/
diff --git a/doc/src/graphics.qdoc b/doc/src/graphics.qdoc
new file mode 100644
index 00000000..ce7939da
--- /dev/null
+++ b/doc/src/graphics.qdoc
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\title Graphics
+\page graphics.html
+
+\list
+ \li
+ \l{Working with 3D Content}{3D Assets}
+
+ Best practices on how to work with 3D content in Studio, and how to import 3D content from
+ various 3D content creation tools.
+
+ \li
+ \l{Layers}
+
+ A single Studio presentation combines one or more layers. The visual result of each layer comes
+ from rendering a 3D scene, 2D scene, or sub-presentation.
+
+ \li
+ \l{Materials and shaders}
+
+ Materials and shaders define how object surfaces are rendered in Studio and Viewer.
+
+ \li
+ \l{Light Properties}{Lights}
+
+ In Qt 3D Studio, scenes are illuminated with one or more lights.
+
+ \li
+ \l{Using Sub-Presentations}{Sub-Presentations}
+
+ Sub-Presentations is a feature which allows a Studio presentation or a QML file to
+ be embedded in a Studio presentation.
+
+ \li
+ \l{Stereoscopic rendering}
+
+ This is a technical preview on how stereoscopic rendering could work in Qt 3D Studio.
+\endlist
+
+*/
diff --git a/doc/src/images/ApplicationPreferences.png b/doc/src/images/ApplicationPreferences.png
index 5a48a352..69b57677 100644
--- a/doc/src/images/ApplicationPreferences.png
+++ b/doc/src/images/ApplicationPreferences.png
Binary files differ
diff --git a/doc/src/images/DisableDepthTest.png b/doc/src/images/DisableDepthTest.png
index 9549289d..cb9dc648 100644
--- a/doc/src/images/DisableDepthTest.png
+++ b/doc/src/images/DisableDepthTest.png
Binary files differ
diff --git a/doc/src/images/Studio-Action.png b/doc/src/images/Studio-Action.png
index 90668169..0e0eb7ef 100644
--- a/doc/src/images/Studio-Action.png
+++ b/doc/src/images/Studio-Action.png
Binary files differ
diff --git a/doc/src/images/Studio-SceneView.png b/doc/src/images/Studio-SceneView.png
index a5c024a6..60863292 100644
--- a/doc/src/images/Studio-SceneView.png
+++ b/doc/src/images/Studio-SceneView.png
Binary files differ
diff --git a/doc/src/images/Studio-Timeline-Breadcrumb.png b/doc/src/images/Studio-Timeline-Breadcrumb.png
index e9090053..af92d96b 100644
--- a/doc/src/images/Studio-Timeline-Breadcrumb.png
+++ b/doc/src/images/Studio-Timeline-Breadcrumb.png
Binary files differ
diff --git a/doc/src/images/Studio-Timeline-Interpolation.png b/doc/src/images/Studio-Timeline-Interpolation.png
index 6754f1f3..f8b84487 100644
--- a/doc/src/images/Studio-Timeline-Interpolation.png
+++ b/doc/src/images/Studio-Timeline-Interpolation.png
Binary files differ
diff --git a/doc/src/images/Studio-Timeline-Overview.png b/doc/src/images/Studio-Timeline-Overview.png
index a990e2b6..e927aa13 100644
--- a/doc/src/images/Studio-Timeline-Overview.png
+++ b/doc/src/images/Studio-Timeline-Overview.png
Binary files differ
diff --git a/doc/src/images/Studio-Timeline-SceneGraph.png b/doc/src/images/Studio-Timeline-SceneGraph.png
index 95faa07b..b39908b3 100644
--- a/doc/src/images/Studio-Timeline-SceneGraph.png
+++ b/doc/src/images/Studio-Timeline-SceneGraph.png
Binary files differ
diff --git a/doc/src/images/addAssets.png b/doc/src/images/addAssets.png
index 14ed11b7..0855a28e 100644
--- a/doc/src/images/addAssets.png
+++ b/doc/src/images/addAssets.png
Binary files differ
diff --git a/doc/src/images/component_timeline.png b/doc/src/images/component_timeline.png
index 4ca726db..7355ac89 100644
--- a/doc/src/images/component_timeline.png
+++ b/doc/src/images/component_timeline.png
Binary files differ
diff --git a/doc/src/images/copy-transform-settings.png b/doc/src/images/copy-transform-settings.png
index 2aed6795..54375987 100644
--- a/doc/src/images/copy-transform-settings.png
+++ b/doc/src/images/copy-transform-settings.png
Binary files differ
diff --git a/doc/src/images/create-guides.png b/doc/src/images/create-guides.png
new file mode 100644
index 00000000..44c30dcf
--- /dev/null
+++ b/doc/src/images/create-guides.png
Binary files differ
diff --git a/doc/src/images/data-inputs.png b/doc/src/images/data-inputs.png
index f7f879f8..09943993 100644
--- a/doc/src/images/data-inputs.png
+++ b/doc/src/images/data-inputs.png
Binary files differ
diff --git a/doc/src/images/datainput-property-active-icon.png b/doc/src/images/datainput-property-active-icon.png
index 26f5af0f..8a3f4f61 100644
--- a/doc/src/images/datainput-property-active-icon.png
+++ b/doc/src/images/datainput-property-active-icon.png
Binary files differ
diff --git a/doc/src/images/dyn-keyframes-make-dynamic.png b/doc/src/images/dyn-keyframes-make-dynamic.png
index 0edc8a3e..8a968ec6 100644
--- a/doc/src/images/dyn-keyframes-make-dynamic.png
+++ b/doc/src/images/dyn-keyframes-make-dynamic.png
Binary files differ
diff --git a/doc/src/images/dyn-keyframes-position.png b/doc/src/images/dyn-keyframes-position.png
index 2a6bc21a..e80baeef 100644
--- a/doc/src/images/dyn-keyframes-position.png
+++ b/doc/src/images/dyn-keyframes-position.png
Binary files differ
diff --git a/doc/src/images/dyn-keyframes-slide.png b/doc/src/images/dyn-keyframes-slide.png
index e9289604..7e20db67 100644
--- a/doc/src/images/dyn-keyframes-slide.png
+++ b/doc/src/images/dyn-keyframes-slide.png
Binary files differ
diff --git a/doc/src/images/guide-properties.png b/doc/src/images/guide-properties.png
new file mode 100644
index 00000000..fa8a06ce
--- /dev/null
+++ b/doc/src/images/guide-properties.png
Binary files differ
diff --git a/doc/src/images/import-assetes-dnd.png b/doc/src/images/import-assetes-dnd.png
index 48eefa86..ab895628 100644
--- a/doc/src/images/import-assetes-dnd.png
+++ b/doc/src/images/import-assetes-dnd.png
Binary files differ
diff --git a/doc/src/images/light-properties.png b/doc/src/images/light-properties.png
new file mode 100644
index 00000000..a5f5528a
--- /dev/null
+++ b/doc/src/images/light-properties.png
Binary files differ
diff --git a/doc/src/images/material-open-in-inspector.png b/doc/src/images/material-open-in-inspector.png
new file mode 100644
index 00000000..a5a2a8c4
--- /dev/null
+++ b/doc/src/images/material-open-in-inspector.png
Binary files differ
diff --git a/doc/src/images/open-presentation.png b/doc/src/images/open-presentation.png
index 14d897dd..c9883dbc 100644
--- a/doc/src/images/open-presentation.png
+++ b/doc/src/images/open-presentation.png
Binary files differ
diff --git a/doc/src/images/presentation-size.png b/doc/src/images/presentation-size.png
index 2006c90b..d7be52f0 100644
--- a/doc/src/images/presentation-size.png
+++ b/doc/src/images/presentation-size.png
Binary files differ
diff --git a/doc/src/images/slide-palette-data-input-active.png b/doc/src/images/slide-palette-data-input-active.png
index c3db0691..9d5a7b47 100644
--- a/doc/src/images/slide-palette-data-input-active.png
+++ b/doc/src/images/slide-palette-data-input-active.png
Binary files differ
diff --git a/doc/src/images/slide-palette-data-input-inactive.png b/doc/src/images/slide-palette-data-input-inactive.png
index c19ce112..7cb639fb 100644
--- a/doc/src/images/slide-palette-data-input-inactive.png
+++ b/doc/src/images/slide-palette-data-input-inactive.png
Binary files differ
diff --git a/doc/src/images/slidePalette.png b/doc/src/images/slidePalette.png
index d415053b..f2d3cab9 100644
--- a/doc/src/images/slidePalette.png
+++ b/doc/src/images/slidePalette.png
Binary files differ
diff --git a/doc/src/images/slidePlayMode.png b/doc/src/images/slidePlayMode.png
index 57b8f90a..4d68f0ec 100644
--- a/doc/src/images/slidePlayMode.png
+++ b/doc/src/images/slidePlayMode.png
Binary files differ
diff --git a/doc/src/images/subpresentation-layer-inspector.png b/doc/src/images/subpresentation-layer-inspector.png
index b51bf535..756fd7f5 100644
--- a/doc/src/images/subpresentation-layer-inspector.png
+++ b/doc/src/images/subpresentation-layer-inspector.png
Binary files differ
diff --git a/doc/src/images/subpresentation-project-structure.png b/doc/src/images/subpresentation-project-structure.png
index 6def2aae..8a933a24 100644
--- a/doc/src/images/subpresentation-project-structure.png
+++ b/doc/src/images/subpresentation-project-structure.png
Binary files differ
diff --git a/doc/src/images/timeline-datainput.png b/doc/src/images/timeline-datainput.png
index 1a6b1c52..be359d63 100644
--- a/doc/src/images/timeline-datainput.png
+++ b/doc/src/images/timeline-datainput.png
Binary files differ
diff --git a/doc/src/images/timeline-text-edit.png b/doc/src/images/timeline-text-edit.png
index b40a87f2..89301e80 100644
--- a/doc/src/images/timeline-text-edit.png
+++ b/doc/src/images/timeline-text-edit.png
Binary files differ
diff --git a/doc/src/images/timeline-texts-icon.png b/doc/src/images/timeline-texts-icon.png
index cfde79ab..18e97994 100644
--- a/doc/src/images/timeline-texts-icon.png
+++ b/doc/src/images/timeline-texts-icon.png
Binary files differ
diff --git a/doc/src/images/timeline.png b/doc/src/images/timeline.png
index 27448b65..a4ed4853 100644
--- a/doc/src/images/timeline.png
+++ b/doc/src/images/timeline.png
Binary files differ
diff --git a/doc/src/images/view-scale-mode.png b/doc/src/images/view-scale-mode.png
index a44607bb..cd9350d9 100644
--- a/doc/src/images/view-scale-mode.png
+++ b/doc/src/images/view-scale-mode.png
Binary files differ
diff --git a/doc/src/scripting.qdoc b/doc/src/scripting.qdoc
new file mode 100644
index 00000000..01553ccd
--- /dev/null
+++ b/doc/src/scripting.qdoc
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\title Scripting
+\page scripting.html
+
+\list
+ \li
+ \l{Using Data Inputs}{Data Input}
+
+ Qt 3D Studio supports data-driven animations. This makes it possible to control timeline
+ animations, object properties and slides with data input.
+
+ \li
+ \l{Using Behavior Scripts}{Behavior}
+
+ Qt 3D Studio supports using behavior scripts. Included in Studio is a set of behavior scripts,
+ these can be found in the scripts asset library.
+
+ \li
+ \l{File Formats}
+
+ File formats of custom effect, materials and shaders.
+
+\endlist
+
+*/
diff --git a/doc/src/tutorials.qdoc b/doc/src/tutorials.qdoc
new file mode 100644
index 00000000..c7b4d4ab
--- /dev/null
+++ b/doc/src/tutorials.qdoc
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+
+\title Tutorials
+\page tutorials.html
+
+\list
+ \li
+ \l {Using Sub-Presentations}
+
+ Learn how to use sub-presentations on layers and textures.
+ \li
+ \l {Using Image-Based Lighting}
+
+ Learn how to illuminate your scenes with HDR images.
+ \li
+ \l {Dynamic Keyframes}
+
+ Learn how to create smooth animation transitions using dynamic keyframes.
+ \li
+ \l {Using Data Inputs}
+
+ Learn how to set up your project to use data for controlling animations, slides and object
+ properties.
+ \li
+ \l {Using Behavior Scripts}
+
+ Learn how to use behavior scripts in your project.
+\endlist
+
+*/
diff --git a/doc/style/qt5-sidebar.html b/doc/style/qt5-sidebar.html
index eb007c75..765cf6ff 100644
--- a/doc/style/qt5-sidebar.html
+++ b/doc/style/qt5-sidebar.html
@@ -6,15 +6,13 @@
<div class="indexboxcont indexboxbar">
<ul>
<li><a href="getting-started.html">Getting Started</a></li>
- <li><a href="qt3dstudio-studio.html">Studio</a></li>
- <li><a href="qt3dstudio-viewer.html">Viewer</a></li>
+ <li><a href="graphics.html">Graphics</a></li>
+ <li><a href="animations.html">Animations</a></li>
+ <li><a href="scripting.html">Scripting</a></li>
+ <li><a href="deployment.html">Deployment</a></li>
+ <li><a href="getting-help.html">Getting Help</a></li>
<li><a href="runtime/index.html">Runtime</a></li>
<li><a href="runtime/qt3d-runtime-qml.html">QML API Reference</a></li>
<li><a href="runtime/qt3d-runtime-cpp.html">C++ API Reference</a></li>
- <li><a href="qt3dstudio-file-formats.html">File Formats</a></li>
- <li><a href="qt3dstudio-best-practices.html">Best Practices</a></li>
- <li><a href="requirements.html">Requirements</a></li>
- <li><a href="experimental-features.html">Experimental Features</a></li>
- <li><a href="copyright-notices.html">Copyright Notices</a></li>
</ul>
</div>
diff --git a/src/Authoring/Client/Code/Core/Commands/CmdDataModel.cpp b/src/Authoring/Client/Code/Core/Commands/CmdDataModel.cpp
index 1e521df8..47a44b51 100644
--- a/src/Authoring/Client/Code/Core/Commands/CmdDataModel.cpp
+++ b/src/Authoring/Client/Code/Core/Commands/CmdDataModel.cpp
@@ -64,9 +64,8 @@ void SApplicationState::Notify(const SApplicationState &inOther, CDoc &inDoc)
// to a deleted item
void SApplicationState::PreNotify(const SApplicationState &inOther, CDoc &inDoc)
{
- if (m_SelectedInstance != inOther.m_SelectedInstance) {
+ if (m_SelectedInstance != inOther.m_SelectedInstance)
inDoc.DeselectAllItems(false);
- }
}
CmdDataModel::CmdDataModel(CDoc &inDoc)
@@ -96,25 +95,11 @@ bool CmdDataModel::ConsumerExists() const
return m_Consumer != nullptr;
}
-void CmdDataModel::SetConsumer(ITransactionProducer *inProducer)
-{
- if (!ConsumerExists())
- m_Consumer = std::make_shared<CTransactionConsumer>();
- inProducer->SetConsumer(m_Consumer);
-}
-
-void CmdDataModel::ReleaseConsumer(ITransactionProducer *inProducer, bool inRunNotifications)
-{
- inProducer->SetConsumer(TTransactionConsumerPtr());
- if (inRunNotifications)
- RunDoNotifications();
-}
-
void CmdDataModel::SetConsumer()
{
if (!ConsumerExists()) {
- m_Doc.GetCore()->GetDispatch();
- SetConsumer(m_Doc.GetStudioSystem());
+ m_Consumer = std::make_shared<CTransactionConsumer>();
+ m_Doc.GetStudioSystem()->SetConsumer(m_Consumer);
m_Doc.GetAssetGraph()->SetConsumer(m_Consumer);
m_BeforeDoAppState.Store(m_Doc);
}
@@ -123,11 +108,16 @@ void CmdDataModel::SetConsumer()
void CmdDataModel::ReleaseConsumer(bool inRunNotifications)
{
if (ConsumerExists()) {
- m_Doc.GetAssetGraph()->SetConsumer(TTransactionConsumerPtr());
+ m_Doc.GetAssetGraph()->SetConsumer(nullptr);
+
if (HasTransactions())
m_Doc.SetModifiedFlag(true);
m_AfterDoAppState.Store(m_Doc);
- ReleaseConsumer(m_Doc.GetStudioSystem(), inRunNotifications);
+
+ m_Doc.GetStudioSystem()->SetConsumer(nullptr);
+
+ if (inRunNotifications)
+ RunDoNotifications();
}
}
diff --git a/src/Authoring/Client/Code/Core/Commands/CmdDataModel.h b/src/Authoring/Client/Code/Core/Commands/CmdDataModel.h
index 7980bd4e..642df8de 100644
--- a/src/Authoring/Client/Code/Core/Commands/CmdDataModel.h
+++ b/src/Authoring/Client/Code/Core/Commands/CmdDataModel.h
@@ -88,10 +88,6 @@ protected:
SApplicationState m_BeforeDoAppState;
// The application state after this command.
SApplicationState m_AfterDoAppState;
-
-private:
- void SetConsumer(ITransactionProducer *inProducer);
- void ReleaseConsumer(ITransactionProducer *inProducer, bool inRunNotifications);
};
struct SScopedDataModelConsumer
diff --git a/src/Authoring/Client/Code/Core/Commands/CmdStack.cpp b/src/Authoring/Client/Code/Core/Commands/CmdStack.cpp
index 3530822f..76f51126 100644
--- a/src/Authoring/Client/Code/Core/Commands/CmdStack.cpp
+++ b/src/Authoring/Client/Code/Core/Commands/CmdStack.cpp
@@ -27,16 +27,13 @@
**
****************************************************************************/
-#include "Qt3DSCommonPrecompile.h"
#include "CmdStack.h"
#include "Cmd.h"
#include "CmdStackModifier.h"
CCmdStack::CCmdStack()
{
- m_Listener = NULL;
- m_MaxUndoStackSize = 100;
- m_CommandStackModifier = NULL;
+
}
CCmdStack::~CCmdStack()
@@ -66,14 +63,13 @@ bool CCmdStack::ExecuteCommand(CCmd *inCommand)
// Execute the command.
unsigned long theUpdateMask = inCommand->Do();
-
// If the listener is not null then do the notifications.
- if (m_Listener != NULL) {
+ if (m_Listener) {
m_Listener->CommandUpdate(theUpdateMask);
// Set the modified flag if it needs to be set.
if (inCommand->ShouldSetModifiedFlag()) {
- m_Listener->SetCommandModifiedFlag(TRUE);
+ m_Listener->SetCommandModifiedFlag(true);
}
}
@@ -135,11 +131,11 @@ bool CCmdStack::ExecuteCommand(CCmd *inCommand)
//=============================================================================
void CCmdStack::Undo()
{
-
if (m_CommandStackModifier) {
if (m_CommandStackModifier->PreUndo() == false)
return;
}
+
if (m_UndoList.size() > 0) {
m_undoingOrRedoing = true;
CCmd *theLastCommand = m_UndoList.back();
@@ -147,7 +143,6 @@ void CCmdStack::Undo()
unsigned long theUpdateMask = theLastCommand->Undo();
-
// Once a command is undone then it is considered committed. Prevents merging after this has
// been redone.
theLastCommand->SetCommitted(true);
@@ -155,13 +150,12 @@ void CCmdStack::Undo()
m_RedoList.push_back(theLastCommand);
// If the listener is not null then do the notifications.
- if (m_Listener != NULL) {
+ if (m_Listener) {
m_Listener->CommandUpdate(theUpdateMask);
// Set the modified flag if it needs to be set.
- if (theLastCommand->ShouldSetModifiedFlag()) {
- m_Listener->SetCommandModifiedFlag(TRUE);
- }
+ if (theLastCommand->ShouldSetModifiedFlag())
+ m_Listener->SetCommandModifiedFlag(true);
}
m_undoingOrRedoing = false;
}
@@ -186,13 +180,12 @@ void CCmdStack::Redo()
m_UndoList.push_back(theLastCommand);
// If the listener is not null then do the notifications.
- if (m_Listener != NULL) {
+ if (m_Listener) {
m_Listener->CommandUpdate(theUpdateMask);
// Set the modified flag if it needs to be set.
- if (theLastCommand->ShouldSetModifiedFlag()) {
- m_Listener->SetCommandModifiedFlag(TRUE);
- }
+ if (theLastCommand->ShouldSetModifiedFlag())
+ m_Listener->SetCommandModifiedFlag(true);
}
m_undoingOrRedoing = false;
}
diff --git a/src/Authoring/Client/Code/Core/Commands/CmdStack.h b/src/Authoring/Client/Code/Core/Commands/CmdStack.h
index 7388703d..9597f5a6 100644
--- a/src/Authoring/Client/Code/Core/Commands/CmdStack.h
+++ b/src/Authoring/Client/Code/Core/Commands/CmdStack.h
@@ -102,15 +102,15 @@ public:
protected:
void EmptyUndoStack();
- ICmdStackModifier *m_CommandStackModifier;
+ ICmdStackModifier *m_CommandStackModifier = nullptr;
TCmdList m_UndoList;
TCmdList m_RedoList;
bool m_undoingOrRedoing = false;
- unsigned long m_MaxUndoStackSize;
+ unsigned long m_MaxUndoStackSize = 100;
- CModificationListener *m_Listener;
+ CModificationListener *m_Listener = nullptr;
};
#endif // INCLUDED_CMD_STACK_H
diff --git a/src/Authoring/Client/Code/Core/Doc/ComposerEditorInterface.cpp b/src/Authoring/Client/Code/Core/Doc/ComposerEditorInterface.cpp
index f377802b..53591a0b 100644
--- a/src/Authoring/Client/Code/Core/Doc/ComposerEditorInterface.cpp
+++ b/src/Authoring/Client/Code/Core/Doc/ComposerEditorInterface.cpp
@@ -228,11 +228,13 @@ struct SComposerImportInterface : public SComposerImportBase, public IComposerEd
void createMaterial(const InstanceDesc &desc, TImportId inParent) override
{
- QString materialName = desc.m_Id;
+ QString materialName = CFilePath::MakeSafeFileStem(desc.m_Id);
Option<SValue> name = m_ImportObj->GetInstancePropertyValue(desc.m_Handle,
ComposerPropertyNames::name);
- if (name.hasValue())
- materialName = qt3dsdm::get<TDataStrPtr>(*name)->toQString();
+ if (name.hasValue()) {
+ materialName = CFilePath::MakeSafeFileStem(
+ qt3dsdm::get<TDataStrPtr>(*name)->toQString());
+ }
QString filepath = m_Editor.getMaterialFilePath(materialName);
int i = 1;
@@ -245,7 +247,7 @@ struct SComposerImportInterface : public SComposerImportBase, public IComposerEd
QMap<QString, QMap<QString, QString>> textureValues;
m_Editor.getMaterialInfo(filepath, name, values, textureValues);
if (values.contains(importFile) && values[importFile] == m_Relativeimportfile) {
- const auto material = m_Editor.getOrCreateMaterial(materialName);
+ const auto material = m_Editor.getOrCreateMaterial(materialName, false);
if (!m_createdMaterials.contains(material))
m_Editor.setMaterialValues(material, values, textureValues);
break;
@@ -255,7 +257,7 @@ struct SComposerImportInterface : public SComposerImportBase, public IComposerEd
}
bool isNewMaterial = !m_Editor.getMaterial(materialName).Valid();
- const auto material = m_Editor.getOrCreateMaterial(materialName);
+ const auto material = m_Editor.getOrCreateMaterial(materialName, false);
if (!m_createdMaterials.contains(material) && isNewMaterial) {
m_Editor.SetSpecificInstancePropertyValue(0, material, QStringLiteral("importid"),
std::make_shared<CDataStr>(desc.m_Id));
@@ -497,11 +499,11 @@ struct SComposerRefreshInterface : public SComposerImportBase, public IComposerE
void createMaterial(const InstanceDesc &desc, TImportId inParent) override
{
- QString materialName = desc.m_Id;
+ QString materialName = CFilePath::MakeSafeFileStem(desc.m_Id);
Option<SValue> name = m_importObj->GetInstancePropertyValue(desc.m_Handle,
ComposerPropertyNames::name);
if (name.hasValue())
- materialName = qt3dsdm::get<QString>(*name);
+ materialName = CFilePath::MakeSafeFileStem(qt3dsdm::get<QString>(*name));
// Get a unique material name
// Reuse a material name if previously imported from the same source
@@ -533,7 +535,7 @@ struct SComposerRefreshInterface : public SComposerImportBase, public IComposerE
for (auto &child : children)
m_Editor.RemoveChild(material, child);
} else {
- material = m_Editor.getOrCreateMaterial(materialName);
+ material = m_Editor.getOrCreateMaterial(materialName, false);
}
if (!m_createdMaterials.contains(material)) {
@@ -556,7 +558,7 @@ struct SComposerRefreshInterface : public SComposerImportBase, public IComposerE
// Actual material inside material container has been created
// Next create the referenced material located inside the model
- QString refName = desc.m_Id;
+ QString refName = originalMaterialName;
refName += QLatin1String("_ref");
TIdMultiMap::iterator refInserter(m_IdToSlideInstances.insert(
refName, QVector<QPair<Qt3DSDMSlideHandle, Qt3DSDMInstanceHandle>>()));
@@ -581,13 +583,13 @@ struct SComposerRefreshInterface : public SComposerImportBase, public IComposerE
instance = m_Editor.CreateSceneGraphInstance(
ComposerObjectTypes::ReferencedMaterial, oldVersion,
theIterator.GetCurrentSlide(), DocumentEditorInsertType::NextSibling,
- CPt(), PRIMITIVETYPE_UNKNOWN, 0);
+ CPt(), PRIMITIVETYPE_UNKNOWN, 0, true, false);
m_Editor.DeleteInstance(oldVersion);
} else {
instance = m_Editor.CreateSceneGraphInstance(
ComposerObjectTypes::ReferencedMaterial, parent,
theIterator.GetCurrentSlide(), DocumentEditorInsertType::LastChild,
- CPt(), PRIMITIVETYPE_UNKNOWN, 0);
+ CPt(), PRIMITIVETYPE_UNKNOWN, 0, true, false);
}
m_Editor.setMaterialReferenceByPath(instance, materialName);
m_Editor.SetName(instance, materialName);
diff --git a/src/Authoring/Client/Code/Core/Doc/Doc.cpp b/src/Authoring/Client/Code/Core/Doc/Doc.cpp
index 550cf1f3..599e0306 100644
--- a/src/Authoring/Client/Code/Core/Doc/Doc.cpp
+++ b/src/Authoring/Client/Code/Core/Doc/Doc.cpp
@@ -417,7 +417,7 @@ Q3DStudio::IDocumentEditor &CDoc::OpenTransaction(const QString &inCmdName, cons
++m_TransactionDepth;
if (m_TransactionDepth == 1) {
assert(!m_OpenTransaction);
- m_OpenTransaction = std::make_shared<qt3dsdm::CmdDataModel>(std::ref(*this));
+ m_OpenTransaction = std::make_shared<qt3dsdm::CmdDataModel>(*this);
m_OpenTransaction->SetName(inCmdName);
m_OpenTransaction->SetConsumer();
m_Core->SetCommandStackModifier(this);
@@ -432,9 +432,9 @@ Q3DStudio::IDocumentEditor &CDoc::OpenTransaction(const QString &inCmdName, cons
qCInfo(qt3ds::TRACE_INFO) << inFile << "(" << inLine << "): Open Transaction: "
<< inCmdName;
- if (!m_SceneEditor) {
+ if (!m_SceneEditor)
m_SceneEditor = Q3DStudio::IInternalDocumentEditor::CreateEditor(*this);
- }
+
return *m_SceneEditor;
}
@@ -474,9 +474,9 @@ void CDoc::IKnowWhatIAmDoingForceCloseTransaction()
qCInfo(qt3ds::TRACE_INFO) << "Closing transaction";
// Ensure hasTransaction will return false right at this second.
std::shared_ptr<qt3dsdm::CmdDataModel> theTransaction(m_OpenTransaction);
- m_OpenTransaction = std::shared_ptr<qt3dsdm::CmdDataModel>();
+ m_OpenTransaction.reset();
- m_Core->SetCommandStackModifier(NULL);
+ m_Core->SetCommandStackModifier(nullptr);
// Release the consumer without running notifications because our command will run
// the notifications when it first gets executed.
theTransaction->ReleaseConsumer(false);
@@ -1199,7 +1199,6 @@ void CDoc::OnSlideDeleted(qt3dsdm::Qt3DSDMSlideHandle inSlide)
}
void CDoc::OnInstanceDeleted(qt3dsdm::Qt3DSDMInstanceHandle inInstance)
{
- qt3dsdm::TTransactionConsumerPtr theConsumer = m_StudioSystem->GetFullSystem()->GetConsumer();
if (GetSelectedInstance() == inInstance)
DeselectAllItems();
@@ -1321,10 +1320,7 @@ void CDoc::onPropertyChanged(qt3dsdm::Qt3DSDMInstanceHandle inInstance,
inInstance, QStringLiteral("controlledproperty"))) {
// we need to rebuild the datainput map as we do not know what exactly
// happened with controlledproperty property
- // TODO: implement a pre-change signal that can be used to extract
- // controlledproperty string before and after the change, so we know exactly
- // what happened to the element
- UpdateDatainputMap();
+ UpdateDatainputMapForInstance(inInstance);
}
}
@@ -1707,7 +1703,7 @@ void CDoc::CloseDocument()
// selection would be invalid from this point onwards
DeselectAllItems();
- m_SceneEditor = std::shared_ptr<Q3DStudio::IInternalDocumentEditor>();
+ m_SceneEditor.reset();
if (m_DocumentBufferCache) {
// Ensure old buffers aren't picked up for the same relative path.
m_DocumentBufferCache->Clear();
@@ -2970,6 +2966,56 @@ void CDoc::UpdateDatainputMap(QMultiMap<QString,
UpdateDatainputMapRecursive(GetSceneInstance(), outMap);
}
+// Update global datainput map for all datainput bindings for a single instance.
+void CDoc::UpdateDatainputMapForInstance(qt3dsdm::Qt3DSDMInstanceHandle inInstance)
+{
+ auto propSystem = GetPropertySystem();
+
+ qt3dsdm::Qt3DSDMPropertyHandle ctrldPropHandle
+ = propSystem->GetAggregateInstancePropertyByName(inInstance,
+ QStringLiteral("controlledproperty"));
+
+ if (propSystem->HasAggregateInstanceProperty(inInstance, ctrldPropHandle)) {
+ qt3dsdm::SValue ctrldPropVal;
+ propSystem->GetInstancePropertyValue(inInstance, ctrldPropHandle, ctrldPropVal);
+ Q3DStudio::CString currCtrldPropsStr
+ = qt3dsdm::get<qt3dsdm::TDataStrPtr>(ctrldPropVal)->GetData();
+ QStringList splitStr = currCtrldPropsStr.toQString().split(QLatin1Char(' '));
+
+ // There is no way to detect a case where control is removed i.e. a controller-property
+ // pair simply disappears from controlledproperty string. We need to do a complete
+ // rebuild for inInstance references in the global map, but still avoid doing
+ // a scene-wide datainput map update.
+ for (auto &it : qAsConst(g_StudioApp.m_dataInputDialogItems))
+ it->removeControlFromInstance(inInstance);
+
+ // Rebuild controlled element items and append them to global datainput map.
+ for (int i = 0; i < splitStr.size() - 1; i += 2) {
+ // Check for '$' because Qt3DS v1.1 did not differentiate datainput
+ // names with it
+ QString diName = splitStr[i].startsWith(QLatin1Char('$'))
+ ? splitStr[i].remove(0, 1) : splitStr[i];
+ QString propName = splitStr[i+1];
+ auto propHandle = propSystem->GetAggregateInstancePropertyByName(
+ inInstance, propName);
+ auto propType = propSystem->GetDataType(propHandle);
+ CDataInputDialogItem::ControlledItem item(inInstance, propHandle);
+ if (propType)
+ item.dataType = {propType, false};
+ else if (propName == QLatin1String("@slide"))
+ item.dataType = {qt3dsdm::DataModelDataType::Value::String, true};
+ else if (propName == QLatin1String("@timeline"))
+ item.dataType = {qt3dsdm::DataModelDataType::Value::RangedNumber, true};
+
+ // Check for DI name validity because we might have broken
+ // presentations with property control bindings set to non-existent
+ // datainputs
+ if (g_StudioApp.m_dataInputDialogItems.contains(diName))
+ g_StudioApp.m_dataInputDialogItems[diName]->ctrldElems.append(item);
+ }
+ }
+}
+
void CDoc::UpdateDatainputMapRecursive(
const qt3dsdm::Qt3DSDMInstanceHandle inInstance,
QMultiMap<QString,
@@ -3159,6 +3205,42 @@ void CDoc::ReplaceDatainput(const QString &oldName, const QString &newName,
}
}
+QString CDoc::GetCurrentController(qt3dsdm::Qt3DSDMInstanceHandle instHandle,
+ qt3dsdm::Qt3DSDMPropertyHandle propHandle)
+{
+ auto propSys = GetPropertySystem();
+ qt3dsdm::SValue currPropVal;
+ propSys->GetInstancePropertyValue(
+ instHandle,
+ propSys->GetAggregateInstancePropertyByName(
+ instHandle, QStringLiteral("controlledproperty")),
+ currPropVal);
+ if (!currPropVal.empty()) {
+ QString currPropValStr = qt3dsdm::get<QString>(currPropVal);
+ QString propName = propSys->GetName(propHandle);
+
+ // Datainput controller name is always prepended with "$". Differentiate
+ // between datainput and property that has the same name by searching specifically
+ // for whitespace followed by property name.
+ int propNamePos = currPropValStr.indexOf(" " + propName);
+ if ((propNamePos != -1) && (propNamePos != 0)) {
+ int posCtrlr = currPropValStr.mid(0, propNamePos).lastIndexOf("$");
+
+ // adjust pos if this is the first controller - property pair in controlledproperty
+ if (posCtrlr < 0)
+ posCtrlr = 0;
+
+ // remove $
+ posCtrlr++;
+ return currPropValStr.mid(posCtrlr, propNamePos - posCtrlr);
+ } else {
+ return {};
+ }
+ }
+
+ return {};
+}
+
QDebug operator<<(QDebug dbg, const SubPresentationRecord &r)
{
QDebugStateSaver stateSaver(dbg);
diff --git a/src/Authoring/Client/Code/Core/Doc/Doc.h b/src/Authoring/Client/Code/Core/Doc/Doc.h
index c4d4985a..dad6b365 100644
--- a/src/Authoring/Client/Code/Core/Doc/Doc.h
+++ b/src/Authoring/Client/Code/Core/Doc/Doc.h
@@ -240,10 +240,14 @@ public:
QMultiMap<QString,
QPair<qt3dsdm::Qt3DSDMInstanceHandle,
qt3dsdm::Qt3DSDMPropertyHandle>> *outMap = nullptr);
+ void UpdateDatainputMapForInstance(qt3dsdm::Qt3DSDMInstanceHandle inInstance);
bool VerifyControlledProperties(const qt3dsdm::Qt3DSDMInstanceHandle inInstance);
void ReplaceDatainput(const QString &oldName, const QString &newName,
const QList<qt3dsdm::Qt3DSDMInstanceHandle> &instances);
+ QString GetCurrentController(qt3dsdm::Qt3DSDMInstanceHandle instHandle,
+ qt3dsdm::Qt3DSDMPropertyHandle propHandle) const;
+
bool IsModified();
bool IsValid() const;
@@ -355,6 +359,8 @@ public:
void RemoveDatainputBindings(
const QMultiMap<QString, QPair<qt3dsdm::Qt3DSDMInstanceHandle,
qt3dsdm::Qt3DSDMPropertyHandle>> *map) override;
+ QString GetCurrentController(qt3dsdm::Qt3DSDMInstanceHandle instHandle,
+ qt3dsdm::Qt3DSDMPropertyHandle propHandle) override;
Q3DStudio::IDocumentBufferCache &GetBufferCache() override;
Q3DStudio::IDocumentReader &GetDocumentReader() override;
Q3DStudio::IDocumentEditor &OpenTransaction(const QString &inCmdName, const char *inFile,
diff --git a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp
index 4d51b4c9..dd988c7d 100644
--- a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp
+++ b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp
@@ -1681,21 +1681,36 @@ public:
CreateSceneGraphInstance(ComposerObjectTypes::Image, instance, theSlide);
const Q3DStudio::TGUIDPacked thePackedGuid(m_Bridge.GetGUID(theImageInstance));
qt3dsdm::SLong4 theImageGuid(thePackedGuid.Data1, thePackedGuid.Data2, thePackedGuid.Data3,
- thePackedGuid.Data4);
+ thePackedGuid.Data4);
m_SlideCore.ForceSetInstancePropertyValue(theSlide, instance, propName, theImageGuid);
- if (propName == m_Bridge.GetObjectDefinitions().m_Material.m_SpecularReflection)
+ if (propName == m_Bridge.GetObjectDefinitions().m_Material.m_SpecularReflection) {
SetInstancePropertyValue(theImageInstance,
m_Bridge.GetObjectDefinitions().m_Image.m_TextureMapping,
std::make_shared<CDataStr>(L"Environmental Mapping"), false);
- else if (propName == m_Bridge.GetObjectDefinitions().m_Layer.m_LightProbe
- || propName == m_Bridge.GetObjectDefinitions().m_Layer.m_LightProbe2)
+ } else if (propName == m_Bridge.GetObjectDefinitions().m_Layer.m_LightProbe
+ || propName == m_Bridge.GetObjectDefinitions().m_Layer.m_LightProbe2) {
SetInstancePropertyValue(theImageInstance,
m_Bridge.GetObjectDefinitions().m_Image.m_TextureMapping,
std::make_shared<CDataStr>(L"Light Probe"), false);
- else if (propName == m_Bridge.GetObjectDefinitions().m_MaterialBase.m_IblProbe)
+ // Preserve legacy behavior where image based lighting used always tiling for
+ // horizontal direction
+ SetInstancePropertyValue(theImageInstance,
+ m_Bridge.GetObjectDefinitions().m_Image.m_TilingU,
+ std::make_shared<CDataStr>(L"Tiled"), false);
+ SetInstancePropertyValue(theImageInstance,
+ m_Bridge.GetObjectDefinitions().m_Image.m_TilingV,
+ std::make_shared<CDataStr>(L"No Tiling"), false);
+ } else if (propName == m_Bridge.GetObjectDefinitions().m_MaterialBase.m_IblProbe) {
SetInstancePropertyValue(theImageInstance,
m_Bridge.GetObjectDefinitions().m_Image.m_TextureMapping,
- std::make_shared<CDataStr>(L"IBL Override"), false);
+ std::make_shared<CDataStr>(L"Light Probe"), false);
+ SetInstancePropertyValue(theImageInstance,
+ m_Bridge.GetObjectDefinitions().m_Image.m_TilingU,
+ std::make_shared<CDataStr>(L"Tiled"), false);
+ SetInstancePropertyValue(theImageInstance,
+ m_Bridge.GetObjectDefinitions().m_Image.m_TilingV,
+ std::make_shared<CDataStr>(L"No Tiling"), false);
+ }
return theImageInstance;
}
@@ -2016,7 +2031,7 @@ public:
void writeMaterialFile(Qt3DSDMInstanceHandle instance, bool createNewFile) override
{
- const auto materialName = GetName(instance);
+ const auto materialName = CFilePath::MakeSafeFileStem(GetName(instance));
writeMaterialFile(instance, materialName, createNewFile,
getFilePathFromMaterialName(materialName));
}
@@ -2244,7 +2259,7 @@ public:
Qt3DSDMSlideHandle slide = m_Bridge.GetOrCreateGraphRoot(parent);
instance = CreateSceneGraphInstance(ComposerObjectTypes::Material, parent,
slide, DocumentEditorInsertType::LastChild,
- CPt(), PRIMITIVETYPE_UNKNOWN, -1);
+ CPt(), PRIMITIVETYPE_UNKNOWN, -1, true, false);
SetName(instance, m_Bridge.getMaterialContainerName());
m_SlideCore.forceSetInstancePropertyValueOnAllSlides(
instance, m_Bridge.GetSceneAsset().m_EndTime, 0);
@@ -2372,6 +2387,14 @@ public:
TInstanceHandle handle;
};
+ void setInstanceValueIfChanged(TInstanceHandle instance, TPropertyHandle prop, SValue value)
+ {
+ SValue oldValue;
+ m_PropertySystem.GetInstancePropertyValue(instance, prop, oldValue);
+ if (oldValue != value)
+ SetInstancePropertyValue(instance, prop, value);
+ }
+
QVector<ChildInstance> setPropertyValues(TInstanceHandle instance,
const QMap<QString, QString> &values)
{
@@ -2396,8 +2419,7 @@ public:
switch (type) {
case DataModelDataType::Long4:
{
- SetInstancePropertyValue(instance, prop,
- std::make_shared<CDataStr>(propString));
+ setInstanceValueIfChanged(instance, prop, std::make_shared<CDataStr>(propString));
SValue value;
m_PropertySystem.GetInstancePropertyValue(instance, prop, value);
if (!value.empty()) {
@@ -2412,7 +2434,7 @@ public:
}
case DataModelDataType::Float:
{
- SetInstancePropertyValue(instance, prop, i.value().toFloat());
+ setInstanceValueIfChanged(instance, prop, i.value().toFloat());
break;
}
case DataModelDataType::Float2:
@@ -2420,7 +2442,7 @@ public:
QStringList floats = i.value().split(QStringLiteral(" "));
if (floats.length() == 2) {
SFloat2 value(floats[0].toFloat(), floats[1].toFloat());
- SetInstancePropertyValue(instance, prop, value);
+ setInstanceValueIfChanged(instance, prop, value);
}
break;
}
@@ -2429,21 +2451,21 @@ public:
QStringList floats = i.value().split(QStringLiteral(" "));
if (floats.length() == 3) {
SFloat3 value(floats[0].toFloat(), floats[1].toFloat(), floats[2].toFloat());
- SetInstancePropertyValue(instance, prop, value);
+ setInstanceValueIfChanged(instance, prop, value);
}
break;
}
case DataModelDataType::Bool:
{
if (propString == "True")
- SetInstancePropertyValue(instance, prop, true);
+ setInstanceValueIfChanged(instance, prop, true);
else if (propString == "False")
- SetInstancePropertyValue(instance, prop, false);
+ setInstanceValueIfChanged(instance, prop, false);
break;
}
case DataModelDataType::String:
{
- SetInstancePropertyValue(instance, prop, std::make_shared<CDataStr>(propString));
+ setInstanceValueIfChanged(instance, prop, std::make_shared<CDataStr>(propString));
break;
}
default:
@@ -2471,6 +2493,8 @@ public:
if (textureValues.contains(child.name))
setPropertyValues(child.handle, textureValues[child.name]);
}
+
+ m_Doc.GetCore()->GetDispatch()->FireImmediateRefreshInstance(instance);
}
void SetSlideName(TInstanceHandle inSlideInstance, TPropertyHandle propName,
@@ -5793,5 +5817,5 @@ void CUpdateableDocumentEditor::RollbackEditor()
std::shared_ptr<IInternalDocumentEditor> IInternalDocumentEditor::CreateEditor(CDoc &doc)
{
- return std::shared_ptr<IInternalDocumentEditor>(new CDocEditor(doc));
+ return std::make_shared<CDocEditor>(doc);
}
diff --git a/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp b/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp
index 39b51e94..3a1907b7 100644
--- a/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp
+++ b/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp
@@ -1536,6 +1536,30 @@ struct SComposerSerializerImpl : public IComposerSerializer
ioProperties.clear();
ParseInstanceProperties(inReader, inInstance, outExtraAttributes, ioProperties);
+
+ // Fix for QT3DS-2581: if an image has mapping mode "Light Probe" without
+ // explicitly set U tiling mode, force horizontal tiling to "Tiled" to
+ // obey legacy behavior where light probe U tiling was hard-wired to tiled. This
+ // is to preserve behavior on old presentations that relied on hardcoding.
+ bool hasMappingAsProbe = false;
+ bool hasTilingH = false;
+ for (size_t idx = 0, end = ioProperties.size(); idx < end; ++idx) {
+ if (ioProperties[idx].first == m_ObjectDefinitions.m_Image.m_TilingU)
+ hasTilingH = true;
+ if (ioProperties[idx].first == m_ObjectDefinitions.m_Image.m_TextureMapping
+ && ioProperties[idx].second.toQVariant() == QVariant("Light Probe")) {
+ hasMappingAsProbe = true;
+ }
+ }
+
+ if (!hasTilingH && hasMappingAsProbe) {
+ qCDebug(qt3ds::TRACE_INFO)
+ << "Setting light probe horizontal tiling default to 'Tiled'.";
+ qt3dsdm::SValue theValue(qt3dsdm::TDataStrPtr(new qt3dsdm::CDataStr(L"Tiled")));
+ ioProperties.push_back(std::make_pair(
+ m_ObjectDefinitions.m_Image.m_TilingU, theValue));
+ }
+
if (inSlide.Valid()) {
for (size_t idx = 0, end = ioProperties.size(); idx < end; ++idx)
m_SlideCore.ForceSetInstancePropertyValue(inSlide, inInstance,
diff --git a/src/Authoring/Client/Code/Core/Doc/IDoc.h b/src/Authoring/Client/Code/Core/Doc/IDoc.h
index 955c364c..33b8463e 100644
--- a/src/Authoring/Client/Code/Core/Doc/IDoc.h
+++ b/src/Authoring/Client/Code/Core/Doc/IDoc.h
@@ -114,6 +114,9 @@ public:
virtual void RemoveDatainputBindings(
const QMultiMap<QString, QPair<qt3dsdm::Qt3DSDMInstanceHandle,
qt3dsdm::Qt3DSDMPropertyHandle>> *map) = 0;
+
+ virtual QString GetCurrentController(qt3dsdm::Qt3DSDMInstanceHandle instHandle,
+ qt3dsdm::Qt3DSDMPropertyHandle propHandle) = 0;
// Return an editor to editing the scene graph of the document.
// This editor takes care of putting objects into the property slide
// as well as updating the world
diff --git a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h
index 0349ec3f..2e5fe2c6 100644
--- a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h
+++ b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h
@@ -217,7 +217,7 @@ public:
static const long DEFAULT_CLIENT_WIDTH = 1920;
static const long DEFAULT_CLIENT_HEIGHT = 1080;
static const long DEFAULT_TIME_ADVANCE = 100;
- static const long DEFAULT_BIG_TIME_ADVANCE = 200;
+ static const long DEFAULT_BIG_TIME_ADVANCE = 500;
static const long DEFAULT_SELECTOR_WIDTH = 30;
static const long DEFAULT_SELECTOR_LENGTH = 50;
static const long DEFAULT_AUTOSAVE_DELAY = 600;
diff --git a/src/Authoring/Client/Code/Core/Utility/q3dsdirwatcher.cpp b/src/Authoring/Client/Code/Core/Utility/q3dsdirwatcher.cpp
index 4ce3ae9d..a3601a28 100644
--- a/src/Authoring/Client/Code/Core/Utility/q3dsdirwatcher.cpp
+++ b/src/Authoring/Client/Code/Core/Utility/q3dsdirwatcher.cpp
@@ -212,11 +212,16 @@ void Q3DSDirWatcher::sendRecords()
void Q3DSDirWatcher::addRecord(const QString &path, FileModificationType::Enum type)
{
- m_records.push_back(getRecordFromCache(path, type));
+ auto iter = std::find_if(m_records.begin(), m_records.end(),
+ [&](SFileModificationRecord &m) -> bool
+ { return m.m_File == path && m.m_ModificationType == type; });
+
+ if (iter == m_records.end()) // add only unique entries
+ m_records.push_back(getRecordFromCache(path, type));
}
SFileModificationRecord Q3DSDirWatcher::getRecordFromCache(const QString &path,
- FileModificationType::Enum type)
+ FileModificationType::Enum type)
{
if (m_recordCache.contains(path)) {
m_recordCache[path].m_ModificationType = type;
diff --git a/src/Authoring/Common/Code/Qt3DSFileTools.cpp b/src/Authoring/Common/Code/Qt3DSFileTools.cpp
index fe38dca8..092237aa 100644
--- a/src/Authoring/Common/Code/Qt3DSFileTools.cpp
+++ b/src/Authoring/Common/Code/Qt3DSFileTools.cpp
@@ -377,6 +377,38 @@ QString CFilePath::GetUserApplicationDirectory()
return QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
}
+// Qt has no native folder copy, so do it the hard way
+bool CFilePath::copyFolder(const QString &srcFolder, const QString &destFolder)
+{
+ bool success = false;
+
+ QDir srcDir(srcFolder);
+ if (!srcDir.exists())
+ return false;
+
+ QDir destDir(destFolder);
+ if (!destDir.exists())
+ destDir.mkpath(QStringLiteral("."));
+
+ const QStringList files = srcDir.entryList(QDir::Files);
+ for (const auto &file : files) {
+ success = QFile::copy(srcFolder + QLatin1Char('/') + file,
+ destFolder + QLatin1Char('/') + file);
+ if (!success)
+ return false;
+ }
+
+ const QStringList dirs = srcDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
+ for (const auto &dir : dirs) {
+ success = copyFolder(srcFolder + QLatin1Char('/') + dir,
+ destFolder + QLatin1Char('/') + dir);
+ if (!success)
+ return false;
+ }
+
+ return true;
+}
+
SFile::SFile(const QSharedPointer<QFile> &of, const CFilePath &path)
: m_OpenFile(of)
, m_Path(path)
diff --git a/src/Authoring/Common/Code/Qt3DSFileTools.h b/src/Authoring/Common/Code/Qt3DSFileTools.h
index bb77f36c..e66e29f5 100644
--- a/src/Authoring/Common/Code/Qt3DSFileTools.h
+++ b/src/Authoring/Common/Code/Qt3DSFileTools.h
@@ -247,6 +247,8 @@ public:
// Get the directory where applications can write data.
static QString GetUserApplicationDirectory();
+ static bool copyFolder(const QString &srcFolder, const QString &destFolder);
+
private:
void normalizeAndSetPath(const QString& path);
QString m_identifier;
diff --git a/src/Authoring/QT3DSDM/Systems/Qt3DSDMActionInfo.h b/src/Authoring/QT3DSDM/Systems/Qt3DSDMActionInfo.h
index ee4d1917..efc70202 100644
--- a/src/Authoring/QT3DSDM/Systems/Qt3DSDMActionInfo.h
+++ b/src/Authoring/QT3DSDM/Systems/Qt3DSDMActionInfo.h
@@ -37,8 +37,8 @@ namespace qt3dsdm {
using std::wstring;
struct SActionInfo
{
- Qt3DSDMInstanceHandle m_Instance; // InstanceHandle corresponding to this action (to store other
- // properties not listed here)
+ // InstanceHandle corresponding to this action (to store other properties not listed here)
+ Qt3DSDMInstanceHandle m_Instance;
// Where the action is added to
Qt3DSDMSlideHandle m_Slide; // the slide that the action is added to
diff --git a/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp b/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp
index 8155b13f..83e9384b 100644
--- a/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp
+++ b/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp
@@ -223,11 +223,14 @@ struct DataConstructor<SObjectRefType>
#define QT3DS_PROPNAME_tracking "tracking"
#define QT3DS_PROPNAME_dropshadow "dropshadow"
#define QT3DS_PROPNAME_dropshadowstrength "dropshadowstrength"
-#define QT3DS_PROPNAME_dropshadowoffset "dropshadowoffset"
-#define QT3DS_PROPNAME_dropshadowhorzalign "dropshadowhorzalign"
-#define QT3DS_PROPNAME_dropshadowvertalign "dropshadowvertalign"
+#define QT3DS_PROPNAME_dropshadowoffset "dropshadowoffset" // To be removed in 2.x (when UIP version is next updated)
+#define QT3DS_PROPNAME_dropshadowoffsetx "dropshadowoffsetx"
+#define QT3DS_PROPNAME_dropshadowoffsety "dropshadowoffsety"
+#define QT3DS_PROPNAME_dropshadowhorzalign "dropshadowhorzalign" // To be removed in 2.x (when UIP version is next updated)
+#define QT3DS_PROPNAME_dropshadowvertalign "dropshadowvertalign" // To be removed in 2.x (when UIP version is next updated)
#define QT3DS_PROPNAME_wordwrap "wordwrap"
#define QT3DS_PROPNAME_boundingbox "boundingbox"
+#define QT3DS_PROPNAME_elide "elide"
#define QT3DS_PROPNAME_enableacceleratedfont "enableacceleratedfont"
#define QT3DS_PROPNAME_importfile "importfile"
#define QT3DS_PROPNAME_fileid "fileid"
diff --git a/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h b/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h
index 9088c08a..4d54ea07 100644
--- a/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h
+++ b/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h
@@ -280,10 +280,13 @@ class IPropertySystem;
HANDLE_COMPOSER_PROPERTY(dropshadow, m_DropShadow, bool, false) \
HANDLE_COMPOSER_PROPERTY(dropshadowstrength, m_DropShadowStrength, float, 80.f) \
HANDLE_COMPOSER_PROPERTY(dropshadowoffset, m_DropShadowOffset, float, 10.f) \
+ HANDLE_COMPOSER_PROPERTY(dropshadowoffsetx, m_DropShadowOffsetX, float, 0.f) \
+ HANDLE_COMPOSER_PROPERTY(dropshadowoffsety, m_DropShadowOffsetY, float, 0.f) \
HANDLE_COMPOSER_PROPERTY(dropshadowhorzalign, m_DropShadowHorizontalAlignment, TDataStrPtr, L"Right") \
HANDLE_COMPOSER_PROPERTY(dropshadowvertalign, m_DropShadowVerticalAlignment, TDataStrPtr, L"Bottom") \
HANDLE_COMPOSER_PROPERTY(wordwrap, m_WordWrap, TDataStrPtr, L"WrapWord") \
HANDLE_COMPOSER_PROPERTY(boundingbox, m_BoundingBox, SFloat2, SFloat2(0, 0)) \
+ HANDLE_COMPOSER_PROPERTY(elide, m_Elide, bool, false) \
HANDLE_COMPOSER_PROPERTY(enableacceleratedfont, m_EnableAcceleratedFont, bool, false) \
HANDLE_COMPOSER_PROPERTY_DUPLICATE(controlledproperty, m_ControlledProperty, TDataStrPtr, L"")
diff --git a/src/Authoring/QT3DSDM/Systems/Qt3DSDMDataCore.h b/src/Authoring/QT3DSDM/Systems/Qt3DSDMDataCore.h
index d9e9fca4..971bd779 100644
--- a/src/Authoring/QT3DSDM/Systems/Qt3DSDMDataCore.h
+++ b/src/Authoring/QT3DSDM/Systems/Qt3DSDMDataCore.h
@@ -272,6 +272,10 @@ public:
virtual TMetaDataData GetAdditionalMetaDataData(Qt3DSDMInstanceHandle inInstance,
Qt3DSDMPropertyHandle inProperty) const = 0;
virtual Qt3DSDMInstanceHandle GetPropertyOwner(Qt3DSDMPropertyHandle inProperty) const = 0;
+
+ virtual QVector<Qt3DSDMPropertyHandle> GetControllableProperties(
+ Qt3DSDMInstanceHandle inInst) const = 0;
+
};
typedef std::shared_ptr<IPropertySystem> TPropertySystemPtr;
diff --git a/src/Authoring/QT3DSDM/Systems/Qt3DSDMTransactions.h b/src/Authoring/QT3DSDM/Systems/Qt3DSDMTransactions.h
index f3d47d7b..f6ed3da0 100644
--- a/src/Authoring/QT3DSDM/Systems/Qt3DSDMTransactions.h
+++ b/src/Authoring/QT3DSDM/Systems/Qt3DSDMTransactions.h
@@ -187,15 +187,6 @@ struct CTransactionConsumer : public ITransactionConsumer
}
};
-struct SIgnorantTransactionConsumer : public ITransactionConsumer
-{
- void OnTransaction(qt3dsdm::TTransactionPtr) override {}
- // Notifications to be sent for undo/redo These are used to
- // notify clients that something is different.
- void OnDoNotification(std::function<void()>) override {}
- void OnUndoNotification(std::function<void()>) override {}
-};
-
template <typename TTransactionType>
inline void RunWithConsumer(TTransactionConsumerPtr inConsumer, TTransactionType inTransaction)
{
diff --git a/src/Authoring/QT3DSDM/Systems/StudioPropertySystem.cpp b/src/Authoring/QT3DSDM/Systems/StudioPropertySystem.cpp
index e97f21ff..068dceff 100644
--- a/src/Authoring/QT3DSDM/Systems/StudioPropertySystem.cpp
+++ b/src/Authoring/QT3DSDM/Systems/StudioPropertySystem.cpp
@@ -187,6 +187,26 @@ bool CStudioPropertySystem::IsInstanceOrDerivedFrom(Qt3DSDMInstanceHandle inInst
return m_DataCore->IsInstanceOrDerivedFrom(inInstance, inParent);
}
+QVector<Qt3DSDMPropertyHandle>
+CStudioPropertySystem::GetControllableProperties(Qt3DSDMInstanceHandle inInst) const
+{
+ vector<Qt3DSDMMetaDataPropertyHandle> propList;
+ QVector<Qt3DSDMPropertyHandle> outList;
+ m_MetaData->GetMetaDataProperties(inInst, propList);
+
+ for (const auto it : qAsConst(propList)) {
+ auto metadata = m_MetaData->GetMetaDataPropertyInfo(it).getValue();
+
+ if ((metadata.m_Controllable
+ || (metadata.m_Animatable
+ && m_StudioAnimationSystem->IsPropertyAnimatable(inInst, metadata.m_Property)))
+ && !metadata.m_IsHidden) {
+ outList.append(metadata.m_Property);
+ }
+ }
+ return outList;
+}
+
Qt3DSDMPropertyHandle CStudioPropertySystem::AddProperty(Qt3DSDMInstanceHandle inInstance,
const QString &inName,
DataModelDataType::Value inPropType)
diff --git a/src/Authoring/QT3DSDM/Systems/StudioPropertySystem.h b/src/Authoring/QT3DSDM/Systems/StudioPropertySystem.h
index b180778d..8ded286f 100644
--- a/src/Authoring/QT3DSDM/Systems/StudioPropertySystem.h
+++ b/src/Authoring/QT3DSDM/Systems/StudioPropertySystem.h
@@ -119,6 +119,9 @@ public:
Qt3DSDMPropertyHandle inProperty,
SValue &outValue) const;
+ QVector<Qt3DSDMPropertyHandle> GetControllableProperties(
+ Qt3DSDMInstanceHandle inInst) const override;
+
private:
static bool DerivedGuidMatches(qt3dsdm::IDataCore &inDataCore,
qt3dsdm::Qt3DSDMInstanceHandle inInstance,
diff --git a/src/Authoring/QT3DSIMP/Qt3DSImportLib/Qt3DSImportComposerTypes.cpp b/src/Authoring/QT3DSIMP/Qt3DSImportLib/Qt3DSImportComposerTypes.cpp
index 1d9ca48d..e6aeb7c1 100644
--- a/src/Authoring/QT3DSIMP/Qt3DSImportLib/Qt3DSImportComposerTypes.cpp
+++ b/src/Authoring/QT3DSIMP/Qt3DSImportLib/Qt3DSImportComposerTypes.cpp
@@ -62,6 +62,18 @@ DataModelDataType::Value SImportModel::GetPropertyDataType(const QString &inProp
return SImportNode::GetPropertyDataType(inPropertyName);
}
+DataModelDataType::Value SImportLight::GetPropertyDataType(const QString &inPropertyName)
+{
+ ITERATE_COMPOSER_LIGHT_PROPERTIES
+ return SImportNode::GetPropertyDataType(inPropertyName);
+}
+
+DataModelDataType::Value SImportCamera::GetPropertyDataType(const QString &inPropertyName)
+{
+ ITERATE_COMPOSER_CAMERA_PROPERTIES
+ return SImportNode::GetPropertyDataType(inPropertyName);
+}
+
DataModelDataType::Value SImportMaterial::GetPropertyDataType(const QString &inPropertyName)
{
ITERATE_COMPOSER_MATERIAL_PROPERTIES
@@ -102,7 +114,9 @@ DataModelDataType::Value SImportControllableObject::GetPropertyDataType(
ITERATE_COMPOSER_MATERIAL_PROPERTIES
ITERATE_COMPOSER_NODE_PROPERTIES
ITERATE_COMPOSER_LIGHT_PROPERTIES
- return SImportAsset::GetPropertyDataType(inPropertyName);
+ // Cannot fall back to SImportAsset as we might receive custom material
+ // properties which are not known to property system and cause assert.
+ return DataModelDataType::None;
}
#undef HANDLE_COMPOSER_PROPERTY_NO_DEFAULT
@@ -131,6 +145,10 @@ SImportAsset &SImportComposerTypes::GetImportAssetForType(ComposerObjectTypes::E
return m_Asset;
case ComposerObjectTypes::Group:
return m_Group;
+ case ComposerObjectTypes::Light:
+ return m_Light;
+ case ComposerObjectTypes::Camera:
+ return m_Camera;
case ComposerObjectTypes::Model:
return m_Model;
case ComposerObjectTypes::Node:
diff --git a/src/Authoring/QT3DSIMP/Qt3DSImportLib/Qt3DSImportComposerTypes.h b/src/Authoring/QT3DSIMP/Qt3DSImportLib/Qt3DSImportComposerTypes.h
index a5a7f896..3b9c33c5 100644
--- a/src/Authoring/QT3DSIMP/Qt3DSImportLib/Qt3DSImportComposerTypes.h
+++ b/src/Authoring/QT3DSIMP/Qt3DSImportLib/Qt3DSImportComposerTypes.h
@@ -86,6 +86,20 @@ struct SImportGroup : public SImportNode
ComposerObjectTypes::Enum GetObjectType() override { return ComposerObjectTypes::Group; }
};
+struct SImportLight : public SImportNode
+{
+ ITERATE_COMPOSER_LIGHT_PROPERTIES
+ DataModelDataType::Value GetPropertyDataType(const QString &inPropertyName) override;
+ ComposerObjectTypes::Enum GetObjectType() override { return ComposerObjectTypes::Light; }
+};
+
+struct SImportCamera : public SImportNode
+{
+ ITERATE_COMPOSER_CAMERA_PROPERTIES
+ DataModelDataType::Value GetPropertyDataType(const QString &inPropertyName) override;
+ ComposerObjectTypes::Enum GetObjectType() override { return ComposerObjectTypes::Camera; }
+};
+
struct SImportModel : public SImportNode
{
ITERATE_COMPOSER_MODEL_PROPERTIES
@@ -180,6 +194,8 @@ struct SImportComposerTypes
{
SImportAsset m_Asset;
SImportGroup m_Group;
+ SImportLight m_Light;
+ SImportCamera m_Camera;
SImportModel m_Model;
SImportNode m_Node;
SImportMaterial m_Material;
diff --git a/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportColladaSGTranslation.cpp b/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportColladaSGTranslation.cpp
index 0fc889bf..4a3c3a1a 100644
--- a/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportColladaSGTranslation.cpp
+++ b/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportColladaSGTranslation.cpp
@@ -139,6 +139,10 @@ protected:
std::function<void(long, long)> PopMaterial;
std::function<void(const char *, const char *, long)> PushTexture;
std::function<void()> PopTexture;
+ std::function<void(const char *)> PushLight;
+ std::function<void()> PopLight;
+ std::function<void(const char *)> PushCamera;
+ std::function<void()> PopCamera;
std::function<void(daeElement *inElement)> CacheAnimationTrack;
std::function<void(long)> ApplyAnimationTrack;
@@ -150,6 +154,10 @@ protected:
std::function<void(const TTransformList &inTransforms)> SetTransforms;
std::function<void(const SMaterialParameters &inMaterialParameters)> SetMaterial;
std::function<void(long inMapType, const STextureParameters &inTextureParameters)> SetTexture;
+ std::function<void(double clipstart, double clipend, bool ortho,
+ double fov)> SetCameraProperties;
+ std::function<void(int type, const SFloat3 &color, double intensity,
+ double linearfade, double quadfade, bool shadows)> SetLightProperties;
std::function<void(const char *, const char *)> SetAnimationTrack;
std::function<void(const char *, const char *, const SKeyframeParameters &)>
@@ -182,7 +190,7 @@ void FindTexturesViaNewParam(daeElement *inElementPtr, ColladaDOMWalker::TURILis
if (theSourceRef) {
const xsNCName theSourceSid = theSourceRef->getValue();
- daeElement *theSurfaceNewParamPtr = NULL;
+ daeElement *theSurfaceNewParamPtr = nullptr;
if (RecursiveFindElementBySid(theSourceSid, theSurfaceNewParamPtr,
theNewParam->getParent(), -1, domEffect::ID())) {
FindTexturesViaNewParam(theSurfaceNewParamPtr, outTexturePaths);
@@ -241,7 +249,7 @@ long RetrieveFaceIndex(ColladaDOMWalker::TFaceIndicies &ioFaceIndicies,
* the actual functions within that class.
*/
ColladaDOMWalker::ColladaDOMWalker(ISceneGraphTranslation *inTranslation)
- : m_ColladaRoot(NULL)
+ : m_ColladaRoot(nullptr)
, m_Translator(inTranslation)
{
PushGroup = std::bind(&ISceneGraphTranslation::PushGroup, m_Translator, std::placeholders::_1);
@@ -257,6 +265,20 @@ ColladaDOMWalker::ColladaDOMWalker(ISceneGraphTranslation *inTranslation)
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
PopTexture = std::bind(&ISceneGraphTranslation::PopTexture, m_Translator);
+ PushLight = std::bind(&ISceneGraphTranslation::PushLight, m_Translator, std::placeholders::_1);
+ SetLightProperties = std::bind(&ISceneGraphTranslation::SetLightProperties, m_Translator,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, std::placeholders::_4,
+ std::placeholders::_5, std::placeholders::_6);
+ PopLight = std::bind(&ISceneGraphTranslation::PopLight, m_Translator);
+
+ PushCamera = std::bind(&ISceneGraphTranslation::PushCamera, m_Translator,
+ std::placeholders::_1);
+ SetCameraProperties = std::bind(&ISceneGraphTranslation::SetCameraProperties, m_Translator,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3, std::placeholders::_4);
+ PopCamera = std::bind(&ISceneGraphTranslation::PopCamera, m_Translator);
+
CacheAnimationTrack =
std::bind(&ColladaDOMWalker::TrackObjectIndex, this, std::placeholders::_1,
std::bind(&ISceneGraphTranslation::CacheAnimationTrack, m_Translator));
@@ -341,7 +363,7 @@ bool ColladaDOMWalker::LoadDocument(const std::string &inFilePath)
*/
void ColladaDOMWalker::ProcessScene()
{
- if (m_ColladaRoot != NULL) {
+ if (m_ColladaRoot != nullptr) {
const domCOLLADA::domSceneRef theScene = m_ColladaRoot->getScene();
// Retrieve the active visual_scene
const domInstanceWithExtraRef theInstanceVisualScene = theScene->getInstance_visual_scene();
@@ -498,9 +520,12 @@ void ColladaDOMWalker::ProcessNode(const domNodeRef inNode)
inNode->getInstance_geometry_array();
long theGeometryCount = (long)theInstanceGeometryArray.getCount();
bool thePushModelFlag = false;
+ bool lightFlag = false;
+ bool cameraFlag = false;
- if (theGeometryCount == 1) // Just a single model
- {
+ // Process the node
+ if (theGeometryCount == 1) {
+ // Just a single model
thePushModelFlag = true;
PushModel(GetNameOrIDOrSid(inNode));
ProcessTransform(inNode);
@@ -511,8 +536,8 @@ void ColladaDOMWalker::ProcessNode(const domNodeRef inNode)
PushGroup(GetNameOrIDOrSid(inNode));
ProcessTransform(inNode);
}
- } else // Multiple models
- {
+ } else if (theGeometryCount > 1) {
+ // Multiple models
thePushModelFlag = false;
PushGroup(GetNameOrIDOrSid(inNode));
ProcessTransform(inNode);
@@ -524,19 +549,103 @@ void ColladaDOMWalker::ProcessNode(const domNodeRef inNode)
ProcessInstanceGeometry(inNode, theInstanceGeometryRef);
PopModel();
}
+ } else {
+ // No geometry
+ const domInstance_light_Array &lights = inNode->getInstance_light_array();
+ const domInstance_camera_Array &cameras = inNode->getInstance_camera_array();
+ if (cameras.getCount()) {
+ // Camera
+ cameraFlag = true;
+ PushCamera(GetNameOrIDOrSid(inNode));
+ ProcessTransform(inNode);
+ // Process camera properties
+ const domInstance_cameraRef cameraRef = cameras[0];
+ const xsAnyURI &cameraURI = cameraRef->getUrl();
+ const daeElementRef cameraElementRef = cameraURI.getElement();
+ const domCamera *camera = daeSafeCast<domCamera>(cameraElementRef);
+ domCamera::domOptics::domTechnique_commonRef technique
+ = camera->getOptics()->getTechnique_common();
+ double fov = 0;
+ double clipstart = 0;
+ double clipend = 0;
+ bool ortho = false;
+ if (technique->getPerspective()) {
+ fov = technique->getPerspective()->getXfov() != nullptr
+ ? technique->getPerspective()->getXfov()->getValue()
+ : technique->getPerspective()->getYfov()->getValue();
+ clipstart = technique->getPerspective()->getZnear()->getValue();
+ clipend = technique->getPerspective()->getZfar()->getValue();
+ } else if (technique->getOrthographic()) {
+ fov = technique->getOrthographic()->getXmag() != nullptr
+ ? technique->getOrthographic()->getXmag()->getValue()
+ : technique->getOrthographic()->getYmag()->getValue();
+ clipstart = technique->getOrthographic()->getZnear()->getValue();
+ clipend = technique->getOrthographic()->getZfar()->getValue();
+ ortho = true;
+ }
+ SetCameraProperties(clipstart, clipend, ortho, fov);
+ } else if (lights.getCount()) {
+ // Light
+ lightFlag = true;
+ PushLight(GetNameOrIDOrSid(inNode));
+ ProcessTransform(inNode);
+ // Process light properties
+ const domInstance_lightRef lightRef = lights[0];
+ const xsAnyURI &lightURI = lightRef->getUrl();
+ const daeElementRef lightElementRef = lightURI.getElement();
+ const domLight *light = daeSafeCast<domLight>(lightElementRef);
+ domLight::domTechnique_commonRef technique = light->getTechnique_common();
+ int type = 0;
+ domFloat3 color;
+ double linearFade = 0;
+ double quadFade = 0;
+ if (technique->getPoint()) {
+ domLight::domTechnique_common::domPointRef point = technique->getPoint();
+ color = point->getColor()->getValue();
+ linearFade = point->getLinear_attenuation()->getValue() * 1000;
+ quadFade = point->getQuadratic_attenuation()->getValue() * 1000;
+ } else if (technique->getDirectional()) {
+ type = 1;
+ domLight::domTechnique_common::domDirectionalRef directional
+ = technique->getDirectional();
+ color = directional->getColor()->getValue();
+ } else if (technique->getAmbient()) {
+ type = 4;
+ domLight::domTechnique_common::domAmbientRef ambient = technique->getAmbient();
+ color = ambient->getColor()->getValue();
+ } else {
+ // We do not have support for spot light. It will be handled as
+ // directional in SetLightProperties.
+ type = 2;
+ domLight::domTechnique_common::domSpotRef spot = technique->getSpot();
+ color = spot->getColor()->getValue();
+ linearFade = spot->getLinear_attenuation()->getValue() * 1000;
+ quadFade = spot->getQuadratic_attenuation()->getValue() * 1000;
+ }
+ // Collada does not seem to have info about casting shadows or light intensity.
+ // We'll use the defaults (intensity 100, no shadows)
+ SetLightProperties(type, SFloat3(color.get(0), color.get(1), color.get(2)),
+ 100, linearFade, quadFade, false);
+ }
}
+ // Process the children
const domNode_Array &theNodes = inNode->getNode_array();
long theNodesCount = (long)theNodes.getCount();
- for (long theIndex = 0; theIndex < theNodesCount; ++theIndex) {
+ for (long theIndex = 0; theIndex < theNodesCount; ++theIndex)
ProcessNode(theNodes[theIndex]);
- }
- if (thePushModelFlag)
+ if (thePushModelFlag) {
PopModel();
- else
- PopGroup();
+ } else {
+ if (lightFlag)
+ PopLight();
+ else if (cameraFlag)
+ PopCamera();
+ else
+ PopGroup();
+ }
} break;
default: // No support for other types currently
break;
@@ -1297,14 +1406,14 @@ void ColladaDOMWalker::ProcessTextureParameters(const domExtraRef inTextureExtra
void ColladaDOMWalker::ProcessTexture(
const domCommon_color_or_texture_type_complexType::domTextureRef inTextureRef, long inMapType)
{
- if (inTextureRef != NULL) {
+ if (inTextureRef != nullptr) {
// TODO: What about texcoord?
const xsNCName theTextureParamSid = inTextureRef->getTexture();
ColladaDOMWalker::TURIList theTextures;
STextureParameters theTextureParameters;
ProcessTextureParameters(inTextureRef->getExtra(), theTextureParameters);
- daeElement *theNewParamPtr = NULL;
+ daeElement *theNewParamPtr = nullptr;
// Look for param name in <newparam>s
if (RecursiveFindElementBySid(theTextureParamSid, theNewParamPtr, inTextureRef,
@@ -1496,7 +1605,7 @@ void ColladaDOMWalker::ProcessAnimation(const domAnimationRef inAnimation)
void ColladaDOMWalker::ProcessChannel(const domChannelRef inChannel)
{
TStringList theIdentifierList;
- daeElement *theContainerElement = NULL;
+ daeElement *theContainerElement = nullptr;
const char *theBaseProperty = GetAnimatedPropertyInfoFromElement(
inChannel->getTarget(), m_ColladaRoot, theContainerElement, theIdentifierList);
@@ -1564,22 +1673,22 @@ void ColladaDOMWalker::ProcessSampler(const domSampler *inSamplerRef,
(float)theOUTPUTInfo.m_Array
->getValue()[theKeyframeIndex * theOUTPUTInfo.m_Stride
+ theOUTPUTInfo.m_Offset[theAnimatedSubPropertyIndex]],
- theIN_TANGENTInfo.m_Array != NULL
+ theIN_TANGENTInfo.m_Array != nullptr
? (float)theIN_TANGENTInfo.m_Array
->getValue()[theKeyframeIndex * theIN_TANGENTInfo.m_Stride
+ theAnimatedSubPropertyIndex * 2]
: 0.0f,
- theIN_TANGENTInfo.m_Array != NULL
+ theIN_TANGENTInfo.m_Array != nullptr
? (float)theIN_TANGENTInfo.m_Array
->getValue()[theKeyframeIndex * theIN_TANGENTInfo.m_Stride
+ theAnimatedSubPropertyIndex * 2 + 1]
: 0.0f,
- theOUT_TANGENTInfo.m_Array != NULL
+ theOUT_TANGENTInfo.m_Array != nullptr
? (float)theOUT_TANGENTInfo.m_Array
->getValue()[theKeyframeIndex * theOUT_TANGENTInfo.m_Stride
+ theAnimatedSubPropertyIndex * 2]
: 0.0f,
- theOUT_TANGENTInfo.m_Array != NULL
+ theOUT_TANGENTInfo.m_Array != nullptr
? (float)theOUT_TANGENTInfo.m_Array
->getValue()[theKeyframeIndex * theOUT_TANGENTInfo.m_Stride
+ theAnimatedSubPropertyIndex * 2 + 1]
diff --git a/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportFbxSGTranslation.cpp b/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportFbxSGTranslation.cpp
index 68f62ed1..52bf4690 100644
--- a/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportFbxSGTranslation.cpp
+++ b/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportFbxSGTranslation.cpp
@@ -91,10 +91,12 @@ protected:
void FilterNodeHierarchy(TNodeFilter inFilter, TNodeSet &inSet);
void ProcessNode(FbxNode *inFbxNode);
void ProcessGroup(FbxNode *inFbxNode);
+ void ProcessLight(FbxNode *inFbxNode);
+ void ProcessCamera(FbxNode *inFbxNode);
void ProcessMesh(FbxNode *inFbxNode);
void ProcessNodeChildren(FbxNode *inFbxNode);
long ProcessSkeletonNode(FbxNode *inFbxNode, TNodeSet &inNodeSet, bool inIsRoot);
- void ProcessTransform(FbxNode *inFbxNode);
+ void ProcessTransform(FbxNode *inFbxNode, bool ignoreScale = false);
void ReadVertex(const FbxVector4 *inFbxCtrlPoints, int inFbxCtrlPointIndex, float *outValue,
FbxAMatrix &geometricTransformation);
void ReadVertex(const TPerVertexWeightInfo &inFbxWeights, int inFbxCtrlPointIndex,
@@ -156,14 +158,13 @@ protected:
TNodeToIndicesMap m_NodeToIndicies;
TNodeIsAnimatedMap m_NodeIsAnimatedMap;
TJointNodeHierarchyMap m_JointNodeHierarchyMap;
- // Set if nodes we need to export in order to see all meshes in the file.
- TNodeSet m_meshNodes;
+ TNodeSet m_importNodes;
EAuthoringToolType m_AuthoringToolType;
};
FbxDomWalker::FbxDomWalker(ISceneGraphTranslation *inTranslation)
- : m_FbxManager(NULL)
- , m_FbxScene(NULL)
+ : m_FbxManager(nullptr)
+ , m_FbxScene(nullptr)
, m_Translator(inTranslation)
, m_AnimationTrackCount(0)
, m_AuthoringToolType(EAuthoringToolType_Unknown)
@@ -172,9 +173,9 @@ FbxDomWalker::FbxDomWalker(ISceneGraphTranslation *inTranslation)
FbxDomWalker::~FbxDomWalker()
{
- if (m_FbxScene != NULL)
+ if (m_FbxScene != nullptr)
m_FbxScene->Destroy();
- if (m_FbxManager != NULL)
+ if (m_FbxManager != nullptr)
m_FbxManager->Destroy();
}
@@ -256,6 +257,11 @@ bool FbxDomWalker::LoadDocument(const std::string &inFilePath)
m_Translator->SetAuthoringTool(EAuthoringToolType_FBX_Maya,
major * 1000 + minor * 100 + revision);
m_AuthoringToolType = EAuthoringToolType_FBX_Maya;
+ } else if (strstr(appName, "Blender")) {
+ qWarning("Importing from Blender. Light and Camera rotations may be incorrect");
+ m_Translator->SetAuthoringTool(EAuthoringToolType_FBX_Blender,
+ major * 1000 + minor * 100 + revision);
+ m_AuthoringToolType = EAuthoringToolType_FBX_Blender;
} else {
m_Translator->SetAuthoringTool(EAuthoringToolType_FBX_Max,
major * 1000 + minor * 100 + revision);
@@ -311,15 +317,30 @@ struct SMeshFilter
// filter out valid meshes. Anything else we don't care about.
bool operator()(FbxNode &inFbxNode) const
{
- if (inFbxNode.GetNodeAttribute() != NULL) {
+ if (inFbxNode.GetNodeAttribute() != nullptr) {
return inFbxNode.GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eMesh
- && inFbxNode.GetMesh() && inFbxNode.GetMesh()->GetControlPointsCount() != 0;
+ && inFbxNode.GetMesh() && inFbxNode.GetMesh()->GetControlPointsCount() != 0;
}
return false;
}
};
+struct SLightCameraFilter
+{
+ // filter out valid lights and cameras.
+ bool operator()(FbxNode &inFbxNode) const
+ {
+ if (inFbxNode.GetNodeAttribute() != nullptr) {
+ return (inFbxNode.GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eLight
+ && inFbxNode.GetLight())
+ || (inFbxNode.GetNodeAttribute()->GetAttributeType()
+ == FbxNodeAttribute::eCamera && inFbxNode.GetCamera());
+ }
+
+ return false;
+ }
+};
struct SNodeSetFilter
{
const TNodeSet &m_NodeSet;
@@ -337,7 +358,7 @@ struct SNodeSetFilter
*/
void FbxDomWalker::ProcessScene()
{
- if (m_FbxScene != NULL) {
+ if (m_FbxScene != nullptr) {
// FbxAxisSystem::MayaYUp.ConvertScene( m_FbxScene );
int sign;
FbxAxisSystem SceneAxisSystem = m_FbxScene->GetGlobalSettings().GetAxisSystem();
@@ -362,8 +383,9 @@ void FbxDomWalker::ProcessScene()
QT3DS_ASSERT(false);
}
- m_meshNodes.clear();
- FilterNodeHierarchy(SMeshFilter(), m_meshNodes);
+ m_importNodes.clear();
+ FilterNodeHierarchy(SMeshFilter(), m_importNodes);
+ FilterNodeHierarchy(SLightCameraFilter(), m_importNodes);
ProcessNode(m_FbxScene->GetRootNode());
}
}
@@ -426,7 +448,7 @@ int FbxDomWalker::GetParentJointID(const FbxNode *inFbxNode)
void FbxDomWalker::ProcessNodeChildren(FbxNode *inFbxNode)
{
for (int i = 0; i < inFbxNode->GetChildCount(); ++i) {
- if (m_meshNodes.find(inFbxNode) != m_meshNodes.end())
+ if (m_importNodes.find(inFbxNode) != m_importNodes.end())
ProcessNode(inFbxNode->GetChild(i));
}
}
@@ -449,6 +471,49 @@ void FbxDomWalker::ProcessGroup(FbxNode *inFbxNode)
}
/**
+* @brief Process a light
+*
+* @param[in] inFbxNode Pointer to node element
+*
+* @return no return
+*/
+void FbxDomWalker::ProcessLight(FbxNode *inFbxNode)
+{
+ std::string lightName = inFbxNode->GetName();
+ m_Translator->PushLight(lightName.c_str());
+ ProcessTransform(inFbxNode, true);
+ FbxLight *light = inFbxNode->GetLight();
+ FbxDouble3 color = light->Color.Get();
+ m_Translator->SetLightProperties(light->LightType.Get(), SFloat3(color[0], color[1], color[2]),
+ light->Intensity.Get(), 0, 0, light->CastShadows.Get());
+ ProcessNodeChildren(inFbxNode);
+ m_Translator->PopLight();
+}
+
+/**
+* @brief Process a camera
+*
+* @param[in] inFbxNode Pointer to node element
+*
+* @return no return
+*/
+void FbxDomWalker::ProcessCamera(FbxNode *inFbxNode)
+{
+ std::string cameraName = inFbxNode->GetName();
+ m_Translator->PushCamera(cameraName.c_str());
+ ProcessTransform(inFbxNode, true);
+ FbxCamera *camera = inFbxNode->GetCamera();
+ // Maya does not export FOV, but focal length. We need to convert it to FOV.
+ FbxDouble fov = (m_AuthoringToolType == EAuthoringToolType_FBX_Maya)
+ ? camera->ComputeFieldOfView(camera->FocalLength.Get()) : camera->FieldOfView.Get();
+ m_Translator->SetCameraProperties(camera->GetNearPlane(), camera->GetFarPlane(),
+ camera->ProjectionType.Get() == FbxCamera::eOrthogonal,
+ fov);
+ ProcessNodeChildren(inFbxNode);
+ m_Translator->PopCamera();
+}
+
+/**
* @brief Process a skeleton node and the children
*
* @param[in] inFbxNode Pointer to node element
@@ -461,7 +526,7 @@ long FbxDomWalker::ProcessSkeletonNode(FbxNode *inFbxNode, TNodeSet &inNodeSet,
{
bool pushGroup = false;
long groupId = -1;
- if (inFbxNode->GetNodeAttribute() != NULL) {
+ if (inFbxNode->GetNodeAttribute() != nullptr) {
std::string groupName = "Skeleton_";
groupName += inFbxNode->GetName();
m_Translator->PushGroup(groupName.c_str());
@@ -501,28 +566,39 @@ long FbxDomWalker::ProcessSkeletonNode(FbxNode *inFbxNode, TNodeSet &inNodeSet,
*/
void FbxDomWalker::ProcessNode(FbxNode *inFbxNode)
{
- if (inFbxNode->GetNodeAttribute() != NULL && m_meshNodes.find(inFbxNode) != m_meshNodes.end()) {
-
+ if (inFbxNode->GetNodeAttribute() != nullptr && m_importNodes.find(inFbxNode)
+ != m_importNodes.end()) {
FbxNodeAttribute::EType theAttribType = inFbxNode->GetNodeAttribute()->GetAttributeType();
switch (theAttribType) {
case FbxNodeAttribute::eMesh: {
FbxMesh *theFbxMesh = inFbxNode->GetMesh();
- if (theFbxMesh == NULL || theFbxMesh->GetControlPointsCount() == 0) {
+ if (theFbxMesh == nullptr || theFbxMesh->GetControlPointsCount() == 0)
ProcessGroup(inFbxNode);
- } else {
+ else
ProcessMesh(inFbxNode);
- }
- } break;
- // Ignore skeleton for now; we add them as the first child of the model with a special
- // flag indicating they ignore parent transforms.
- case FbxNodeAttribute::eSkeleton:
break;
- default:
+ }
+ case FbxNodeAttribute::eLight: {
+ ProcessLight(inFbxNode);
+ break;
+ }
+ case FbxNodeAttribute::eCamera: {
+ ProcessCamera(inFbxNode);
+ break;
+ }
+ case FbxNodeAttribute::eSkeleton: {
+ // Ignore skeleton for now; we add them as the first child of the model with a special
+ // flag indicating they ignore parent transforms.
+ break;
+ }
+ default: {
ProcessGroup(inFbxNode);
break;
}
- } else
+ }
+ } else {
ProcessNodeChildren(inFbxNode);
+ }
}
/**
@@ -550,7 +626,7 @@ FbxAMatrix getGeometricTransform(const FbxNode *pNode)
*
* @returna no return
*/
-void FbxDomWalker::ProcessTransform(FbxNode *inFbxNode)
+void FbxDomWalker::ProcessTransform(FbxNode *inFbxNode, bool ignoreScale)
{
std::vector<INodeTransform *> theTransforms;
@@ -564,6 +640,11 @@ void FbxDomWalker::ProcessTransform(FbxNode *inFbxNode)
theTransformMatrix = inFbxNode->EvaluateLocalTransform();
+ // Lights and cameras should ignore scale
+ if (ignoreScale)
+ theTransformMatrix.SetS(FbxVector4(1.0, 1.0, 1.0, 1.0));
+ // TODO: Do some rotation magic if m_AuthoringToolType == Blender?
+
theTransforms.push_back(new NodeTransform(ETransformType_Matrix4x4));
ReadFMatrix4(theTransformMatrix, *theTransforms.back());
@@ -1134,7 +1215,7 @@ long RetrieveFaceIndex(FbxDomWalker::TFaceIndicies &ioFaceIndicies,
void FbxDomWalker::ProcessMesh(FbxNode *inFbxNode)
{
FbxMesh *theFbxMesh = inFbxNode->GetMesh();
- if (theFbxMesh == NULL) {
+ if (theFbxMesh == nullptr) {
QT3DS_ASSERT(false);
return;
}
@@ -1950,7 +2031,7 @@ void FbxDomWalker::QueryMaterialInfo(FbxMesh *fbxMesh, SFaceMaterialInfo *info)
{
for (int l = 0; l < fbxMesh->GetElementMaterialCount(); l++) {
FbxGeometryElementMaterial *theMaterialElement = fbxMesh->GetElementMaterial(l);
- FbxSurfaceMaterial *theMaterial = NULL;
+ FbxSurfaceMaterial *theMaterial = nullptr;
int theMatId = -1;
theMaterial = fbxMesh->GetNode()->GetMaterial(
theMaterialElement->GetIndexArray().GetAt(info->m_StartFace));
@@ -1983,14 +2064,14 @@ void FbxDomWalker::ReadMaterial(const FbxSurfaceMaterial *inMaterial, const int
return;
QT3DS_ASSERT(inMaterial->GetClassId().Is(FbxSurfaceMaterial::ClassId)
- || inMaterial->GetClassId().Is(FbxSurfacePhong::ClassId)
- || inMaterial->GetClassId().Is(FbxSurfaceLambert::ClassId));
+ || inMaterial->GetClassId().Is(FbxSurfacePhong::ClassId)
+ || inMaterial->GetClassId().Is(FbxSurfaceLambert::ClassId));
// init some base values
theNewMaterial.m_Ambient.SetColor(0, 0, 0, 1);
theNewMaterial.m_Diffuse.SetColor(1, 1, 1, 1);
- if (inMaterial->GetClassId().Is(FbxSurfacePhong::ClassId)) {
+ if (inMaterial->GetClassId().Is(FbxSurfaceLambert::ClassId)) {
// lambert is base for all materials
// for phong we override the type and read the additional values later below
FbxSurfaceLambert *lambertMaterial = (FbxSurfaceLambert *)inMaterial;
@@ -1999,21 +2080,21 @@ void FbxDomWalker::ReadMaterial(const FbxSurfaceMaterial *inMaterial, const int
fbxColor = lambertMaterial->Ambient;
attenuationFactor = (float)lambertMaterial->AmbientFactor;
theNewMaterial.m_Ambient.SetColor((float)fbxColor.mData[0] * attenuationFactor,
- (float)fbxColor.mData[1] * attenuationFactor,
- (float)fbxColor.mData[2] * attenuationFactor, 1);
+ (float)fbxColor.mData[1] * attenuationFactor,
+ (float)fbxColor.mData[2] * attenuationFactor, 1);
fbxColor = lambertMaterial->Diffuse;
attenuationFactor = (float)lambertMaterial->DiffuseFactor;
theNewMaterial.m_Diffuse.SetColor((float)fbxColor.mData[0] * attenuationFactor,
- (float)fbxColor.mData[1] * attenuationFactor,
- (float)fbxColor.mData[2] * attenuationFactor, 1);
+ (float)fbxColor.mData[1] * attenuationFactor,
+ (float)fbxColor.mData[2] * attenuationFactor, 1);
fbxColor = lambertMaterial->Emissive;
attenuationFactor = (float)lambertMaterial->EmissiveFactor;
theNewMaterial.m_Emission.SetColor((float)fbxColor.mData[0] * attenuationFactor,
- (float)fbxColor.mData[1] * attenuationFactor,
- (float)fbxColor.mData[2] * attenuationFactor, 1);
+ (float)fbxColor.mData[1] * attenuationFactor,
+ (float)fbxColor.mData[2] * attenuationFactor, 1);
fbxColor = lambertMaterial->TransparentColor;
theNewMaterial.m_Transparent.SetColor((float)fbxColor.mData[0], (float)fbxColor.mData[1],
- (float)fbxColor.mData[2], 1);
+ (float)fbxColor.mData[2], 1);
theNewMaterial.m_Transparency.SetValue((float)lambertMaterial->TransparencyFactor);
}
@@ -2024,11 +2105,11 @@ void FbxDomWalker::ReadMaterial(const FbxSurfaceMaterial *inMaterial, const int
fbxColor = phongMaterial->Specular;
attenuationFactor = (float)phongMaterial->SpecularFactor;
theNewMaterial.m_Specular.SetColor((float)fbxColor.mData[0] * attenuationFactor,
- (float)fbxColor.mData[1] * attenuationFactor,
- (float)fbxColor.mData[2] * attenuationFactor, 1);
+ (float)fbxColor.mData[1] * attenuationFactor,
+ (float)fbxColor.mData[2] * attenuationFactor, 1);
fbxColor = phongMaterial->Reflection;
theNewMaterial.m_Reflective.SetColor((float)fbxColor.mData[0], (float)fbxColor.mData[1],
- (float)fbxColor.mData[2], 1);
+ (float)fbxColor.mData[2], 1);
theNewMaterial.m_Reflectivity.SetValue((float)phongMaterial->ReflectionFactor);
theNewMaterial.m_Shininess.SetValue((float)phongMaterial->Shininess);
}
@@ -2307,9 +2388,9 @@ void FbxDomWalker::ProcessAnimLayer(FbxNode *inNode, FbxAnimLayer *inAnimLayer)
FbxAnimCurveNode *theRotateCurveNode = inNode->LclRotation.GetCurveNode(inAnimLayer);
FbxAnimCurveNode *theScaleCurveNode = inNode->LclScaling.GetCurveNode(inAnimLayer);
// color animation
- FbxAnimCurve *redAnimCurve = NULL;
- FbxAnimCurve *greenAnimCurve = NULL;
- FbxAnimCurve *blueAnimCurve = NULL;
+ FbxAnimCurve *redAnimCurve = nullptr;
+ FbxAnimCurve *greenAnimCurve = nullptr;
+ FbxAnimCurve *blueAnimCurve = nullptr;
FbxNodeAttribute *nodeAttribute = inNode->GetNodeAttribute();
if (nodeAttribute) {
@@ -2417,7 +2498,7 @@ void FbxDomWalker::ProcessAnimLayer(FbxNode *inNode, FbxAnimLayer *inAnimLayer)
*/
void FbxDomWalker::ProcessAnimationStacks()
{
- if (m_FbxScene != NULL) {
+ if (m_FbxScene != nullptr) {
// get animation stack count
int numAnimStacks = m_FbxScene->GetSrcObjectCount<FbxAnimStack>();
diff --git a/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportSceneGraphTranslation.cpp b/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportSceneGraphTranslation.cpp
index 11eab904..a29c2353 100644
--- a/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportSceneGraphTranslation.cpp
+++ b/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportSceneGraphTranslation.cpp
@@ -478,9 +478,60 @@ public:
{
return ((inAuthoringToolType == EAuthoringToolType_FBX_Max)
|| (inAuthoringToolType == EAuthoringToolType_FBX_Modo)
- || (inAuthoringToolType == EAuthoringToolType_FBX_Maya));
+ || (inAuthoringToolType == EAuthoringToolType_FBX_Maya)
+ || (inAuthoringToolType == EAuthoringToolType_FBX_Blender));
}
+ void PushLight(const char *inName) override { PushObject(inName, ComposerObjectTypes::Light); }
+ void SetLightProperties(int type, const SFloat3 &color, double intensity, double linearfade,
+ double quadfade, bool shadows) override
+ {
+ Q_UNUSED(linearfade)
+ Q_UNUSED(quadfade)
+ TIMPHandle light = m_InstanceStack.back();
+ switch (type) {
+ case 0:
+ m_Import.SetInstancePropertyValue(light, m_Light.m_LightType, QStringLiteral("Point"));
+ break;
+ case 1:
+ m_Import.SetInstancePropertyValue(light, m_Light.m_LightType,
+ QStringLiteral("Directional"));
+ break;
+ case 4:
+ m_Import.SetInstancePropertyValue(light, m_Light.m_LightType, QStringLiteral("Area"));
+ break;
+ default:
+ qWarning("Unsupported light type, converting to directional.");
+ m_Import.SetInstancePropertyValue(light, m_Light.m_LightType,
+ QStringLiteral("Directional"));
+ break;
+ }
+ m_Import.SetInstancePropertyValue(light, m_Light.m_LightColor, color);
+ m_Import.SetInstancePropertyValue(light, m_Light.m_Brightness, intensity);
+ // TODO: These do not seem to be incuded in FbxLight. Kept here in case Collada has support
+ // for them (QT3DS-2857)
+ //m_Import.SetInstancePropertyValue(light, m_Light.m_LinearFade, linearfade);
+ //m_Import.SetInstancePropertyValue(light, m_Light.m_ExpFade, quadfade);
+ m_Import.SetInstancePropertyValue(light, m_Light.m_CastShadow, shadows);
+ }
+ void PopLight() override { PopObject(); }
+
+ void PushCamera(const char *inName) override
+ {
+ PushObject(inName, ComposerObjectTypes::Camera);
+ }
+ void SetCameraProperties(double clipstart, double clipend, bool ortho, double fov) override
+ {
+ TIMPHandle camera = m_InstanceStack.back();
+ m_Import.SetInstancePropertyValue(camera, m_Camera.m_ClipNear, clipstart);
+ m_Import.SetInstancePropertyValue(camera, m_Camera.m_ClipFar, clipend);
+ m_Import.SetInstancePropertyValue(camera, m_Camera.m_Orthographic, ortho);
+ m_Import.SetInstancePropertyValue(camera, m_Camera.m_Fov, fov);
+ if (m_AuthoringToolType == EAuthoringToolType_FBX_Maya)
+ m_Import.SetInstancePropertyValue(camera, m_Camera.m_FovHorizontal, true);
+ }
+ void PopCamera() override { PopObject(); }
+
void PushGroup(const char *inName) override { PushObject(inName, ComposerObjectTypes::Group); }
void SetGroupSkeletonId(long inId) override
{
@@ -699,9 +750,8 @@ public:
// Opacity
float theTransparency = 1.0f;
if (inMaterialParameters.m_Transparency.m_Flag) {
- // This is true for MAX and MODO but not for MAYA
- if ((m_AuthoringToolType == EAuthoringToolType_FBX_Max)
- || (m_AuthoringToolType == EAuthoringToolType_FBX_Modo)) {
+ // This is true for MAX, Blender and MODO but not for MAYA
+ if (m_AuthoringToolType != EAuthoringToolType_FBX_Maya) {
// on FBX 0 is fully opaque and 1 is fully transparent
// we treat it vice versa
theTransparency = 1.0f - inMaterialParameters.m_Transparency.m_Value;
@@ -711,18 +761,21 @@ public:
}
float theTransparent = 1.0f;
float theOpacity = theTransparency * theTransparent;
- if (inMaterialParameters.m_TransparentOpaqueType.m_Flag
- && inMaterialParameters.m_Transparent.m_Type == SColorOrTexture::Color) {
- if (inMaterialParameters.m_TransparentOpaqueType.m_Value == EMatOpaqueType_A_ONE) {
- theTransparent = inMaterialParameters.m_Transparent.m_Color[3];
- theOpacity = theTransparency * theTransparent;
- } else // EMatOpaqueType_RGB_ZERO
- {
+ if (((inMaterialParameters.m_Transparency.m_Flag && theOpacity == 1.0f)
+ || inMaterialParameters.m_TransparentOpaqueType.m_Flag)
+ && inMaterialParameters.m_Transparent.m_Type == SColorOrTexture::Color) {
+ if (m_AuthoringToolType == EAuthoringToolType_FBX_Maya
+ || inMaterialParameters.m_TransparentOpaqueType.m_Value
+ != EMatOpaqueType_A_ONE) {
+ // EMatOpaqueType_RGB_ZERO or importing from Maya
theTransparent = (inMaterialParameters.m_Transparent.m_Color[0]
- + inMaterialParameters.m_Transparent.m_Color[1]
- + inMaterialParameters.m_Transparent.m_Color[2])
- / 3.0f;
+ + inMaterialParameters.m_Transparent.m_Color[1]
+ + inMaterialParameters.m_Transparent.m_Color[2])
+ / 3.0f;
theOpacity = 1.0f - (theTransparency * theTransparent);
+ } else {
+ theTransparent = inMaterialParameters.m_Transparent.m_Color[3];
+ theOpacity = theTransparency * theTransparent;
}
}
SetInstancePropertyValue(theMaterial, m_Material.m_Opacity, theOpacity * 100.0f);
diff --git a/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportSceneGraphTranslation.h b/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportSceneGraphTranslation.h
index eec9558c..4187f626 100644
--- a/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportSceneGraphTranslation.h
+++ b/src/Authoring/QT3DSIMP/Qt3DSImportSGTranslation/Qt3DSImportSceneGraphTranslation.h
@@ -340,6 +340,7 @@ typedef enum _EAuthoringToolType {
EAuthoringToolType_FBX_Max,
EAuthoringToolType_FBX_Modo,
EAuthoringToolType_FBX_Maya,
+ EAuthoringToolType_FBX_Blender
} EAuthoringToolType;
//==============================================================================
@@ -357,6 +358,13 @@ public:
virtual void SetAuthoringTool(EAuthoringToolType inAuthoringToolType,
long inAuthoringToolVersion) = 0;
+ virtual void PushLight(const char *inName) = 0;
+ virtual void SetLightProperties(int type, const SFloat3 &color, double intensity,
+ double linearfade, double quadfade, bool shadows) = 0;
+ virtual void PopLight() = 0;
+ virtual void PushCamera(const char *inName) = 0;
+ virtual void SetCameraProperties(double clipstart, double clipend, bool ortho, double fov) = 0;
+ virtual void PopCamera() = 0;
virtual void PushGroup(const char *inName) = 0;
virtual void SetGroupSkeletonId(long inId) = 0;
virtual void SetIgnoresParentTransform(bool inValue) = 0;
diff --git a/src/Authoring/Studio/Application/DataInputListDlg.cpp b/src/Authoring/Studio/Application/DataInputListDlg.cpp
index 02055157..4ba31ca9 100644
--- a/src/Authoring/Studio/Application/DataInputListDlg.cpp
+++ b/src/Authoring/Studio/Application/DataInputListDlg.cpp
@@ -319,7 +319,7 @@ void CDataInputListDlg::updateInfo()
= m_dataInputs[m_currentDataInputName]->externalPresBoundTypes.uniqueKeys();
for (auto &k : uniqueKeys) {
m_infoContents->appendRow(QList<QStandardItem *>(
- {new QStandardItem(QObject::tr("<subpresentation>")),
+ {new QStandardItem(QObject::tr("<another presentation>")),
new QStandardItem(k), new QStandardItem()}));
}
}
@@ -358,15 +358,29 @@ void CDataInputListDlg::keyPressEvent(QKeyEvent *event)
void CDataInputListDlg::accept()
{
- if (g_StudioApp.GetCore()->GetDoc()->IsTransactionOpened())
- g_StudioApp.GetCore()->GetDoc()->CloseTransaction();
-
m_actualDataInputs->clear();
const auto keys = m_dataInputs.keys();
for (auto name : keys)
m_actualDataInputs->insert(name, m_dataInputs.value(name));
+ // Only show automatic binding removal choice if user has deleted
+ // in-use datainput during this activation of the dialog, to avoid constant
+ // nagging at closing of this dialog in case we have invalid datainputs.
+ if (m_deletedDiInUse)
+ QTimer::singleShot(0, &g_StudioApp, &CStudioApp::checkDeletedDatainputs);
+
+ if (g_StudioApp.GetCore()->GetDoc()->IsTransactionOpened()) {
+ g_StudioApp.GetCore()->GetDoc()->CloseTransaction();
+ // If a datainput has been edited (and datainput controller names
+ // updated in element "controlledproperty" properties), we need to make all changes
+ // non-undoable. This is because datainput definitions in UIA file (and in global
+ // datainput map) are not participating in the command stack. Changes there cannot be
+ // reversed, leading to datainput map and element properties being out of sync after Undo.
+ if (m_diHasBeenEdited)
+ g_StudioApp.GetCore()->GetCmdStack()->RemoveLastUndo();
+ }
+
QDialog::accept();
}
@@ -412,34 +426,51 @@ void CDataInputListDlg::onAddDataInput()
void CDataInputListDlg::onRemoveDataInput()
{
- QString title(QObject::tr("Warning"));
- QString text(QObject::tr("This operation cannot be undone. Are you sure?"));
- auto ret = g_StudioApp.GetDialogs()->DisplayMessageBox(title, text,
- Qt3DSMessageBox::ICON_WARNING, true,
- this);
- if (ret != Qt3DSMessageBox::MSGBX_OK)
- return;
-
QVector<int> removedRows;
+ bool anyDiInUse = false;
+
if (m_ui->tableView->selectionModel()) {
const QModelIndexList indexes = m_ui->tableView->selectionModel()->selectedIndexes();
for (const auto &index : indexes) {
- if (!removedRows.contains(index.row()))
+ if (!removedRows.contains(index.row())) {
removedRows.append(index.row());
+ QString diName = m_tableContents
+ ->itemFromIndex(index)->data(Qt::EditRole).toString();
+ if (m_dataInputs[diName]->ctrldElems.size()
+ || m_dataInputs[diName]->externalPresBoundTypes.size() ) {
+ anyDiInUse = true;
+ }
+ }
}
+ }
+
- if (removedRows.size() > 0) {
- std::sort(removedRows.begin(), removedRows.end());
- for (int i = removedRows.size() - 1; i >= 0; --i)
- m_dataInputs.remove(
- m_tableContents->item(removedRows[i])->data(Qt::EditRole).toString());
+ QString title(QObject::tr("Warning"));
+ QString text;
- m_ui->tableView->clearSelection();
- m_currentDataInputIndex = -1;
+ if (anyDiInUse)
+ text.append(QObject::tr("One or more datainputs are currently in use. "));
+ text.append(QObject::tr("This operation cannot be undone.\n\nAre you sure?"));
- updateButtons();
- updateContents();
+ auto ret = g_StudioApp.GetDialogs()->DisplayMessageBox(title, text,
+ Qt3DSMessageBox::ICON_WARNING, true,
+ this);
+ if (ret != Qt3DSMessageBox::MSGBX_OK)
+ return;
+
+ m_deletedDiInUse = anyDiInUse;
+
+ if (removedRows.size() > 0) {
+ std::sort(removedRows.begin(), removedRows.end());
+ for (int i = removedRows.size() - 1; i >= 0; --i) {
+ m_dataInputs.remove(
+ m_tableContents->item(removedRows[i])->data(Qt::EditRole).toString());
}
+ m_ui->tableView->clearSelection();
+ m_currentDataInputIndex = -1;
+
+ updateButtons();
+ updateContents();
}
}
@@ -522,6 +553,7 @@ void CDataInputListDlg::onEditDataInput()
di->name, elementHandles);
m_dataInputs.remove(m_currentDataInputName);
m_currentDataInputName = di->name;
+ m_diHasBeenEdited = true;
}
// Insert replaces the previous key - value pair if existing.
m_dataInputs.insert(m_currentDataInputName, di);
diff --git a/src/Authoring/Studio/Application/DataInputListDlg.h b/src/Authoring/Studio/Application/DataInputListDlg.h
index f6dd0a65..ff59c5b4 100644
--- a/src/Authoring/Studio/Application/DataInputListDlg.h
+++ b/src/Authoring/Studio/Application/DataInputListDlg.h
@@ -110,6 +110,8 @@ private:
// -1 all types, 0... matches EDataType enum
int m_typeFilter = -1;
QString m_searchString;
+ bool m_deletedDiInUse = false;
+ bool m_diHasBeenEdited = false;
QAction *m_replaceSelectedAction;
QAction *m_replaceAllAction;
diff --git a/src/Authoring/Studio/Application/DataInputSelectView.cpp b/src/Authoring/Studio/Application/DataInputSelectView.cpp
index e64bfc04..5d37b0af 100644
--- a/src/Authoring/Studio/Application/DataInputSelectView.cpp
+++ b/src/Authoring/Studio/Application/DataInputSelectView.cpp
@@ -55,6 +55,10 @@ DataInputSelectView::DataInputSelectView(const QVector<EDataType> &acceptedTypes
QTimer::singleShot(0, this, &DataInputSelectView::initialize);
}
+DataInputSelectView::~DataInputSelectView()
+{
+}
+
void DataInputSelectView::setData(const QVector<QPair<QString, int>> &dataInputList,
const QString &currentController, int handle, int instance)
{
@@ -70,6 +74,7 @@ void DataInputSelectView::setMatchingTypes(const QVector<EDataType> &matchingTyp
m_matchingTypes = matchingTypes;
if (!m_matchingTypes.isEmpty())
m_defaultType = m_matchingTypes[0];
+ updateData();
}
void DataInputSelectView::updateData()
@@ -91,8 +96,9 @@ void DataInputSelectView::updateData()
for (auto &i : qAsConst(m_dataInputList)) {
bool isCurrentCtrlr = i.first == m_currController;
if (i.first.contains(m_searchString) || !m_searchString.size() || isCurrentCtrlr) {
- if (m_typeFilter == -1
- || (m_typeFilter == -2 && m_matchingTypes.contains((EDataType)i.second))
+ if (m_typeFilter == DataInputTypeFilter::AllTypes
+ || (m_typeFilter == DataInputTypeFilter::MatchingTypes
+ && m_matchingTypes.contains((EDataType)i.second))
|| m_typeFilter == (EDataType)i.second || isCurrentCtrlr) {
dataInputs.append({i.first, getDiTypeStr(i.second)});
if (isCurrentCtrlr) {
@@ -199,6 +205,7 @@ void DataInputSelectView::setTypeFilter(const int index)
{
m_typeFilter = index;
updateData();
+ Q_EMIT filterChanged();
}
void DataInputSelectView::focusOutEvent(QFocusEvent *event)
@@ -212,6 +219,13 @@ bool DataInputSelectView::toolTipsEnabled() const
return CStudioPreferences::ShouldShowTooltips();
}
+void DataInputSelectView::setCurrentController(const QString &currentController)
+{
+ m_currController = currentController;
+ // Need to update the entire data as being current controller affects if the item is visible
+ updateData();
+}
+
void DataInputSelectView::initialize()
{
CStudioPreferences::setQmlContextProperties(rootContext());
diff --git a/src/Authoring/Studio/Application/DataInputSelectView.h b/src/Authoring/Studio/Application/DataInputSelectView.h
index 165b4588..9dc3a4e5 100644
--- a/src/Authoring/Studio/Application/DataInputSelectView.h
+++ b/src/Authoring/Studio/Application/DataInputSelectView.h
@@ -35,13 +35,20 @@
class DataInputSelectModel;
+enum DataInputTypeFilter {
+ MatchingTypes = -2,
+ AllTypes = -1,
+};
+
class DataInputSelectView : public QQuickWidget
{
Q_OBJECT
Q_PROPERTY(int selected MEMBER m_selection NOTIFY selectedChanged)
+ Q_PROPERTY(int typeFilter MEMBER m_typeFilter NOTIFY filterChanged)
public:
explicit DataInputSelectView(const QVector<EDataType> &acceptedTypes,
QWidget *parent = nullptr);
+ ~DataInputSelectView();
void setData(const QVector<QPair<QString, int>> &dataInputList,
const QString &currentController,
int handle = 0, int instance = 0);
@@ -49,6 +56,8 @@ public:
QString getAddNewDataInputString() { return tr("[Add New Datainput]"); }
QString getNoneString() { return tr("[None]"); }
DataInputSelectModel *getModel() const { return m_model; }
+ int instance() const { return m_instance; }
+ int handle() const { return m_handle; }
Q_INVOKABLE void setSelection(int index);
Q_INVOKABLE int selection() const { return m_selection; }
@@ -56,9 +65,12 @@ public:
Q_INVOKABLE void setTypeFilter(const int index);
Q_INVOKABLE bool toolTipsEnabled() const;
+ void setCurrentController(const QString &currentController);
+
Q_SIGNALS:
void dataInputChanged(int handle, int instance, const QString &selected);
void selectedChanged();
+ void filterChanged();
protected:
void focusOutEvent(QFocusEvent *event) override;
@@ -77,8 +89,8 @@ private:
QString m_mostRecentlyAdded;
EDataType m_defaultType;
QVector<EDataType> m_matchingTypes;
- // -2 denotes allowed types, -1 all types, 0... matches EDataType enum
- int m_typeFilter = -2;
+ // 0... matches EDataType enum
+ int m_typeFilter = DataInputTypeFilter::MatchingTypes;
QVector<QPair<QString, int>> m_dataInputList;
QString m_searchString;
};
diff --git a/src/Authoring/Studio/Application/ProjectFile.cpp b/src/Authoring/Studio/Application/ProjectFile.cpp
index 5b28db30..a2792049 100644
--- a/src/Authoring/Studio/Application/ProjectFile.cpp
+++ b/src/Authoring/Studio/Application/ProjectFile.cpp
@@ -559,27 +559,58 @@ void ProjectFile::loadSubpresentationsAndDatainputs(
* Check that a given presentation's or Qml stream's id is unique
*
* @param id presentation's or Qml stream's Id
- * @param src source node to exclude from the check, if empty the current document node is used
+ * @param src source node to exclude from the check. Defaults to empty.
*/
bool ProjectFile::isUniquePresentationId(const QString &id, const QString &src) const
{
if (!m_fileInfo.exists())
return true;
- QString theSrc = src.isEmpty() ? g_StudioApp.GetCore()->GetDoc()->getRelativePath() : src;
- bool isCurrDoc = theSrc == g_StudioApp.GetCore()->GetDoc()->getRelativePath();
+ bool isCurrDoc = src == g_StudioApp.GetCore()->GetDoc()->getRelativePath();
if (!isCurrDoc && id == g_StudioApp.GetCore()->GetDoc()->getPresentationId())
return false;
auto *sp = std::find_if(g_StudioApp.m_subpresentations.begin(),
g_StudioApp.m_subpresentations.end(),
- [&id, &theSrc](const SubPresentationRecord &spr) -> bool {
- return spr.m_id == id && spr.m_argsOrSrc != theSrc;
+ [&id, &src](const SubPresentationRecord &spr) -> bool {
+ return spr.m_id == id && spr.m_argsOrSrc != src;
});
return sp == g_StudioApp.m_subpresentations.end();
}
+// Returns unique presentation name based on given relative presentation path
+// Only the file name base is returned, no path or suffix.
+QString ProjectFile::getUniquePresentationName(const QString &presSrc) const
+{
+ if (!m_fileInfo.exists())
+ return {};
+
+ const QString fullPresSrc = getAbsoluteFilePathTo(presSrc);
+ QFileInfo fi(fullPresSrc);
+ const QStringList files = fi.dir().entryList(QDir::Files);
+ QString checkName = fi.fileName();
+ if (files.contains(checkName)) {
+ const QString nameTemplate = QStringLiteral("%1%2.%3");
+ const QString suffix = fi.suffix();
+ QString base = fi.completeBaseName();
+ int counter = 0;
+ int checkIndex = base.size();
+ while (checkIndex > 1 && base.at(checkIndex - 1).isDigit())
+ --checkIndex;
+ if (checkIndex < base.size())
+ counter = base.mid(checkIndex).toInt();
+
+ if (counter > 0)
+ base = base.left(checkIndex);
+
+ while (files.contains(checkName))
+ checkName = nameTemplate.arg(base).arg(++counter).arg(suffix);
+ }
+
+ return QFileInfo(checkName).completeBaseName();
+}
+
QString ProjectFile::ensureUniquePresentationId(const QString &id) const
{
if (!m_fileInfo.exists())
@@ -851,6 +882,19 @@ void ProjectFile::renameMaterial(const QString &oldName, const QString &newName)
Q_EMIT assetNameChanged();
}
+// Copies oldPres presentation as newPres. The id for newPres will be autogenerated.
+bool ProjectFile::duplicatePresentation(const QString &oldPres, const QString &newPres)
+{
+ const QString fullOldPath = getAbsoluteFilePathTo(oldPres);
+ const QString fullNewPath = getAbsoluteFilePathTo(newPres);
+ const bool success = QFile::copy(fullOldPath, fullNewPath);
+
+ if (success)
+ addPresentationNode(fullNewPath, {});
+
+ return success;
+}
+
/**
* Returns an absolute file path for a given relative file path.
*
diff --git a/src/Authoring/Studio/Application/ProjectFile.h b/src/Authoring/Studio/Application/ProjectFile.h
index 0ea0244e..3e47da28 100644
--- a/src/Authoring/Studio/Application/ProjectFile.h
+++ b/src/Authoring/Studio/Application/ProjectFile.h
@@ -61,6 +61,7 @@ public:
void addPresentationNode(const QString &uip, const QString &pId = {});
void addPresentationNodes(const QHash<QString, QString> &nodeList);
bool isUniquePresentationId(const QString &id, const QString &src = {}) const;
+ QString getUniquePresentationName(const QString &presSrc) const;
QString getProjectPath() const;
QString getProjectFilePath() const;
QString getProjectName() const;
@@ -79,6 +80,7 @@ public:
bool renamePresentationFile(const QString &oldName, const QString &newName);
void deletePresentationFile(const QString &filePath);
void renameMaterial(const QString &oldName, const QString &newName);
+ bool duplicatePresentation(const QString &oldPres, const QString &newPres);
Q_SIGNALS:
void presentationIdChanged(const QString &path, const QString &id);
diff --git a/src/Authoring/Studio/Application/StudioApp.cpp b/src/Authoring/Studio/Application/StudioApp.cpp
index 15ceb814..d6e589a4 100644
--- a/src/Authoring/Studio/Application/StudioApp.cpp
+++ b/src/Authoring/Studio/Application/StudioApp.cpp
@@ -40,6 +40,7 @@
#include "SlideView.h"
#include "IKeyframesManager.h"
#include "PresentationFile.h"
+#include "EditPresentationIdDlg.h"
#include <QtGui/qsurfaceformat.h>
#include <QtCore/qfileinfo.h>
@@ -1207,6 +1208,10 @@ void CStudioApp::SetAutosetKeyframes(bool inFlag)
*/
void CStudioApp::PlaybackPlay()
{
+ // Do not start playback if user is currently interacting with scene
+ if (getRenderer().isMouseDown())
+ return;
+
CDoc *theDoc = m_core->GetDoc();
if (!theDoc->IsPlaying()) {
m_playbackTime = theDoc->GetCurrentViewTime();
@@ -1546,7 +1551,6 @@ bool CStudioApp::isPlaybackPreviewOn() const
return m_playbackPreviewOn;
}
-//=============================================================================
/**
* Handles the Save command
* This will save the file, if the file has not been saved before this will
@@ -1558,10 +1562,7 @@ bool CStudioApp::OnSave(bool autosave)
{
Qt3DSFile theCurrentDoc = m_core->GetDoc()->GetDocumentPath();
if (!theCurrentDoc.IsFile()) {
- if (autosave)
- return false;
- else
- return OnSaveAs();
+ return false;
} else if (!theCurrentDoc.CanWrite()) {
m_dialogs->DisplaySavingPresentationFailed();
return false;
@@ -1585,36 +1586,43 @@ bool CStudioApp::OnSave(bool autosave)
}
/**
- * Command handler for the File Save As menu option.
- * This will prompt the user for a location to save the file out to then
- * will perform the save.
- * @return true if the file was successfully saved.
+ * This will prompt the user for a location and name to save a copy of the project folder.
+ * Saving under the current project is not possible.
*/
-bool CStudioApp::OnSaveAs()
+void CStudioApp::onProjectSaveAs()
{
- QString theFile = m_dialogs->GetSaveAsChoice();
- if (!theFile.isEmpty()) {
- m_core->OnSaveDocument(theFile);
- return true;
- }
- return false;
-}
-
-/**
- * Command handler for the File Save Copy menu option.
- * This will prompt the user for a location to save the file out to then
- * save a copy, leaving the original file open in the editor.
- * @return true if the file was successfully saved.
- */
-bool CStudioApp::OnSaveCopy()
-{
- QString theFile = m_dialogs->GetSaveAsChoice();
- if (!theFile.isEmpty()) {
- // Send in a "true" to the save function to indicate this is a copy
- m_core->OnSaveDocument(theFile, true);
- return true;
+ if (PerformSavePrompt()) {
+ const QString newProj = m_dialogs->GetSaveAsChoice(QObject::tr("Save Project As"),
+ true, true);
+ if (!newProj.isEmpty()) {
+ // Copy the project
+ const QString currentProj = GetCore()->getProjectFile().getProjectPath();
+ if (CFilePath::copyFolder(currentProj, newProj)) {
+ // Prompt whether to open the new project
+ QMessageBox box(m_pMainWnd);
+ box.setWindowTitle(QObject::tr("Project copy saved successfully"));
+ box.setText(QObject::tr("Continue working with the original project?"));
+ box.setIcon(QMessageBox::Question);
+ box.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
+ box.setButtonText(QMessageBox::No, QObject::tr("No, open the one I just saved"));
+ box.setDefaultButton(QMessageBox::Yes);
+ int choice = box.exec();
+ if (choice == QMessageBox::No) {
+ const QString newProjDoc = newProj
+ + QDir::cleanPath(GetCore()->GetDoc()->GetDocumentPath()).mid(
+ currentProj.length());
+ QTimer::singleShot(0, [this, newProjDoc]() {
+ OnLoadDocument(newProjDoc);
+ });
+ }
+ } else {
+ const QString title(QObject::tr("Project save failed"));
+ const QString warning = QObject::tr("Failed to save the project as %1.")
+ .arg(newProj);
+ QMessageBox::warning(m_pMainWnd, title, warning);
+ }
+ }
}
- return false;
}
void CStudioApp::SetAutosaveEnabled(bool enabled)
@@ -2211,9 +2219,36 @@ void CStudioApp::verifyDatainputBindings()
}
}
-
bool CStudioApp::hasProfileUI()
{
static const bool profileui = qEnvironmentVariableIntValue("QT3DS_PROFILEUI") > 0;
return profileui;
}
+
+/**
+* This will prompt the user for a new name for the duplicated presentation and copy the current
+* presentation with that name in the same folder as the original. The new presentation is added
+* to the project and gets autogenerated id. The new presentation is made current.
+*/
+void CStudioApp::duplicatePresentation(const QString &presFile)
+{
+ QString thePresFile = presFile;
+ bool qmlStream = presFile.endsWith(QLatin1String(".qml"));
+ if (presFile.isEmpty())
+ thePresFile = GetCore()->GetDoc()->GetDocumentPath();
+
+ if (thePresFile != GetCore()->GetDoc()->GetDocumentPath() || PerformSavePrompt()) {
+ QFileInfo fi(thePresFile);
+ QString relativePresPath = QDir(GetCore()->getProjectFile().getProjectPath())
+ .relativeFilePath(fi.absoluteFilePath());
+
+ EditPresentationIdDlg dlg(relativePresPath,
+ qmlStream ? EditPresentationIdDlg::DuplicateQmlStream
+ : EditPresentationIdDlg::DuplicatePresentation,
+ m_pMainWnd);
+ dlg.exec();
+ const QString newPres = dlg.getDuplicateFile();
+ if (!newPres.isEmpty())
+ OnLoadDocument(newPres);
+ }
+}
diff --git a/src/Authoring/Studio/Application/StudioApp.h b/src/Authoring/Studio/Application/StudioApp.h
index 3405e997..6ddf95e0 100644
--- a/src/Authoring/Studio/Application/StudioApp.h
+++ b/src/Authoring/Studio/Application/StudioApp.h
@@ -201,8 +201,7 @@ public:
CInspectableBase *getInspectableFromInstance(qt3dsdm::Qt3DSDMInstanceHandle inInstance);
void RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler, QWidget *actionParent);
bool OnSave(bool autosave = false);
- bool OnSaveAs();
- bool OnSaveCopy();
+ void onProjectSaveAs();
bool OnLoadDocument(const QString &inDocument, bool inShowStartupDialogOnError = true);
void OnLoadDocumentCatcher(const QString &inLocation);
void OnFileOpen();
@@ -222,6 +221,7 @@ public:
void checkDeletedDatainputs();
void saveDataInputsToProjectFile();
void verifyDatainputBindings();
+ void duplicatePresentation(const QString &presFile = {});
// CCoreAsynchronousEventListener
void OnAsynchronousCommand(CCmd *inCmd) override;
diff --git a/src/Authoring/Studio/MainFrm.cpp b/src/Authoring/Studio/MainFrm.cpp
index b8edfbaf..fe0b2137 100644
--- a/src/Authoring/Studio/MainFrm.cpp
+++ b/src/Authoring/Studio/MainFrm.cpp
@@ -105,8 +105,9 @@ CMainFrame::CMainFrame()
connect(m_ui->action_New_Presentation, &QAction::triggered, this, &CMainFrame::OnFileNew);
connect(m_ui->action_Open, &QAction::triggered, this, &CMainFrame::OnFileOpen);
connect(m_ui->action_Save, &QAction::triggered, this, &CMainFrame::OnFileSave);
- connect(m_ui->actionSave_As, &QAction::triggered, this, &CMainFrame::OnFileSaveAs);
- connect(m_ui->actionSave_a_Copy, &QAction::triggered, this, &CMainFrame::OnFileSaveCopy);
+ connect(m_ui->action_Save_Project_As, &QAction::triggered, this, &CMainFrame::onProjectSaveAs);
+ connect(m_ui->action_Duplicate_Presentation, &QAction::triggered,
+ this, &CMainFrame::onDuplicatePresentation);
connect(m_ui->action_Revert, &QAction::triggered, this, &CMainFrame::OnFileRevert);
connect(m_ui->actionImportAssets, &QAction::triggered, this, &CMainFrame::OnFileImportAssets);
connect(m_ui->actionData_Inputs, &QAction::triggered, this, &CMainFrame::OnFileDataInputs);
@@ -135,22 +136,26 @@ CMainFrame::CMainFrame()
connect(m_ui->actionPresentation_Settings, &QAction::triggered,
this, &CMainFrame::OnEditPresentationPreferences);
connect(m_ui->menu_Edit, &QMenu::aboutToShow, [this]() {
- QString type = g_StudioApp.getDuplicateType();
- QString label = tr("Duplicate %1").arg(type);
- m_ui->action_Duplicate_Object->setText(label);
- m_ui->action_Duplicate_Object->setEnabled(!type.isEmpty());
-
- type = g_StudioApp.getDeleteType();
- label = tr("Delete %1").arg(type);
- m_ui->actionDelete->setText(label);
- m_ui->actionDelete->setEnabled(!type.isEmpty());
-
- if (g_StudioApp.canUngroupSelectedObjects()) {
- m_ui->actionGroup->setText(tr("Ungroup Objects"));
- m_ui->actionGroup->setEnabled(true);
- } else {
- m_ui->actionGroup->setText(tr("Group Objects"));
- m_ui->actionGroup->setEnabled(g_StudioApp.canGroupSelectedObjects());
+ // macOS doesn't block menubar while startup dialog is being shown, and that causes a
+ // crash on aboutToShow if it's called before everything is set
+ if (m_ui->menu_Edit->isEnabled()) {
+ QString type = g_StudioApp.getDuplicateType();
+ QString label = tr("Duplicate %1").arg(type);
+ m_ui->action_Duplicate_Object->setText(label);
+ m_ui->action_Duplicate_Object->setEnabled(!type.isEmpty());
+
+ type = g_StudioApp.getDeleteType();
+ label = tr("Delete %1").arg(type);
+ m_ui->actionDelete->setText(label);
+ m_ui->actionDelete->setEnabled(!type.isEmpty());
+
+ if (g_StudioApp.canUngroupSelectedObjects()) {
+ m_ui->actionGroup->setText(tr("Ungroup Objects"));
+ m_ui->actionGroup->setEnabled(true);
+ } else {
+ m_ui->actionGroup->setText(tr("Group Objects"));
+ m_ui->actionGroup->setEnabled(g_StudioApp.canGroupSelectedObjects());
+ }
}
});
connect(m_ui->menu_Edit, &QMenu::aboutToHide, [this]() {
@@ -379,8 +384,8 @@ void CMainFrame::OnCreate()
m_ui->menu_Edit->setEnabled(false);
m_ui->menu_Timeline->setEnabled(false);
m_ui->menu_View->setEnabled(false);
- m_ui->actionSave_As->setEnabled(false);
- m_ui->actionSave_a_Copy->setEnabled(false);
+ m_ui->action_Save_Project_As->setEnabled(false);
+ m_ui->action_Duplicate_Presentation->setEnabled(false);
m_ui->action_Connect_to_Device->setEnabled(false);
m_ui->action_Revert->setEnabled(false);
m_ui->actionImportAssets->setEnabled(false);
@@ -394,10 +399,6 @@ void CMainFrame::OnCreate()
m_ui->actionZoom_Tool->setVisible(false);
#endif
- // TODO: Save as/save copy functionality hidden until it is redesigned (QT3DS-2630)
- m_ui->actionSave_As->setVisible(false);
- m_ui->actionSave_a_Copy->setVisible(false);
-
// Show a message about opening or creating a presentation
m_sceneView.data()->setVisible(false);
setCentralWidget(m_ui->infoText);
@@ -424,9 +425,8 @@ void CMainFrame::OnNewPresentation()
m_ui->menu_Edit->setEnabled(true);
m_ui->menu_Timeline->setEnabled(true);
m_ui->menu_View->setEnabled(true);
- // TODO: Save as/save copy functionality disabled until it is redesigned (QT3DS-2630)
-// m_ui->actionSave_As->setEnabled(true);
-// m_ui->actionSave_a_Copy->setEnabled(true);
+ m_ui->action_Save_Project_As->setEnabled(true);
+ m_ui->action_Duplicate_Presentation->setEnabled(true);
m_ui->action_Connect_to_Device->setEnabled(true);
m_ui->action_Revert->setEnabled(true);
m_ui->actionImportAssets->setEnabled(true);
@@ -754,29 +754,23 @@ void CMainFrame::OnUpdateFileSave()
{
m_ui->action_Save->setEnabled(g_StudioApp.GetCore()->GetDoc()->IsModified());
}
-//=============================================================================
+
/**
- * Command handler for the File Save As menu option.
- * This will prompt the user for a location to save the file out to then
- * will perform the save.
+ * Command handler for the File Save Project As menu option.
*/
-void CMainFrame::OnFileSaveAs()
+void CMainFrame::onProjectSaveAs()
{
- g_StudioApp.OnSaveAs();
+ g_StudioApp.onProjectSaveAs();
}
-//=============================================================================
/**
- * Command handler for the File Save a Copy menu option.
- * This will prompt the user for a location to save the file out to then
- * save a copy, leaving the original file open in the editor.
+ * Command handler for the File Duplicate Presentation menu option.
*/
-void CMainFrame::OnFileSaveCopy()
+void CMainFrame::onDuplicatePresentation()
{
- g_StudioApp.OnSaveCopy();
+ g_StudioApp.duplicatePresentation();
}
-//=============================================================================
/**
* Command handler for the New Project menu option.
* This will also create a new default presentation.
diff --git a/src/Authoring/Studio/MainFrm.h b/src/Authoring/Studio/MainFrm.h
index 50376a9e..9de55c84 100644
--- a/src/Authoring/Studio/MainFrm.h
+++ b/src/Authoring/Studio/MainFrm.h
@@ -107,8 +107,8 @@ public:
void OnFileOpen();
void OnFileSave();
void OnUpdateFileSave();
- void OnFileSaveAs();
- void OnFileSaveCopy();
+ void onProjectSaveAs();
+ void onDuplicatePresentation();
void OnProjectNew();
void OnFileNew();
void OnFileRevert();
diff --git a/src/Authoring/Studio/MainFrm.ui b/src/Authoring/Studio/MainFrm.ui
index 83893c89..7c15e262 100644
--- a/src/Authoring/Studio/MainFrm.ui
+++ b/src/Authoring/Studio/MainFrm.ui
@@ -45,7 +45,7 @@ Project palette using Import functionality.</string>
<x>0</x>
<y>0</y>
<width>1800</width>
- <height>17</height>
+ <height>21</height>
</rect>
</property>
<widget class="QMenu" name="menu_File">
@@ -66,16 +66,16 @@ Project palette using Import functionality.</string>
<addaction name="action_New_Presentation"/>
</widget>
<addaction name="menu_New"/>
+ <addaction name="action_Duplicate_Presentation"/>
<addaction name="action_Open"/>
- <addaction name="action_Save"/>
- <addaction name="actionSave_As"/>
- <addaction name="actionSave_a_Copy"/>
- <addaction name="action_Revert"/>
<addaction name="menuRecent_Projects"/>
+ <addaction name="action_Revert"/>
+ <addaction name="separator"/>
+ <addaction name="action_Save"/>
+ <addaction name="action_Save_Project_As"/>
<addaction name="separator"/>
<addaction name="actionImportAssets"/>
<addaction name="actionData_Inputs"/>
- <addaction name="action_Connect_to_Device"/>
<addaction name="separator"/>
<addaction name="action_Exit"/>
</widget>
@@ -97,6 +97,8 @@ Project palette using Import functionality.</string>
<addaction name="actionParent"/>
<addaction name="actionUnparent"/>
<addaction name="separator"/>
+ <addaction name="action_Connect_to_Device"/>
+ <addaction name="separator"/>
<addaction name="actionStudio_Preferences"/>
<addaction name="actionPresentation_Settings"/>
</widget>
@@ -292,6 +294,9 @@ Project palette using Import functionality.</string>
<property name="text">
<string>Delete Selected Keyframe(s)</string>
</property>
+ <property name="shortcut">
+ <string>Del</string>
+ </property>
</action>
<action name="actionSet_Interpolation">
<property name="text">
@@ -515,31 +520,28 @@ Project palette using Import functionality.</string>
</action>
<action name="action_Save">
<property name="text">
- <string>&amp;Save</string>
+ <string>&amp;Save Presentation</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
- <action name="actionSave_As">
+ <action name="action_Save_Project_As">
<property name="text">
- <string>Save &amp;As...</string>
+ <string>Save Project &amp;As...</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+S</string>
</property>
</action>
- <action name="actionSave_a_Copy">
+ <action name="action_Duplicate_Presentation">
<property name="text">
- <string>Save a Copy...</string>
- </property>
- <property name="shortcut">
- <string>Ctrl+Alt+S</string>
+ <string>Duplicate Presentation...</string>
</property>
</action>
<action name="action_Revert">
<property name="text">
- <string>&amp;Revert</string>
+ <string>&amp;Revert to Last Save</string>
</property>
</action>
<action name="action_Connect_to_Device">
@@ -822,13 +824,13 @@ Project palette using Import functionality.</string>
</action>
<action name="actionImportAssets">
<property name="text">
- <string>Import Assets...</string>
+ <string>Import...</string>
</property>
<property name="iconText">
- <string>Import Assets</string>
+ <string>Import Assets or Presentations</string>
</property>
<property name="toolTip">
- <string>Import Assets</string>
+ <string>Import Assets or Presentations</string>
</property>
</action>
<action name="actionData_Inputs">
diff --git a/src/Authoring/Studio/Palettes/Action/ActionView.cpp b/src/Authoring/Studio/Palettes/Action/ActionView.cpp
index 54aad9c4..9c62b392 100644
--- a/src/Authoring/Studio/Palettes/Action/ActionView.cpp
+++ b/src/Authoring/Studio/Palettes/Action/ActionView.cpp
@@ -130,7 +130,6 @@ ActionView::ActionView(const QSize &preferredSize, QWidget *parent)
ActionView::~ActionView()
{
- m_connections.clear();
}
QSize ActionView::sizeHint() const
@@ -186,6 +185,11 @@ bool ActionView::event(QEvent *event)
void ActionView::setItem(const qt3dsdm::Qt3DSDMInstanceHandle &handle)
{
+ if (!m_activeBrowser.isNull() && m_activeBrowser->isVisible()) {
+ m_activeBrowser->close();
+ m_activeBrowser.clear();
+ }
+
m_objRefHelper = GetDoc()->GetDataModelObjectReferenceHelper();
m_itemHandle = handle;
m_actionsModel->setInstanceHandle(handle);
@@ -425,6 +429,7 @@ QObject *ActionView::showTriggerObjectBrowser(const QPoint &point)
m_triggerObjectBrowser->disconnect();
m_triggerObjectBrowser->selectAndExpand(instanceHandle, actionInfo.m_Owner);
CDialogs::showWidgetBrowser(this, m_triggerObjectBrowser, point);
+ m_activeBrowser = m_triggerObjectBrowser;
connect(m_triggerObjectBrowser, &ObjectBrowserView::selectionChanged,
this, &ActionView::OnTriggerSelectionChanged);
@@ -456,6 +461,7 @@ QObject *ActionView::showTargetObjectBrowser(const QPoint &point)
m_targetObjectBrowser->disconnect();
m_targetObjectBrowser->selectAndExpand(instanceHandle, actionInfo.m_Owner);
CDialogs::showWidgetBrowser(this, m_targetObjectBrowser, point);
+ m_activeBrowser = m_targetObjectBrowser;
connect(m_targetObjectBrowser, &ObjectBrowserView::selectionChanged,
this, &ActionView::OnTargetSelectionChanged);
@@ -518,10 +524,12 @@ QObject *ActionView::showEventBrowser(const QPoint &point)
m_eventsBrowser->disconnect();
m_eventsBrowser->selectAndExpand(actionInfo.m_Event);
CDialogs::showWidgetBrowser(this, m_eventsBrowser, point);
+ m_activeBrowser = m_eventsBrowser;
connect(m_eventsBrowser, &EventsBrowserView::selectionChanged,
this, [this] {
- setEvent(qt3dsdm::Qt3DSDMEventHandle(m_eventsBrowser->selectedHandle()));
+ if (m_eventsBrowser->canCommit())
+ setEvent(qt3dsdm::Qt3DSDMEventHandle(m_eventsBrowser->selectedHandle()));
});
return m_eventsBrowser;
@@ -554,10 +562,12 @@ QObject *ActionView::showHandlerBrowser(const QPoint &point)
m_handlerBrowser->disconnect();
m_handlerBrowser->selectAndExpand(actionInfo.m_Handler);
CDialogs::showWidgetBrowser(this, m_handlerBrowser, point);
+ m_activeBrowser = m_handlerBrowser;
connect(m_handlerBrowser, &EventsBrowserView::selectionChanged,
this, [this] {
- setHandler(qt3dsdm::Qt3DSDMHandlerHandle(m_handlerBrowser->selectedHandle()));
+ if (m_handlerBrowser->canCommit())
+ setHandler(qt3dsdm::Qt3DSDMHandlerHandle(m_handlerBrowser->selectedHandle()));
});
return m_handlerBrowser;
@@ -586,6 +596,7 @@ QObject *ActionView::showEventBrowserForArgument(int handle, const QPoint &point
m_fireEventsBrowser = new EventsBrowserView(this);
m_fireEventsBrowser->setModel(m_fireEventsModel);
+ m_fireEventsBrowser->setHandle(handle);
qt3dsdm::SValue oldValue;
GetDoc()->GetStudioSystem()->GetActionCore()->GetHandlerArgumentValue(handle, oldValue);
@@ -602,6 +613,7 @@ QObject *ActionView::showEventBrowserForArgument(int handle, const QPoint &point
m_fireEventsBrowser->disconnect();
m_fireEventsBrowser->selectAndExpand(eventName);
CDialogs::showWidgetBrowser(this, m_fireEventsBrowser, point);
+ m_activeBrowser = m_fireEventsBrowser;
connect(m_fireEventsBrowser, &EventsBrowserView::selectionChanged,
this, [this, handle] {
@@ -699,6 +711,17 @@ void ActionView::OnNewPresentation()
m_connections.push_back(theDispatch->ConnectSelectionChange(
std::bind(&ActionView::OnSelectionSet, this,
std::placeholders::_1)));
+
+ auto assetGraph = g_StudioApp.GetCore()->GetDoc()->GetAssetGraph();
+ m_connections.push_back(assetGraph->ConnectChildAdded(
+ std::bind(&ActionView::onAssetGraphChanged, this)));
+ m_connections.push_back(assetGraph->ConnectChildRemoved(
+ std::bind(&ActionView::onAssetGraphChanged, this)));
+}
+
+void ActionView::OnClosingPresentation()
+{
+ m_connections.clear();
}
void ActionView::OnSelectionSet(Q3DStudio::SSelectedValue inSelectable)
@@ -728,8 +751,8 @@ void ActionView::OnSelectionSet(Q3DStudio::SSelectedValue inSelectable)
}
break;
default:
- // Do nothing on slide insertion, guide and unknown types
- return;
+ // Clear selection on selecting other types or nothing at all
+ break;
};
setItem(theInstance);
@@ -748,6 +771,11 @@ void ActionView::OnActionAdded(qt3dsdm::Qt3DSDMActionHandle inAction,
qt3dsdm::Qt3DSDMSlideHandle theMasterOfCurrentSlide =
theStudioSystem->GetSlideSystem()->GetMasterSlide(theCurrentSlide);
+ if (!m_activeBrowser.isNull() && m_activeBrowser->isVisible()) {
+ m_activeBrowser->close();
+ m_activeBrowser.clear();
+ }
+
if (inOwner == m_itemHandle // the action is added to current viewed instance
&& (theCurrentSlide == inSlide // and is added to the current viewed slide
|| (theMasterSlideOfAction == inSlide
@@ -764,6 +792,10 @@ void ActionView::OnActionDeleted(qt3dsdm::Qt3DSDMActionHandle inAction,
Q_UNUSED(inSlide);
Q_UNUSED(inOwner);
+ if (!m_activeBrowser.isNull() && m_activeBrowser->isVisible()) {
+ m_activeBrowser->close();
+ m_activeBrowser.clear();
+ }
m_actionsModel->removeAction(inAction);
}
@@ -773,6 +805,28 @@ void ActionView::OnActionModified(qt3dsdm::Qt3DSDMActionHandle inAction)
return;
if (GetDoc()->GetStudioSystem()->GetActionCore()->HandleValid(inAction)) {
+ if (!m_activeBrowser.isNull() && m_activeBrowser->isVisible()) {
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ if (!actionInfo.m_Instance.Valid()) {
+ m_activeBrowser->close();
+ m_activeBrowser.clear();
+ } else {
+ // Update the selection in an active browser dialog
+ if (m_activeBrowser == m_triggerObjectBrowser) {
+ const auto instanceHandle = GetBridge()->GetInstance(
+ actionInfo.m_Owner, actionInfo.m_TriggerObject);
+ m_triggerObjectBrowser->selectAndExpand(instanceHandle, actionInfo.m_Owner);
+ } else if (m_activeBrowser == m_targetObjectBrowser) {
+ const auto instanceHandle = GetBridge()->GetInstance(
+ actionInfo.m_Owner, actionInfo.m_TargetObject);
+ m_targetObjectBrowser->selectAndExpand(instanceHandle, actionInfo.m_Owner);
+ } else if (m_activeBrowser == m_eventsBrowser) {
+ m_eventsBrowser->selectAndExpand(actionInfo.m_Event);
+ } else if (m_activeBrowser == m_handlerBrowser) {
+ m_handlerBrowser->selectAndExpand(actionInfo.m_Handler);
+ }
+ }
+ }
m_actionsModel->updateAction(inAction);
emitActionChanged();
}
@@ -783,6 +837,37 @@ void ActionView::OnHandlerArgumentModified(qt3dsdm::Qt3DSDMHandlerArgHandle inHa
if (!m_itemHandle.Valid())
return;
+ if (!m_fireEventsBrowser.isNull() && m_activeBrowser == m_fireEventsBrowser
+ && m_activeBrowser->isVisible()) {
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+
+ // m_fireEventsBrowser needs to be closed if another type of target handler is chosen.
+ // Other browsers will remain valid always as long as the action is selected.
+ if (actionInfo.m_Handler != QStringLiteral("Fire Event")) {
+ m_activeBrowser->close();
+ m_activeBrowser.clear();
+ } else {
+ // Update the selection in an active browser dialog
+ const auto bridge = GetBridge();
+ const auto instanceHandle = bridge->GetInstance(actionInfo.m_Owner,
+ actionInfo.m_TargetObject);
+ qt3dsdm::TEventHandleList eventList;
+ bridge->GetEvents(instanceHandle, eventList);
+ qt3dsdm::SValue value;
+ GetDoc()->GetStudioSystem()->GetActionCore()->GetHandlerArgumentValue(
+ m_fireEventsBrowser->handle(), value);
+ QString eventName;
+ for (Qt3DSDMEventHandle eventHandle : eventList) {
+ if (value == eventHandle.GetHandleValue()) {
+ qt3dsdm::SEventInfo eventInfo = bridge->GetEventInfo(eventHandle);
+ eventName = eventInfo.m_FormalName;
+ if (eventName.isEmpty())
+ eventName = eventInfo.m_Name;
+ }
+ }
+ m_fireEventsBrowser->selectAndExpand(eventName);
+ }
+ }
emitActionChanged();
}
@@ -849,25 +934,27 @@ void ActionView::setTriggerObject(const qt3dsdm::SObjectRefType &object)
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);
-
- Qt3DSDMInstanceHandle theBaseInstance = theActionInfo.m_Owner;
- Qt3DSDMInstanceHandle theObjectInstance = theBridge->GetInstance(theBaseInstance, object);
- Qt3DSDMInstanceHandle theOldInstance = theBridge->GetInstance(theBaseInstance,
- theActionInfo.m_TargetObject);
- // old instance and object instance could be the same, for example if user changes the type
- // from Absolute to Path. In this case we don't need to reset handler or event.
- if (theOldInstance != theObjectInstance) {
- theCmd->ResetEvent(
- theBridge->GetDefaultEvent(theObjectInstance, theActionInfo.m_Event));
- }
+ if (!m_triggerObjectBrowser.isNull() && m_triggerObjectBrowser->canCommit()) {
+ auto core = g_StudioApp.GetCore();
+ auto theBridge = GetBridge();
+
+ auto theCmd = new CCmdDataModelActionSetTriggerObject(GetDoc(), action, object);
+ const SActionInfo &theActionInfo
+ = GetDoc()->GetStudioSystem()->GetActionCore()->GetActionInfo(action);
+
+ Qt3DSDMInstanceHandle theBaseInstance = theActionInfo.m_Owner;
+ Qt3DSDMInstanceHandle theObjectInstance = theBridge->GetInstance(theBaseInstance, object);
+ Qt3DSDMInstanceHandle theOldInstance = theBridge->GetInstance(theBaseInstance,
+ theActionInfo.m_TargetObject);
+ // old instance and object instance could be the same, for example if user changes the type
+ // from Absolute to Path. In this case we don't need to reset handler or event.
+ if (theOldInstance != theObjectInstance) {
+ theCmd->ResetEvent(
+ theBridge->GetDefaultEvent(theObjectInstance, theActionInfo.m_Event));
+ }
- core->ExecuteCommand(theCmd);
+ core->ExecuteCommand(theCmd);
+ }
emitActionChanged();
}
@@ -877,26 +964,28 @@ void ActionView::setTargetObject(const qt3dsdm::SObjectRefType &object)
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);
-
- Qt3DSDMInstanceHandle theBaseInstance = theActionInfo.m_Owner;
- Qt3DSDMInstanceHandle theObjectInstance = theBridge->GetInstance(theBaseInstance, object);
- Qt3DSDMInstanceHandle theOldInstance = theBridge->GetInstance(theBaseInstance,
- theActionInfo.m_TargetObject);
- // old instance and object instance could be the same, for example if user changes the type
- // from Absolute to Path. In this case we don't need to reset handler or event.
- if (theOldInstance != theObjectInstance) {
- theCmd->ResetHandler(
- theBridge->GetDefaultHandler(theObjectInstance, theActionInfo.m_Handler));
- }
+ if (!m_targetObjectBrowser.isNull() && m_targetObjectBrowser->canCommit()) {
+ auto core = g_StudioApp.GetCore();
+ auto doc = GetDoc();
+ auto theBridge = GetBridge();
+
+ auto theCmd = new CCmdDataModelActionSetTargetObject(doc, action, object);
+ const SActionInfo &theActionInfo = doc->GetStudioSystem()->GetActionCore()->GetActionInfo(
+ action);
+
+ Qt3DSDMInstanceHandle theBaseInstance = theActionInfo.m_Owner;
+ Qt3DSDMInstanceHandle theObjectInstance = theBridge->GetInstance(theBaseInstance, object);
+ Qt3DSDMInstanceHandle theOldInstance = theBridge->GetInstance(theBaseInstance,
+ theActionInfo.m_TargetObject);
+ // old instance and object instance could be the same, for example if user changes the type
+ // from Absolute to Path. In this case we don't need to reset handler or event.
+ if (theOldInstance != theObjectInstance) {
+ theCmd->ResetHandler(
+ theBridge->GetDefaultHandler(theObjectInstance, theActionInfo.m_Handler));
+ }
- core->ExecuteCommand(theCmd);
+ core->ExecuteCommand(theCmd);
+ }
emitActionChanged();
}
@@ -1107,3 +1196,14 @@ void ActionView::clearPropertyValueInvalid()
{
setPropertyValueInvalid(false);
}
+
+void ActionView::onAssetGraphChanged()
+{
+ // Changes to asset graph invalidate the object browser model, so close it if it is open
+ if (!m_activeBrowser.isNull() && m_activeBrowser->isVisible()
+ && (m_activeBrowser == m_targetObjectBrowser
+ || m_activeBrowser == m_triggerObjectBrowser)) {
+ m_activeBrowser->close();
+ m_activeBrowser.clear();
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/ActionView.h b/src/Authoring/Studio/Palettes/Action/ActionView.h
index 6b3c2807..4cdd2c58 100644
--- a/src/Authoring/Studio/Palettes/Action/ActionView.h
+++ b/src/Authoring/Studio/Palettes/Action/ActionView.h
@@ -134,6 +134,7 @@ public:
// CPresentationChangeListener
void OnNewPresentation() override;
+ void OnClosingPresentation() override;
// ISelectionChangeListener
void OnSelectionSet(Q3DStudio::SSelectedValue inSelectable);
@@ -186,6 +187,7 @@ private:
void updateActionStates();
void setPropertyValueInvalid(bool invalid);
void clearPropertyValueInvalid();
+ void onAssetGraphChanged();
static CDoc *GetDoc();
static CClientDataModelBridge *GetBridge();
@@ -224,6 +226,7 @@ private:
QAction *m_actionPaste;
bool m_propertyValueInvalid = true;
QColor m_currentColor;
+ QPointer<QWidget> m_activeBrowser = nullptr;
};
#endif // ACTIONVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Action/EventsBrowser.qml b/src/Authoring/Studio/Palettes/Action/EventsBrowser.qml
index 47baeec7..e5cb3998 100644
--- a/src/Authoring/Studio/Palettes/Action/EventsBrowser.qml
+++ b/src/Authoring/Studio/Palettes/Action/EventsBrowser.qml
@@ -43,13 +43,9 @@ Rectangle {
ListView {
id: eventsList
- Layout.margins: 10
- Layout.columnSpan: 2
+ Layout.margins: 5
Layout.fillWidth: true
Layout.fillHeight: true
- Layout.minimumHeight: 80
- Layout.preferredHeight: count * 20
- Layout.preferredWidth: root.width
ScrollBar.vertical: ScrollBar {}
@@ -64,9 +60,8 @@ Rectangle {
readonly property bool isCategory: model.isCategory
- x: isCategory ? 0 : 50
width: parent.width
- height: model.parentExpanded ? 30 : 0
+ height: model.parentExpanded ? _controlBaseHeight : 0
visible: height > 0
Behavior on height {
@@ -76,66 +71,63 @@ Rectangle {
}
}
- Row {
- id: row
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ color: model.index === eventsList.currentIndex ? _selectionColor
+ : "transparent"
+ Row {
+ id: row
+ width: parent.width
+ height: parent.height
+ spacing: 5
+
+ Image {
+ id: arrow
+ anchors.verticalCenter: parent.verticalCenter
+ source: {
+ if (!delegateItem.isCategory)
+ return "";
+ model.expanded ? _resDir + "arrow_down.png"
+ : _resDir + "arrow.png";
+ }
- height: categoryIcon.height
- spacing: 5
+ MouseArea {
+ anchors.fill: parent
+ onClicked: model.expanded = !model.expanded
+ }
+ }
- Image {
- source: {
- if (!delegateItem.isCategory)
- return "";
- model.expanded ? _resDir + "arrow_down.png"
- : _resDir + "arrow.png";
+ Image { // group icon
+ anchors.verticalCenter: parent.verticalCenter
+ source: model.icon
}
- MouseArea {
- anchors.fill: parent
- onClicked: model.expanded = !model.expanded
+ StyledLabel {
+ id: name
+ leftPadding: isCategory ? 0 : 45
+ anchors.verticalCenter: parent.verticalCenter
+ text: model.name
}
}
- 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
+ anchors.leftMargin: arrow.width
+ hoverEnabled: true
+ onClicked: {
+ if (!delegateItem.isCategory)
+ eventsList.currentIndex = model.index;
}
-
- MouseArea {
- id: delegateArea
-
- anchors.fill: parent
- hoverEnabled: true
- onClicked: {
- if (!delegateItem.isCategory)
- eventsList.currentIndex = model.index;
- }
- onEntered: itemDescription.text = model.description
- onExited: itemDescription.text = ""
- onDoubleClicked: {
- if (!delegateItem.isCategory) {
- eventsList.currentIndex = model.index;
- _eventsBrowserView.close();
- }
+ onEntered: itemDescription.text = model.description
+ onExited: itemDescription.text = ""
+ onDoubleClicked: {
+ if (!delegateItem.isCategory) {
+ eventsList.currentIndex = model.index;
+ _eventsBrowserView.close();
+ } else {
+ model.expanded = !model.expanded
}
}
}
diff --git a/src/Authoring/Studio/Palettes/Action/EventsBrowserView.cpp b/src/Authoring/Studio/Palettes/Action/EventsBrowserView.cpp
index e677eb6b..b7151af2 100644
--- a/src/Authoring/Studio/Palettes/Action/EventsBrowserView.cpp
+++ b/src/Authoring/Studio/Palettes/Action/EventsBrowserView.cpp
@@ -27,9 +27,7 @@
****************************************************************************/
#include "EventsBrowserView.h"
-#include <QtGui/qcolor.h>
#include "EventsModel.h"
-#include "Literals.h"
#include "StudioUtils.h"
#include "StudioPreferences.h"
@@ -58,11 +56,6 @@ void EventsBrowserView::setModel(EventsModel *model)
}
}
-QSize EventsBrowserView::sizeHint() const
-{
- return {500, 500};
-}
-
qt3dsdm::CDataModelHandle EventsBrowserView::selectedHandle() const
{
const auto handleId = m_model->handleForRow(m_selection);
@@ -72,7 +65,10 @@ qt3dsdm::CDataModelHandle EventsBrowserView::selectedHandle() const
void EventsBrowserView::selectAndExpand(const QString &event)
{
// All categories are expanded by default, so let's just select
+ m_blockCommit = true;
setSelection(m_model->rowForEventName(event));
+ m_blockCommit = false;
+
}
void EventsBrowserView::setSelection(int index)
diff --git a/src/Authoring/Studio/Palettes/Action/EventsBrowserView.h b/src/Authoring/Studio/Palettes/Action/EventsBrowserView.h
index f4e373b2..f8a2b7fa 100644
--- a/src/Authoring/Studio/Palettes/Action/EventsBrowserView.h
+++ b/src/Authoring/Studio/Palettes/Action/EventsBrowserView.h
@@ -46,7 +46,6 @@ public:
QAbstractItemModel *model() const;
void setModel(EventsModel *model);
- QSize sizeHint() const override;
qt3dsdm::CDataModelHandle selectedHandle() const;
void selectAndExpand(const QString &event);
@@ -54,6 +53,11 @@ public:
int selection() const { return m_selection; }
void setSelection(int index);
+ void setHandle(int handle) { m_handle = handle; }
+ int handle() const { return m_handle; }
+
+ bool canCommit() const { return !m_blockCommit; }
+
Q_SIGNALS:
void modelChanged();
void selectionChanged();
@@ -68,6 +72,8 @@ private:
QColor m_baseColor = QColor::fromRgb(75, 75, 75);
QColor m_selectColor;
int m_selection = -1;
+ int m_handle = -1;
+ bool m_blockCommit = false;
};
#endif // EVENTSBROWSERVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/ChooserDelegate.qml b/src/Authoring/Studio/Palettes/Inspector/ChooserDelegate.qml
index b3de58e5..71462f48 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ChooserDelegate.qml
+++ b/src/Authoring/Studio/Palettes/Inspector/ChooserDelegate.qml
@@ -42,7 +42,7 @@ Rectangle {
color: isCurrentFile ? _selectionColor : "transparent"
Row {
- x: depth*28
+ x: depth * 28 - (item.width <= _valueWidth ? 14 : 0)
anchors.verticalCenter: item.verticalCenter
Image {
diff --git a/src/Authoring/Studio/Palettes/Inspector/DataInputChooser.qml b/src/Authoring/Studio/Palettes/Inspector/DataInputChooser.qml
index d949cec9..3681a102 100644
--- a/src/Authoring/Studio/Palettes/Inspector/DataInputChooser.qml
+++ b/src/Authoring/Studio/Palettes/Inspector/DataInputChooser.qml
@@ -89,6 +89,14 @@ Rectangle {
+ "by compatibility with current property")
enabled: filterBoxMouseArea.containsMouse && !filterCombo.popup.activeFocus
}
+ Connections {
+ target: _parentView
+ // Filter type can be changed also from cpp side
+ onFilterChanged: {
+ filterCombo.currentIndex = _parentView.typeFilter
+ + filterCombo.numOfFixedChoices;
+ }
+ }
}
StyledTextField {
diff --git a/src/Authoring/Studio/Palettes/Inspector/FileChooserView.cpp b/src/Authoring/Studio/Palettes/Inspector/FileChooserView.cpp
index c90a3c2f..fc4612c9 100644
--- a/src/Authoring/Studio/Palettes/Inspector/FileChooserView.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/FileChooserView.cpp
@@ -63,11 +63,6 @@ void FileChooserView::initialize()
setSource(QUrl(QStringLiteral("qrc:/Palettes/Inspector/FileChooser.qml")));
}
-QSize FileChooserView::sizeHint() const
-{
- return {500, 500};
-}
-
void FileChooserView::setHandle(int handle)
{
m_handle = handle;
@@ -88,6 +83,21 @@ int FileChooserView::instance() const
return m_instance;
}
+void FileChooserView::updateSelection()
+{
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+
+ qt3dsdm::SValue value;
+ propertySystem->GetInstancePropertyValue(m_instance, m_handle, value);
+
+ QString valueStr = qt3dsdm::get<QString>(value);
+ if (valueStr.isEmpty())
+ valueStr = ChooserModelBase::noneString();
+
+ m_model->setCurrentFile(valueStr);
+}
+
void FileChooserView::focusOutEvent(QFocusEvent *event)
{
QQuickWidget::focusOutEvent(event);
@@ -122,13 +132,6 @@ void FileChooserView::keyPressEvent(QKeyEvent *event)
void FileChooserView::showEvent(QShowEvent *event)
{
- const auto doc = g_StudioApp.GetCore()->GetDoc();
- const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
-
- qt3dsdm::SValue value;
- propertySystem->GetInstancePropertyValue(m_instance, m_handle, value);
-
- m_model->setCurrentFile(qt3dsdm::get<QString>(value));
-
+ updateSelection();
QQuickWidget::showEvent(event);
}
diff --git a/src/Authoring/Studio/Palettes/Inspector/FileChooserView.h b/src/Authoring/Studio/Palettes/Inspector/FileChooserView.h
index 774fb003..6b99343e 100644
--- a/src/Authoring/Studio/Palettes/Inspector/FileChooserView.h
+++ b/src/Authoring/Studio/Palettes/Inspector/FileChooserView.h
@@ -43,14 +43,14 @@ class FileChooserView : public QQuickWidget
public:
explicit FileChooserView(QWidget *parent = nullptr);
- QSize sizeHint() const override;
-
void setHandle(int handle);
int handle() const;
void setInstance(int instance);
int instance() const;
+ void updateSelection();
+
Q_SIGNALS:
void fileSelected(int handle, int instance, const QString &name);
diff --git a/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.cpp b/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.cpp
index b22e7fb2..b9b9be9b 100644
--- a/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.cpp
@@ -97,6 +97,12 @@ struct SComboAttItem : public IInspectableAttributeItem
m_BaseInspectableInfo.m_Commit();
}
+ void ChangeInspectableData(const qt3dsdm::SValue &inValue) override
+ {
+ m_BaseInspectableInfo.m_Setter(inValue);
+ }
+ void CancelInspectableData() override { m_BaseInspectableInfo.m_Cancel(); }
+
float GetInspectableMin() const override { return 0; }
float GetInspectableMax() const override { return 0; }
qt3dsdm::TMetaDataStringList GetInspectableList() const override { return m_MetaDataTypes; }
@@ -160,7 +166,10 @@ struct SFloatIntItem : public IInspectableAttributeItem
qt3dsdm::DataModelDataType::Value GetInspectableType() const override { return m_DataType; }
qt3dsdm::AdditionalMetaDataType::Value GetInspectableAdditionalType() const override
{
- return qt3dsdm::AdditionalMetaDataType::None;
+ if (m_Max > 0)
+ return qt3dsdm::AdditionalMetaDataType::Range;
+ else
+ return qt3dsdm::AdditionalMetaDataType::None;
}
};
@@ -217,8 +226,8 @@ CInspectorGroup *SGuideInspectableImpl::GetGroup(long)
m_Properties.push_back(
std::make_shared<SComboAttItem>(
- SInspectableDataInfo(QStringLiteral("Direction"), QObject::tr("Direction"),
- QObject::tr("Direction of the guide"),
+ SInspectableDataInfo(QStringLiteral("Orientation"), QObject::tr("Orientation"),
+ QObject::tr("Orientation of the guide"),
std::bind(&SGuideInspectableImpl::GetDirection, this),
std::bind(&SGuideInspectableImpl::SetDirection, this,
std::placeholders::_1),
@@ -326,3 +335,9 @@ void SGuideInspectableImpl::FireRefresh()
{
m_Editor.FireImmediateRefresh(qt3dsdm::Qt3DSDMInstanceHandle());
}
+
+const std::vector<std::shared_ptr<IInspectableAttributeItem>> &
+SGuideInspectableImpl::properties() const
+{
+ return m_Properties;
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.h b/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.h
index df95458d..713b7dd1 100644
--- a/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.h
+++ b/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.h
@@ -76,6 +76,8 @@ public:
void Commit();
void Rollback();
void FireRefresh();
+
+ const std::vector<std::shared_ptr<IInspectableAttributeItem>> &properties() const;
private:
qt3dsdm::Qt3DSDMGuideHandle m_Guide;
Q3DStudio::CUpdateableDocumentEditor m_Editor;
diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.cpp b/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.cpp
index e55935a0..dbb720fb 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.cpp
@@ -28,11 +28,15 @@
#include "ImageChooserModel.h"
#include "StudioApp.h"
+#include "ProjectFile.h"
+#include "Core.h"
ImageChooserModel::ImageChooserModel(bool showRenderables, QObject *parent)
: ChooserModelBase(parent)
, m_showRenderables(showRenderables)
{
+ connect(&g_StudioApp.GetCore()->getProjectFile(), &ProjectFile::presentationIdChanged,
+ this, &ImageChooserModel::handlePresentationIdChange);
}
ImageChooserModel::~ImageChooserModel()
@@ -57,3 +61,12 @@ QString ImageChooserModel::specialDisplayName(const ChooserModelBase::TreeItem &
const QString path = item.index.data(QFileSystemModel::FilePathRole).toString();
return g_StudioApp.getRenderableId(path);
}
+
+void ImageChooserModel::handlePresentationIdChange(const QString &path, const QString &id)
+{
+ Q_UNUSED(path)
+ Q_UNUSED(id)
+
+ // Simply update the filename for all rows
+ Q_EMIT dataChanged(index(0), index(rowCount() - 1), {QFileSystemModel::FileNameRole});
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.h b/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.h
index 0a87f3a1..7a1c6b5a 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.h
+++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.h
@@ -43,6 +43,7 @@ private:
bool isVisible(const QString &path) const override;
const QVector<FixedItem> getFixedItems() const override;
QString specialDisplayName(const TreeItem &item) const override;
+ void handlePresentationIdChange(const QString &path, const QString &id);
bool m_showRenderables = false;
};
diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.cpp b/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.cpp
index a9b9e92c..459dd160 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.cpp
@@ -63,11 +63,6 @@ void ImageChooserView::initialize()
setSource(QUrl(QStringLiteral("qrc:/Palettes/Inspector/ImageChooser.qml")));
}
-QSize ImageChooserView::sizeHint() const
-{
- return {500, 500};
-}
-
void ImageChooserView::setHandle(int handle)
{
m_handle = handle;
@@ -120,6 +115,11 @@ QString ImageChooserView::currentDataModelPath() const
return cleanPath;
}
+void ImageChooserView::updateSelection()
+{
+ m_model->setCurrentFile(currentDataModelPath());
+}
+
bool ImageChooserView::isFocused() const
{
return hasFocus();
@@ -148,6 +148,6 @@ void ImageChooserView::keyPressEvent(QKeyEvent *event)
void ImageChooserView::showEvent(QShowEvent *event)
{
- m_model->setCurrentFile(currentDataModelPath());
+ updateSelection();
QQuickWidget::showEvent(event);
}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.h b/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.h
index 74f89d51..bbf8eff5 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.h
+++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.h
@@ -43,8 +43,6 @@ class ImageChooserView : public QQuickWidget
public:
explicit ImageChooserView(QWidget *parent = nullptr);
- QSize sizeHint() const override;
-
void setHandle(int handle);
int handle() const;
@@ -52,6 +50,8 @@ public:
int instance() const;
QString currentDataModelPath() const;
+ void updateSelection();
+
Q_SIGNALS:
void imageSelected(int handle, int instance, const QString &name);
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp
index af97f6cb..48cdfe1c 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp
@@ -202,18 +202,18 @@ void InspectorControlModel::notifyInstancePropertyValue(qt3dsdm::Qt3DSDMInstance
Q_EMIT dataChanged(index(0), index(rowCount() - 1));
}
-QVariant InspectorControlModel::getPropertyValue(long instance, int handle)
+bool InspectorControlModel::hasInstanceProperty(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];
+ for (const auto &group : qAsConst(m_groupElements)) {
+ for (const auto &element : qAsConst(group.controlElements)) {
InspectorControlBase *property = element.value<InspectorControlBase *>();
- if (property->m_property == qt3dsdm::CDataModelHandle(handle))
- return property->m_value;
+ if (property->m_property == qt3dsdm::CDataModelHandle(handle)
+ && property->m_instance == qt3dsdm::CDataModelHandle(instance)) {
+ return true;
+ }
}
}
- return {};
+ return false;
}
bool InspectorControlModel::isInsideMaterialContainer() const
@@ -892,94 +892,62 @@ qt3dsdm::SValue InspectorControlModel::currentPropertyValue(long instance, int h
const auto propertySystem = studioSystem->GetPropertySystem();
propertySystem->GetInstancePropertyValue(instance, handle, value);
- return value;
+ return value;
}
QString InspectorControlModel::currentControllerValue(long instance, int handle) const
{
- const auto doc = g_StudioApp.GetCore()->GetDoc();
- auto studio = doc->GetStudioSystem();
-
- qt3dsdm::SValue currPropVal = currentPropertyValue(
- instance, studio->GetPropertySystem()->GetAggregateInstancePropertyByName(
- instance, QStringLiteral("controlledproperty")));
- if (!currPropVal.empty()) {
- QString currPropValStr
- = qt3dsdm::get<qt3dsdm::TDataStrPtr>(currPropVal)->toQString();
-
- QString propName
- = studio->GetPropertySystem()->GetName(handle);
-
- // Datainput controller name is always prepended with "$". Differentiate
- // between datainput and property that has the same name by searching specifically
- // for whitespace followed by property name.
- long propNamePos = currPropValStr.indexOf(QStringLiteral(" ") + propName);
- if (propNamePos != -1 && propNamePos != 0) {
- long posCtrlr = currPropValStr.left(propNamePos).lastIndexOf(QLatin1Char('$'));
-
- // adjust pos if this is the first controller - property pair
- // in controlledproperty
- if (posCtrlr < 0)
- posCtrlr = 0;
-
- // remove $
- posCtrlr++;
- return currPropValStr.mid(posCtrlr, propNamePos - posCtrlr);
- }
- else
- return {};
- } else {
- return {};
- }
+ return g_StudioApp.GetCore()->GetDoc()->GetCurrentController(instance, handle);
}
void InspectorControlModel::updateControlledToggleState(InspectorControlBase* inItem) const
{
- const auto studio = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem();
- // toggle if controlledproperty contains the name of this property
- qt3dsdm::SValue currPropVal = currentPropertyValue(
- inItem->m_instance, studio->GetPropertySystem()->GetAggregateInstancePropertyByName(
- inItem->m_instance, QStringLiteral("controlledproperty")));
- QString currPropValStr;
- if (!currPropVal.empty())
- currPropValStr = qt3dsdm::get<qt3dsdm::TDataStrPtr>(currPropVal)->toQString();
- // Restore original tool tip from metadata when turning control off
- if (!currPropValStr.size()) {
- inItem->m_controlled = false;
- inItem->m_controller = "";
- } else {
- QString propName
- = studio->GetPropertySystem()->GetName(inItem->m_property);
- // Search specifically for whitespace followed with registered property name.
- // This avoids finding datainput with same name as the property, as datainput
- // name is always prepended with "$"
- long propNamePos = currPropValStr.indexOf(QStringLiteral(" ") + propName);
- if ((propNamePos == -1)
- && (propNamePos != 0)) {
- inItem->m_controlled = false;
- inItem->m_controller = "";
- } else {
- inItem->m_controlled = true;
- // controller name is prepended with "$" to differentiate from property
- // with same name. Reverse find specifically for $.
- long posCtrlr = currPropValStr.left(propNamePos).lastIndexOf(QLatin1Char('$'));
-
- // this is the first controller - property pair in controlledproperty
- if (posCtrlr < 0)
- posCtrlr = 0;
-
- // remove $ from controller name for showing it in UI
- posCtrlr++;
- const QString ctrlName = currPropValStr.mid(posCtrlr, propNamePos - posCtrlr);
-
- inItem->m_controller = ctrlName;
- }
- }
+ if (inItem->m_instance) {
+ const auto studio = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem();
+ // toggle if controlledproperty contains the name of this property
+ qt3dsdm::SValue currPropVal = currentPropertyValue(
+ inItem->m_instance, studio->GetPropertySystem()->GetAggregateInstancePropertyByName(
+ inItem->m_instance, QStringLiteral("controlledproperty")));
+ QString currPropValStr;
+ if (!currPropVal.empty())
+ currPropValStr = qt3dsdm::get<qt3dsdm::TDataStrPtr>(currPropVal)->toQString();
+ // Restore original tool tip from metadata when turning control off
+ if (!currPropValStr.size()) {
+ inItem->m_controlled = false;
+ inItem->m_controller.clear();
+ } else {
+ QString propName
+ = studio->GetPropertySystem()->GetName(inItem->m_property);
+ // Search specifically for whitespace followed with registered property name.
+ // This avoids finding datainput with same name as the property, as datainput
+ // name is always prepended with "$"
+ long propNamePos = currPropValStr.indexOf(QStringLiteral(" ") + propName);
+ if ((propNamePos == -1) && (propNamePos != 0)) {
+ inItem->m_controlled = false;
+ inItem->m_controller.clear();
+ } else {
+ inItem->m_controlled = true;
+ // controller name is prepended with "$" to differentiate from property
+ // with same name. Reverse find specifically for $.
+ long posCtrlr = currPropValStr.left(propNamePos).lastIndexOf(QLatin1Char('$'));
+
+ // this is the first controller - property pair in controlledproperty
+ if (posCtrlr < 0)
+ posCtrlr = 0;
+
+ // remove $ from controller name for showing it in UI
+ posCtrlr++;
+ const QString ctrlName = currPropValStr.mid(posCtrlr, propNamePos - posCtrlr);
+
+ inItem->m_controller = ctrlName;
+ }
+ }
- Q_EMIT inItem->tooltipChanged();
- // Emit signal always to trigger updating of controller name in UI
- // also when user switches from one controller to another
- Q_EMIT inItem->controlledChanged();
+ Q_EMIT inItem->tooltipChanged();
+ // Emit signal always to trigger updating of controller name in UI
+ // also when user switches from one controller to another
+ Q_EMIT inItem->controlledChanged();
+ }
}
void InspectorControlModel::updateAnimateToggleState(InspectorControlBase* inItem)
@@ -993,13 +961,17 @@ void InspectorControlModel::updateAnimateToggleState(InspectorControlBase* inIte
}
}
-bool InspectorControlModel::isTreeRebuildRequired(CInspectableBase* inspectBase) const
+bool InspectorControlModel::isTreeRebuildRequired(CInspectableBase* inspectBase)
{
if (inspectBase != m_inspectableBase || !inspectBase)
return true;
long theCount = m_inspectableBase->GetGroupCount();
auto refMaterial = getReferenceMaterial(inspectBase);
+ if (refMaterial != m_refMaterial) {
+ m_refMaterial = refMaterial;
+ return true;
+ }
long refMaterialGroupCount = 0;
if (refMaterial.Valid())
refMaterialGroupCount = 1; // Only the last group of the refMaterial is used
@@ -1141,7 +1113,6 @@ auto InspectorControlModel::computeGroup(CInspectableBase* inspectable,
}
}
- const auto sceneEditor = g_StudioApp.GetCore()->GetDoc()->getSceneEditor();
for (const auto row : group->GetRows()) {
InspectorControlBase *item = createItem(cdmInspectable, row, theIndex);
if (!item)
@@ -1154,8 +1125,23 @@ auto InspectorControlModel::computeGroup(CInspectableBase* inspectable,
result.controlElements.push_back(QVariant::fromValue(item));
}
}
- } else if (dynamic_cast<SGuideInspectableImpl *>(inspectable)) {
- //KDAB_FIXME: load row element (How ?)
+ } else if (const auto guideInspectable = dynamic_cast<SGuideInspectableImpl *>(inspectable)) {
+ // Guide properties don't come from metadata as they are not actual objects
+ m_guideInspectable = guideInspectable;
+ const auto &properties = m_guideInspectable->properties();
+ for (int i = 0, count = int(properties.size()); i < count; ++i) {
+ auto &prop = properties[i];
+ InspectorControlBase *item = new InspectorControlBase;
+ item->m_title = prop->GetInspectableFormalName();
+ item->m_dataType = prop->GetInspectableType();
+ item->m_propertyType = prop->GetInspectableAdditionalType();
+ item->m_tooltip = prop->GetInspectableDescription();
+ item->m_animatable = false;
+ item->m_controllable = false;
+ item->m_property = i + 1; // Zero property is considered invalid, so +1
+ result.controlElements.push_back(QVariant::fromValue(item));
+ updatePropertyValue(item);
+ }
}
return result;
@@ -1164,6 +1150,7 @@ auto InspectorControlModel::computeGroup(CInspectableBase* inspectable,
void InspectorControlModel::rebuildTree()
{
beginResetModel();
+ m_guideInspectable = nullptr;
QVector<QObject *> deleteVector;
for (int i = 0; i < m_groupElements.count(); ++i) {
auto group = m_groupElements[i];
@@ -1190,17 +1177,28 @@ void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) c
{
const auto doc = g_StudioApp.GetCore()->GetDoc();
auto studioSystem = doc->GetStudioSystem();
- const auto propertySystem = studioSystem->GetPropertySystem();
auto bridge = studioSystem->GetClientDataModelBridge();
+ const auto propertySystem = studioSystem->GetPropertySystem();
qt3dsdm::SValue value;
const auto instance = element->m_instance;
- if (!propertySystem->HandleValid(instance))
- return;
- propertySystem->GetInstancePropertyValue(instance, element->m_property, value);
+ qt3dsdm::Option<qt3dsdm::SMetaDataPropertyInfo> info;
+ if (m_guideInspectable) {
+ value = m_guideInspectable->properties()
+ [handleToGuidePropIndex(element->m_property)]->GetInspectableData();
+ } else {
+ if (!propertySystem->HandleValid(instance))
+ return;
+ propertySystem->GetInstancePropertyValue(instance, element->m_property, value);
+
+ if (value.getType() == qt3dsdm::DataModelDataType::None)
+ return;
+
+ const auto metaDataProvider = doc->GetStudioSystem()->GetActionMetaData();
+ info = metaDataProvider->GetMetaDataPropertyInfo(
+ metaDataProvider->GetMetaDataProperty(instance, element->m_property));
+ }
+
- const auto metaDataProvider = doc->GetStudioSystem()->GetActionMetaData();
- const auto info = metaDataProvider->GetMetaDataPropertyInfo(
- metaDataProvider->GetMetaDataProperty(instance, element->m_property));
bool skipEmits = false;
switch (element->m_dataType) {
case qt3dsdm::DataModelDataType::String: {
@@ -1214,7 +1212,15 @@ void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) c
} // intentional fall-through for other String-derived datatypes
case qt3dsdm::DataModelDataType::StringOrInt:
if (element->m_propertyType == qt3dsdm::AdditionalMetaDataType::StringList) {
- QStringList stringlist = qt3dsdm::get<QStringList>(info->m_MetaDataData);
+ QStringList stringlist;
+ if (m_guideInspectable) {
+ const auto strings = m_guideInspectable->properties()
+ [handleToGuidePropIndex(element->m_property)]->GetInspectableList();
+ for (auto &str : strings)
+ stringlist.append(QString::fromWCharArray(str.wide_str()));
+ } else {
+ stringlist = qt3dsdm::get<QStringList>(info->m_MetaDataData);;
+ }
auto slideSystem = studioSystem->GetSlideSystem();
if (element->m_title == QStringLiteral("Play Mode")) {
@@ -1334,7 +1340,15 @@ void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) c
case qt3dsdm::DataModelDataType::Long:
if (element->m_propertyType == qt3dsdm::AdditionalMetaDataType::Range) {
element->m_value = qt3dsdm::get<int>(value);
- const qt3dsdm::SMetaDataRange ranges = qt3dsdm::get<qt3dsdm::SMetaDataRange>(info->m_MetaDataData);
+ qt3dsdm::SMetaDataRange ranges;
+ if (m_guideInspectable) {
+ const auto prop = m_guideInspectable->properties()
+ [handleToGuidePropIndex(element->m_property)];
+ ranges.m_Min = prop->GetInspectableMin();
+ ranges.m_Max = prop->GetInspectableMax();
+ } else {
+ ranges = qt3dsdm::get<qt3dsdm::SMetaDataRange>(info->m_MetaDataData);
+ }
const QList<double> rangesValues{ranges.m_Min, ranges.m_Max};
element->m_values = QVariant::fromValue<QList<double> >(rangesValues);
}
@@ -1473,6 +1487,9 @@ void InspectorControlModel::refresh()
void InspectorControlModel::saveIfMaterial(qt3dsdm::Qt3DSDMInstanceHandle instance)
{
+ if (!instance.Valid())
+ return;
+
const auto doc = g_StudioApp.GetCore()->GetDoc();
const auto sceneEditor = doc->getSceneEditor();
@@ -1595,6 +1612,7 @@ void InspectorControlModel::setShaderValue(long instance, int handle, const QVar
const auto doc = g_StudioApp.GetCore()->GetDoc();
const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+
Q3DStudio::SCOPED_DOCUMENT_EDITOR(*doc, QObject::tr("Set Material Type"))
->SetMaterialType(instance, v);
@@ -1711,7 +1729,7 @@ void InspectorControlModel::setPropertyValue(long instance, int handle, const QV
const auto studio = doc->GetStudioSystem();
const auto bridge = studio->GetClientDataModelBridge();
// Name property needs special handling
- if (handle == bridge->GetNameProperty()) {
+ if (instance && handle == bridge->GetNameProperty()) {
// Ignore preview of name property change
if (!commit)
return;
@@ -1725,7 +1743,8 @@ void InspectorControlModel::setPropertyValue(long instance, int handle, const QV
if (!newName.isEmpty()) {
if (bridge->isInsideMaterialContainer(instance)
&& (newName.indexOf(QLatin1Char('/')) != -1
- || newName.indexOf(QLatin1Char('#')) != -1)) {
+ || newName.indexOf(QLatin1Char('#')) != -1
+ || newName.indexOf(QLatin1Char(':')) != -1)) {
return;
}
qt3dsdm::Qt3DSDMInstanceHandle parentInstance = bridge->GetParentInstance(instance);
@@ -1811,7 +1830,9 @@ void InspectorControlModel::setPropertyValue(long instance, int handle, const QV
return;
}
- qt3dsdm::SValue oldValue = currentPropertyValue(instance, handle);
+ qt3dsdm::SValue oldValue = m_guideInspectable
+ ? m_guideInspectable->properties()[handleToGuidePropIndex(handle)]->GetInspectableData()
+ : currentPropertyValue(instance, handle);
qt3dsdm::SValue v = value;
const bool hasPreview = (m_modifiedProperty.first == instance
@@ -1829,35 +1850,46 @@ void InspectorControlModel::setPropertyValue(long instance, int handle, const QV
m_modifiedProperty.second = handle;
}
- // If the user enters 0.0 to any (x, y, z) values of camera scale,
- // we reset the value back to original, because zero scale factor will crash
- // camera-specific inverse matrix math. (Additionally, scale of zero for a camera
- // is generally not useful anyway.) We could silently discard zero values also deeper in the
- // value setter code, but then the inspector panel value would not be updated as opposed
- // to both rejecting invalid and resetting the original value here.
- EStudioObjectType theType = bridge->GetObjectType(instance);
- qt3dsdm::AdditionalMetaDataType::Value additionalType
- = studio->GetPropertySystem()->GetAdditionalMetaDataType(instance, handle);
-
- if (theType == EStudioObjectType::OBJTYPE_CAMERA &&
- studio->GetPropertySystem()->GetName(handle) == QLatin1String("scale")) {
- const QVector3D theFloat3 = qt3dsdm::get<QVector3D>(v);
- if (theFloat3.x() == 0.0f || theFloat3.y() == 0.0f || theFloat3.z() == 0.0f )
- v = oldValue;
- }
+ if (instance) {
+ // If the user enters 0.0 to any (x, y, z) values of camera scale,
+ // we reset the value back to original, because zero scale factor will crash
+ // camera-specific inverse matrix math. (Additionally, scale of zero for a camera
+ // is generally not useful anyway.) We could silently discard zero values also deeper in the
+ // value setter code, but then the inspector panel value would not be updated as opposed
+ // to both rejecting invalid and resetting the original value here.
+ EStudioObjectType theType = bridge->GetObjectType(instance);
+ qt3dsdm::AdditionalMetaDataType::Value additionalType
+ = studio->GetPropertySystem()->GetAdditionalMetaDataType(instance, handle);
+
+ if (theType == EStudioObjectType::OBJTYPE_CAMERA &&
+ studio->GetPropertySystem()->GetName(handle) == QLatin1String("scale")) {
+ const QVector3D theFloat3 = qt3dsdm::get<QVector3D>(v);
+ if (theFloat3.x() == 0.0f || theFloat3.y() == 0.0f || theFloat3.z() == 0.0f )
+ v = oldValue;
+ }
- m_UpdatableEditor.EnsureEditor(QObject::tr("Set Property"), __FILE__, __LINE__)
- .SetInstancePropertyValue(instance, handle, v);
+ m_UpdatableEditor.EnsureEditor(QObject::tr("Set Property"), __FILE__, __LINE__)
+ .SetInstancePropertyValue(instance, handle, v);
- m_UpdatableEditor.FireImmediateRefresh(instance);
+ m_UpdatableEditor.FireImmediateRefresh(instance);
+ } else if (m_guideInspectable) {
+ m_guideInspectable->properties()[handleToGuidePropIndex(handle)]->ChangeInspectableData(v);
+ }
if (commit) {
m_modifiedProperty.first = 0;
m_modifiedProperty.second = 0;
- if (m_previouslyCommittedValue == v)
- m_UpdatableEditor.RollbackEditor();
- else
- m_UpdatableEditor.CommitEditor();
+ if (m_previouslyCommittedValue == v) {
+ if (m_guideInspectable)
+ m_guideInspectable->Rollback();
+ else
+ m_UpdatableEditor.RollbackEditor();
+ } else {
+ if (m_guideInspectable)
+ m_guideInspectable->Commit();
+ else
+ m_UpdatableEditor.CommitEditor();
+ }
m_previouslyCommittedValue = {};
refreshTree();
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h
index 0d1e9e3f..13413bb4 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h
@@ -130,7 +130,7 @@ public:
void refresh();
void saveIfMaterial(qt3dsdm::Qt3DSDMInstanceHandle instance);
- QVariant getPropertyValue(long instance, int handle);
+ bool hasInstanceProperty(long instance, int handle);
qt3dsdm::SValue currentPropertyValue(long instance, int handle) const;
QString currentControllerValue(long instance, int handle) const;
@@ -170,6 +170,7 @@ private:
mutable QVector<GroupInspectorControl> m_groupElements;
CInspectableBase *m_inspectableBase = nullptr;
+ SGuideInspectableImpl *m_guideInspectable = nullptr;
struct MaterialEntry
{
@@ -188,6 +189,7 @@ private:
std::vector<MaterialEntry> m_materials;
std::vector<MaterialDataEntry> m_matDatas;
std::vector<Q3DStudio::CFilePath> m_cachedMatDatas;
+ qt3dsdm::Qt3DSDMInstanceHandle m_refMaterial;
Q3DStudio::CUpdateableDocumentEditor m_UpdatableEditor;
@@ -233,12 +235,14 @@ private:
int groupIndex);
QVector<GroupInspectorControl> computeTree(CInspectableBase *inspectBase);
- bool isTreeRebuildRequired(CInspectableBase *inspectBase) const;
+ bool isTreeRebuildRequired(CInspectableBase *inspectBase);
GroupInspectorControl computeGroup(CInspectableBase* inspectBase,
int theIndex, bool disableAnimation = false,
bool isReference = false);
bool isGroupRebuildRequired(CInspectableBase *inspectable, int theIndex) const;
+
+ static int handleToGuidePropIndex(int handle) { return handle - 1; }
};
#endif // INSPECTORCONTROLMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp
index d47a953b..b6037011 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp
@@ -56,6 +56,7 @@
#include "Dialogs.h"
#include "ProjectFile.h"
#include "MaterialRefView.h"
+#include "BasicObjectsModel.h"
#include <QtCore/qtimer.h>
#include <QtQml/qqmlcontext.h>
@@ -68,6 +69,7 @@ InspectorControlView::InspectorControlView(const QSize &preferredSize, QWidget *
: QQuickWidget(parent),
TabNavigable(),
m_inspectorControlModel(new InspectorControlModel(this)),
+ m_meshChooserView(new MeshChooserView(this)),
m_instance(0),
m_handle(0),
m_preferredSize(preferredSize)
@@ -78,8 +80,15 @@ InspectorControlView::InspectorControlView(const QSize &preferredSize, QWidget *
dispatch->AddPresentationChangeListener(this);
dispatch->AddDataModelListener(this);
- m_selectionChangedConnection = g_StudioApp.GetCore()->GetDispatch()->ConnectSelectionChange(
- std::bind(&InspectorControlView::OnSelectionSet, this, std::placeholders::_1));
+ connect(m_meshChooserView, &MeshChooserView::meshSelected, this,
+ [this] (int handle, int instance, const QString &name) {
+ if (name.startsWith(QLatin1Char('#'))) {
+ if (m_inspectorControlModel)
+ m_inspectorControlModel->setPropertyValue(instance, handle, name);
+ } else {
+ setPropertyValueFromFilename(instance, handle, name);
+ }
+ });
}
static bool isInList(const QStringList &list, const QString &inStr)
@@ -116,17 +125,34 @@ void InspectorControlView::filterMatDatas(std::vector<Q3DStudio::CFilePath> &mat
void InspectorControlView::OnNewPresentation()
{
- m_DirectoryConnection = g_StudioApp.getDirectoryWatchingSystem().AddDirectory(
+ auto core = g_StudioApp.GetCore();
+ auto sp = core->GetDoc()->GetStudioSystem()->GetFullSystem()->GetSignalProvider();
+ auto assetGraph = core->GetDoc()->GetAssetGraph();
+
+ m_connections.push_back(core->GetDispatch()->ConnectSelectionChange(
+ std::bind(&InspectorControlView::OnSelectionSet, this, std::placeholders::_1)));
+ m_connections.push_back(g_StudioApp.getDirectoryWatchingSystem().AddDirectory(
g_StudioApp.GetCore()->getProjectFile().getProjectPath(),
- std::bind(&InspectorControlView::onFilesChanged, this, std::placeholders::_1));
+ std::bind(&InspectorControlView::onFilesChanged, this, std::placeholders::_1)));
+ m_connections.push_back(sp->ConnectInstancePropertyValue(
+ std::bind(&InspectorControlView::onInstancePropertyValueChanged, this,
+ std::placeholders::_2)));
+ m_connections.push_back(sp->ConnectComponentSeconds(
+ std::bind(&InspectorControlView::OnTimeChanged, this)));
+ m_connections.push_back(assetGraph->ConnectChildAdded(
+ std::bind(&InspectorControlView::onChildAdded, this, std::placeholders::_2)));
+ m_connections.push_back(assetGraph->ConnectChildRemoved(
+ std::bind(&InspectorControlView::onChildRemoved, this)));
}
void InspectorControlView::OnClosingPresentation()
{
- // Image chooser model needs to be rebuilt from scratch for each presentation, as different
- // presentations count as subpresentations
+ // Image chooser model needs to be deleted, because otherwise it'll try to update the model for
+ // the new presentation before subpresentations are resolved, corrupting the model.
+ // The model also has a connection to project file which needs to refreshed if project changes.
delete m_imageChooserView;
m_fileList.clear();
+ m_connections.clear();
}
void InspectorControlView::OnTimeChanged()
@@ -302,6 +328,31 @@ void InspectorControlView::onInstancePropertyValueChanged(
}
}
+void InspectorControlView::onChildAdded(int inChild)
+{
+ // Changes to asset graph invalidate the object browser model, so close it if it is open
+ if (m_activeBrowser.isActive() && m_activeBrowser.m_browser == m_objectReferenceView)
+ m_activeBrowser.clear();
+
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+ if (bridge->IsCustomMaterialInstance(inChild)) {
+ QVector<qt3dsdm::Qt3DSDMInstanceHandle> refMats;
+ doc->getSceneReferencedMaterials(doc->GetSceneInstance(), refMats);
+ for (auto &refMat : qAsConst(refMats)) {
+ if ((int)bridge->getMaterialReference(refMat) == inChild)
+ g_StudioApp.GetCore()->GetDispatch()->FireImmediateRefreshInstance(refMat);
+ }
+ }
+}
+
+void InspectorControlView::onChildRemoved()
+{
+ // Changes to asset graph invalidate the object browser model, so close it if it is open
+ if (m_activeBrowser.isActive() && m_activeBrowser.m_browser == m_objectReferenceView)
+ m_activeBrowser.clear();
+}
+
QColor InspectorControlView::titleColor(int instance, int handle) const
{
QColor ret = CStudioPreferences::textColor();
@@ -338,16 +389,11 @@ void InspectorControlView::updateInspectable(CInspectableBase *inInspectable)
void InspectorControlView::setInspectable(CInspectableBase *inInspectable)
{
if (m_inspectableBase != inInspectable) {
+ m_activeBrowser.clear();
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::onInstancePropertyValueChanged, this,
- std::placeholders::_2));
- m_timeChanged = sp->ConnectComponentSeconds(
- std::bind(&InspectorControlView::OnTimeChanged, this));
}
}
@@ -445,6 +491,7 @@ QObject *InspectorControlView::showImageChooser(int handle, int instance, const
m_imageChooserView->setInstance(instance);
CDialogs::showWidgetBrowser(this, m_imageChooserView, point);
+ m_activeBrowser.setData(m_imageChooserView, handle, instance);
return m_imageChooserView;
}
@@ -463,29 +510,25 @@ QObject *InspectorControlView::showFilesChooser(int handle, int instance, const
m_fileChooserView->setInstance(instance);
CDialogs::showWidgetBrowser(this, m_fileChooserView, point);
+ m_activeBrowser.setData(m_fileChooserView, handle, instance);
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 (name.startsWith(QStringLiteral("#"))) {
- if (m_inspectorControlModel)
- m_inspectorControlModel->setPropertyValue(instance, handle, name);
- } else {
- setPropertyValueFromFilename(instance, handle, name);
- }
- });
- }
-
m_meshChooserView->setHandle(handle);
m_meshChooserView->setInstance(instance);
- CDialogs::showWidgetBrowser(this, m_meshChooserView, point);
+ m_activeBrowser.setData(m_meshChooserView, handle, instance);
+ int numPrimitives = BasicObjectsModel::BasicMeshesModel().count();
+ bool combo = numPrimitives == m_meshChooserView->numMeshes(); // make a combobox size popup
+ int comboH = qMin(m_meshChooserView->numMeshes(), 15) // max popup height: 15 items
+ * CStudioPreferences::controlBaseHeight();
+
+ CDialogs::showWidgetBrowser(this, m_meshChooserView, point,
+ CDialogs::WidgetBrowserAlign::ComboBox,
+ combo ? QSize(CStudioPreferences::valueWidth(), comboH) : QSize());
return m_meshChooserView;
}
@@ -505,6 +548,7 @@ QObject *InspectorControlView::showTextureChooser(int handle, int instance, cons
m_textureChooserView->setInstance(instance);
CDialogs::showWidgetBrowser(this, m_textureChooserView, point);
+ m_activeBrowser.setData(m_textureChooserView, handle, instance);
return m_textureChooserView;
}
@@ -546,6 +590,7 @@ QObject *InspectorControlView::showObjectReference(int handle, int instance, con
}
CDialogs::showWidgetBrowser(this, m_objectReferenceView, point);
+ m_activeBrowser.setData(m_objectReferenceView, handle, instance);
connect(m_objectReferenceView, &ObjectBrowserView::selectionChanged,
this, [this, doc, handle, instance] {
@@ -553,8 +598,11 @@ QObject *InspectorControlView::showObjectReference(int handle, int instance, con
qt3dsdm::SObjectRefType objRef = doc->GetDataModelObjectReferenceHelper()->GetAssetRefValue(
selectedItem, instance,
(CRelativePathTools::EPathType)(m_objectReferenceView->pathType()));
- Q3DStudio::SCOPED_DOCUMENT_EDITOR(*doc, QObject::tr("Set Property"))
- ->SetInstancePropertyValue(instance, handle, objRef);
+ qt3dsdm::SValue value = m_inspectorControlModel->currentPropertyValue(instance, handle);
+ if (!(value.getData<qt3dsdm::SObjectRefType>() == objRef)) {
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*doc, QObject::tr("Set Property"))
+ ->SetInstancePropertyValue(instance, handle, objRef);
+ }
});
return m_objectReferenceView;
@@ -569,24 +617,20 @@ QObject *InspectorControlView::showMaterialReference(int handle, int instance, c
disconnect(m_matRefListWidget, &QListWidget::itemClicked, nullptr, nullptr);
disconnect(m_matRefListWidget, &QListWidget::itemDoubleClicked, nullptr, nullptr);
- CDoc *doc = g_StudioApp.GetCore()->GetDoc();
- const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
-
- qt3dsdm::SValue value;
- propertySystem->GetInstancePropertyValue(instance, handle, value);
-
- const int numMats = m_matRefListWidget->refreshMaterials(
- doc->GetDataModelObjectReferenceHelper()->Resolve(value, instance));
+ const int numMats = m_matRefListWidget->refreshMaterials(instance, handle);
const int popupHeight = qMin(numMats, 10) * CStudioPreferences::controlBaseHeight();
CDialogs::showWidgetBrowser(this, m_matRefListWidget, point,
CDialogs::WidgetBrowserAlign::ComboBox,
QSize(CStudioPreferences::valueWidth(), popupHeight));
+ m_activeBrowser.setData(m_matRefListWidget, handle, instance);
connect(m_matRefListWidget, &QListWidget::itemClicked, this,
- [doc, propertySystem, instance, handle](QListWidgetItem *item) {
+ [instance, handle](QListWidgetItem *item) {
auto selectedInstance = item->data(Qt::UserRole).toInt();
qt3dsdm::SValue value;
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
propertySystem->GetInstancePropertyValue(instance, handle, value);
auto refInstance = doc->GetDataModelObjectReferenceHelper()->Resolve(value, instance);
if (selectedInstance != refInstance) {
@@ -636,6 +680,7 @@ void InspectorControlView::showDataInputChooser(int handle, int instance, const
handle, instance);
CDialogs::showWidgetBrowser(this, m_dataInputChooserView, point,
CDialogs::WidgetBrowserAlign::ToolButton);
+ m_activeBrowser.setData(m_dataInputChooserView, handle, instance);
}
QColor InspectorControlView::showColorDialog(const QColor &color)
@@ -669,7 +714,6 @@ QString InspectorControlView::convertPathToProjectRoot(const QString &presentati
void InspectorControlView::OnBeginDataModelNotifications()
{
-
}
void InspectorControlView::OnEndDataModelNotifications()
@@ -678,6 +722,42 @@ void InspectorControlView::OnEndDataModelNotifications()
if (inspectable && !inspectable->IsValid())
OnSelectionSet(Q3DStudio::SSelectedValue());
m_inspectorControlModel->refresh();
+
+ if (m_activeBrowser.isActive()) {
+ // Check if the instance/handle pair still has an active UI control. If not, close browser.
+ if (!m_inspectorControlModel->hasInstanceProperty(
+ m_activeBrowser.m_instance, m_activeBrowser.m_handle)) {
+ m_activeBrowser.clear();
+ } else {
+ // Update browser selection
+ if (m_activeBrowser.m_browser == m_imageChooserView) {
+ m_imageChooserView->updateSelection();
+ } else if (m_activeBrowser.m_browser == m_fileChooserView) {
+ m_fileChooserView->updateSelection();
+ } else if (m_activeBrowser.m_browser == m_meshChooserView) {
+ m_meshChooserView->updateSelection();
+ } else if (m_activeBrowser.m_browser == m_textureChooserView) {
+ m_textureChooserView->updateSelection();
+ } else if (m_activeBrowser.m_browser == m_objectReferenceView) {
+ IObjectReferenceHelper *objRefHelper
+ = g_StudioApp.GetCore()->GetDoc()->GetDataModelObjectReferenceHelper();
+ if (objRefHelper) {
+ qt3dsdm::SValue value = m_inspectorControlModel->currentPropertyValue(
+ m_activeBrowser.m_instance, m_activeBrowser.m_handle);
+ qt3dsdm::Qt3DSDMInstanceHandle refInstance
+ = objRefHelper->Resolve(value, m_activeBrowser.m_instance);
+ m_objectReferenceView->selectAndExpand(refInstance, m_activeBrowser.m_instance);
+ }
+ } else if (m_activeBrowser.m_browser == m_matRefListWidget) {
+ m_matRefListWidget->updateSelection();
+ } else if (m_activeBrowser.m_browser == m_dataInputChooserView) {
+ m_dataInputChooserView->setCurrentController(
+ m_inspectorControlModel->currentControllerValue(
+ m_dataInputChooserView->instance(),
+ m_dataInputChooserView->handle()));
+ }
+ }
+ }
}
void InspectorControlView::OnImmediateRefreshInstanceSingle(qt3dsdm::Qt3DSDMInstanceHandle inInstance)
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h
index a5661d74..6cb7fd21 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h
@@ -120,11 +120,10 @@ private:
bool canOpenInInspector(int instance, int handle) const;
void openInInspector();
void onInstancePropertyValueChanged(qt3dsdm::Qt3DSDMPropertyHandle propertyHandle);
+ void onChildAdded(int inChild);
+ void onChildRemoved();
- std::shared_ptr<qt3dsdm::ISignalConnection> m_selectionChangedConnection;
- std::shared_ptr<qt3dsdm::ISignalConnection> m_timeChanged;
- std::shared_ptr<qt3dsdm::ISignalConnection> m_DirectoryConnection;
- std::shared_ptr<qt3dsdm::ISignalConnection> m_PropertyChangeConnection;
+ std::vector<std::shared_ptr<qt3dsdm::ISignalConnection>> m_connections;
QColor m_backgroundColor;
InspectorControlModel *m_inspectorControlModel = nullptr;
CInspectableBase *m_inspectableBase = nullptr;
@@ -144,6 +143,35 @@ private:
QSize m_preferredSize;
QColor m_currentColor;
+
+ class ActiveBrowserData
+ {
+ public:
+ void setData(QWidget *browser, int handle, int instance)
+ {
+ m_browser = browser;
+ m_handle = handle;
+ m_instance = instance;
+ }
+ void clear()
+ {
+ if (isActive())
+ m_browser->close();
+ m_browser.clear();
+ m_handle = -1;
+ m_instance = -1;
+ }
+ bool isActive() const
+ {
+ return !m_browser.isNull() && m_browser->isVisible();
+ }
+
+ QPointer<QWidget> m_browser = nullptr;
+ int m_handle = -1;
+ int m_instance = -1;
+ };
+
+ ActiveBrowserData m_activeBrowser;
};
#endif // INSPECTORCONTROLVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/MaterialRefView.cpp b/src/Authoring/Studio/Palettes/Inspector/MaterialRefView.cpp
index 66a9f8b9..10fdedd5 100644
--- a/src/Authoring/Studio/Palettes/Inspector/MaterialRefView.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/MaterialRefView.cpp
@@ -48,14 +48,19 @@ MaterialRefView::MaterialRefView(QWidget *parent)
/**
* Gather and display the currently used standard and custom material list
*
- * @param refInstance referenced material instance of the currently selected reference material
+ * @param instance The instance that owns the property handle
+ * @param handle The property handle this materials list is for
*
* @return number of items in the list
*/
-int MaterialRefView::refreshMaterials(qt3dsdm::Qt3DSDMInstanceHandle refInstance)
+int MaterialRefView::refreshMaterials(int instance, int handle)
{
clear(); // clear old material list
+ m_instance = instance;
+ m_handle = handle;
+ qt3dsdm::Qt3DSDMInstanceHandle refInstance = getRefInstance();
+
CDoc *doc = g_StudioApp.GetCore()->GetDoc();
const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
@@ -91,11 +96,33 @@ int MaterialRefView::refreshMaterials(qt3dsdm::Qt3DSDMInstanceHandle refInstance
return (int)mats.size();
}
+void MaterialRefView::updateSelection()
+{
+ int refInstance = getRefInstance();
+ for (int i = 0, itemCount = count(); i < itemCount; ++i) {
+ int matInstance = item(i)->data(Qt::UserRole).toInt();
+ if (matInstance == refInstance) {
+ setCurrentRow(i);
+ break;
+ }
+ }
+}
+
bool MaterialRefView::isFocused() const
{
return hasFocus();
}
+int MaterialRefView::getRefInstance() const
+{
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+
+ qt3dsdm::SValue value;
+ propertySystem->GetInstancePropertyValue(m_instance, m_handle, value);
+ return doc->GetDataModelObjectReferenceHelper()->Resolve(value, m_instance);
+}
+
void MaterialRefView::focusInEvent(QFocusEvent *event)
{
QAbstractItemView::focusInEvent(event);
diff --git a/src/Authoring/Studio/Palettes/Inspector/MaterialRefView.h b/src/Authoring/Studio/Palettes/Inspector/MaterialRefView.h
index 8a8d3f0b..157b9a6b 100644
--- a/src/Authoring/Studio/Palettes/Inspector/MaterialRefView.h
+++ b/src/Authoring/Studio/Palettes/Inspector/MaterialRefView.h
@@ -40,8 +40,9 @@ class MaterialRefView : public QListWidget
public:
explicit MaterialRefView(QWidget *parent = nullptr);
- int refreshMaterials(qt3dsdm::Qt3DSDMInstanceHandle refInstance);
+ int refreshMaterials(int instance, int handle);
+ void updateSelection();
protected:
void focusInEvent(QFocusEvent *event) override;
void focusOutEvent(QFocusEvent *event) override;
@@ -51,6 +52,10 @@ Q_SIGNALS:
private:
bool isFocused() const;
+ int getRefInstance() const;
+
+ int m_instance = -1;
+ int m_handle = -1;
};
#endif // MATERIALREFVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/MeshChooser.qml b/src/Authoring/Studio/Palettes/Inspector/MeshChooser.qml
index 0d9e15eb..fcaf498c 100644
--- a/src/Authoring/Studio/Palettes/Inspector/MeshChooser.qml
+++ b/src/Authoring/Studio/Palettes/Inspector/MeshChooser.qml
@@ -47,7 +47,6 @@ Rectangle {
Layout.margins: 4
boundsBehavior: Flickable.StopAtBounds
- spacing: 4
clip: true
ScrollBar.vertical: ScrollBar {}
@@ -55,7 +54,9 @@ Rectangle {
model: _meshChooserModel
delegate: ChooserDelegate {
- onClicked: _meshChooserView.setSelectedMeshName(filePath);
+ onClicked: {
+ _meshChooserView.setSelectedMeshName(filePath);
+ }
onDoubleClicked: {
_meshChooserView.setSelectedMeshName(filePath);
_meshChooserView.hide();
diff --git a/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.cpp b/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.cpp
index 177861c0..521c2fa9 100644
--- a/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.cpp
@@ -64,9 +64,9 @@ void MeshChooserView::initialize()
setSource(QUrl(QStringLiteral("qrc:/Palettes/Inspector/MeshChooser.qml")));
}
-QSize MeshChooserView::sizeHint() const
+int MeshChooserView::numMeshes() const
{
- return {500, 500};
+ return m_model->rowCount();
}
void MeshChooserView::setSelectedMeshName(const QString &name)
@@ -96,6 +96,25 @@ void MeshChooserView::setInstance(int instance)
m_instance = instance;
}
+void MeshChooserView::updateSelection()
+{
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+
+ qt3dsdm::SValue value;
+ propertySystem->GetInstancePropertyValue(m_instance, m_handle, value);
+
+ QString currentFile;
+ const QString meshValue = qt3dsdm::get<QString>(value);
+ if (meshValue.startsWith(QLatin1Char('#'))) {
+ currentFile = meshValue.mid(1);
+ } else {
+ currentFile = QDir::cleanPath(QDir(doc->GetDocumentDirectory()).filePath(meshValue));
+ }
+
+ m_model->setCurrentFile(currentFile);
+}
+
bool MeshChooserView::isFocused() const
{
return hasFocus();
@@ -124,20 +143,6 @@ void MeshChooserView::keyPressEvent(QKeyEvent *event)
void MeshChooserView::showEvent(QShowEvent *event)
{
- const auto doc = g_StudioApp.GetCore()->GetDoc();
- const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
-
- qt3dsdm::SValue value;
- propertySystem->GetInstancePropertyValue(m_instance, m_handle, value);
-
- QString currentFile;
- const QString meshValue = qt3dsdm::get<QString>(value);
- if (meshValue.startsWith(QLatin1Char('#')))
- currentFile = meshValue.mid(1);
- else
- currentFile = QDir::cleanPath(QDir(doc->GetDocumentDirectory()).filePath(meshValue));
-
- m_model->setCurrentFile(currentFile);
-
+ updateSelection();
QQuickWidget::showEvent(event);
}
diff --git a/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.h b/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.h
index fb4673a6..6d12cf14 100644
--- a/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.h
+++ b/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.h
@@ -36,8 +36,10 @@ class CFilePath;
class CString;
}
-QT_FORWARD_DECLARE_CLASS(QAbstractItemModel)
class MeshChooserModel;
+
+QT_FORWARD_DECLARE_CLASS(QAbstractItemModel)
+
class MeshChooserView : public QQuickWidget
{
Q_OBJECT
@@ -46,12 +48,13 @@ class MeshChooserView : public QQuickWidget
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);
+ int numMeshes() const;
+
+ void updateSelection();
Q_SIGNALS:
void meshSelected(int handle, int instance, const QString &name);
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp
index 8c531c5b..0b6db847 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp
@@ -27,13 +27,10 @@
****************************************************************************/
#include "ObjectBrowserView.h"
-#include <QtGui/qcolor.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>
@@ -63,12 +60,6 @@ void ObjectBrowserView::setModel(ObjectListModel *model)
Q_EMIT modelChanged();
}
-
-QSize ObjectBrowserView::sizeHint() const
-{
- return {500, 500};
-}
-
QString ObjectBrowserView::absPath(int index) const
{
return m_model->index(index, 0).data(ObjectListModel::AbsolutePathRole).toString();
@@ -97,7 +88,9 @@ void ObjectBrowserView::selectAndExpand(const qt3dsdm::Qt3DSDMInstanceHandle &ha
if (!index.isValid())
return;
m_model->expandTo(QModelIndex(), index);
+ m_blockCommit = true;
setSelection(m_model->rowForSourceIndex(index));
+ m_blockCommit = false;
}
void ObjectBrowserView::setSelection(int index)
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.h b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.h
index bfe4af58..7fb7ec30 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.h
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.h
@@ -60,7 +60,6 @@ public:
QAbstractItemModel *model() const;
void setModel(ObjectListModel *model);
- QSize sizeHint() const override;
Q_INVOKABLE QString absPath(int index) const;
Q_INVOKABLE QString relPath(int index) const;
@@ -77,6 +76,8 @@ public:
qt3dsdm::Qt3DSDMInstanceHandle selectedHandle() const;
+ bool canCommit() const { return !m_blockCommit; }
+
Q_SIGNALS:
void modelChanged();
void pathTypeChanged();
@@ -101,6 +102,7 @@ private:
int m_selection = -1;
PathType m_pathType = Absolute;
qt3dsdm::Qt3DSDMInstanceHandle m_ownerInstance = 0;
+ bool m_blockCommit = false;
};
#endif // OBJECTBROWSERVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.cpp b/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.cpp
index 16a36787..d06d15ba 100644
--- a/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.cpp
@@ -63,11 +63,6 @@ void TextureChooserView::initialize()
setSource(QUrl(QStringLiteral("qrc:/Palettes/Inspector/TextureChooser.qml")));
}
-QSize TextureChooserView::sizeHint() const
-{
- return {500, 500};
-}
-
void TextureChooserView::setHandle(int handle)
{
m_handle = handle;
@@ -109,6 +104,11 @@ QString TextureChooserView::currentDataModelPath() const
return cleanPath;
}
+void TextureChooserView::updateSelection()
+{
+ m_model->setCurrentFile(currentDataModelPath());
+}
+
void TextureChooserView::focusOutEvent(QFocusEvent *event)
{
QQuickWidget::focusOutEvent(event);
@@ -125,7 +125,6 @@ void TextureChooserView::keyPressEvent(QKeyEvent *event)
void TextureChooserView::showEvent(QShowEvent *event)
{
- m_model->setCurrentFile(currentDataModelPath());
-
+ updateSelection();
QQuickWidget::showEvent(event);
}
diff --git a/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.h b/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.h
index d4ed0abf..156b2465 100644
--- a/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.h
+++ b/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.h
@@ -42,8 +42,6 @@ class TextureChooserView : public QQuickWidget
public:
explicit TextureChooserView(QWidget *parent = nullptr);
- QSize sizeHint() const override;
-
void setHandle(int handle);
int handle() const;
@@ -51,6 +49,8 @@ public:
int instance() const;
QString currentDataModelPath() const;
+ void updateSelection();
+
Q_SIGNALS:
void textureSelected(int handle, int instance, const QString &name);
diff --git a/src/Authoring/Studio/Palettes/PaletteManager.cpp b/src/Authoring/Studio/Palettes/PaletteManager.cpp
index 0a696363..f83a5df6 100644
--- a/src/Authoring/Studio/Palettes/PaletteManager.cpp
+++ b/src/Authoring/Studio/Palettes/PaletteManager.cpp
@@ -40,7 +40,6 @@
#include "InspectorControlView.h"
#include "ActionView.h"
#include "IDragable.h"
-#include "ActionView.h"
#include "ProjectView.h"
#include "TabOrderHandler.h"
#include "StudioPreferences.h"
diff --git a/src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.cpp b/src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.cpp
index 09e1da37..323a6ed1 100644
--- a/src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.cpp
+++ b/src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.cpp
@@ -57,6 +57,14 @@ EditPresentationIdDlg::EditPresentationIdDlg(const QString &src, DialogType type
m_ui->label->setText(tr("Qml Stream Name"));
setWindowTitle(tr("Rename Qml Stream"));
break;
+ case DuplicatePresentation:
+ m_ui->label->setText(tr("Presentation Name"));
+ setWindowTitle(tr("Duplicate Presentation"));
+ break;
+ case DuplicateQmlStream:
+ m_ui->label->setText(tr("Qml Stream Name"));
+ setWindowTitle(tr("Duplicate Qml Stream"));
+ break;
default:
break;
}
@@ -66,7 +74,10 @@ EditPresentationIdDlg::EditPresentationIdDlg(const QString &src, DialogType type
m_ui->lineEditPresentationId->setText(m_presentationId);
} else {
QFileInfo fi(src);
- m_ui->lineEditPresentationId->setText(fi.fileName());
+ QString initialText = fi.completeBaseName();
+ if (m_dialogType == DuplicatePresentation || m_dialogType == DuplicateQmlStream)
+ initialText = g_StudioApp.GetCore()->getProjectFile().getUniquePresentationName(src);
+ m_ui->lineEditPresentationId->setText(initialText);
}
window()->setFixedSize(size());
@@ -103,7 +114,19 @@ void EditPresentationIdDlg::accept()
newValue.prepend(m_src.left(slashIndex + 1));
if (newValue != m_src) {
- if (g_StudioApp.GetCore()->getProjectFile().renamePresentationFile(m_src, newValue))
+ bool success = false;
+ if (m_dialogType == DuplicatePresentation || m_dialogType == DuplicateQmlStream) {
+ success = g_StudioApp.GetCore()->getProjectFile().duplicatePresentation(
+ m_src, newValue);
+ if (success) {
+ m_duplicateFile = g_StudioApp.GetCore()->getProjectFile()
+ .getAbsoluteFilePathTo(newValue);
+ }
+ } else {
+ success = g_StudioApp.GetCore()->getProjectFile().renamePresentationFile(
+ m_src, newValue);
+ }
+ if (success)
QDialog::accept();
else
displayWarning(UniqueWarning);
@@ -117,6 +140,10 @@ void EditPresentationIdDlg::accept()
void EditPresentationIdDlg::displayWarning(WarningType warningType)
{
QString warning;
+ QString uniqueFileNote;
+ if (warningType == UniqueWarning)
+ uniqueFileNote = tr("The new name must be unique within its folder and a valid filename.");
+
switch (m_dialogType) {
// Presentation Id warnings are also displayed from preferences dialog, so they are handled
// by CStudioApp.
@@ -136,15 +163,25 @@ void EditPresentationIdDlg::displayWarning(WarningType warningType)
if (warningType == EmptyWarning)
warning = tr("Presentation name must not be empty.");
else
- warning = tr("Renaming presentation failed.\n"
- "The new name must be unique within its folder and a valid filename.");
+ warning = tr("Renaming presentation failed.\n") + uniqueFileNote;
break;
case EditQmlStreamName:
if (warningType == EmptyWarning)
warning = tr("Qml stream name must not be empty.");
else
- warning = tr("Renaming Qml stream failed.\n"
- "The new name must be unique within its folder and a valid filename.");
+ warning = tr("Renaming Qml stream failed.\n") + uniqueFileNote;
+ break;
+ case DuplicatePresentation:
+ if (warningType == EmptyWarning)
+ warning = tr("Presentation name must not be empty.");
+ else
+ warning = tr("Duplicating presentation failed.\n") + uniqueFileNote;
+ break;
+ case DuplicateQmlStream:
+ if (warningType == EmptyWarning)
+ warning = tr("Qml stream name must not be empty.");
+ else
+ warning = tr("Duplicating Qml stream failed.\n") + uniqueFileNote;
break;
default:
break;
diff --git a/src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.h b/src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.h
index 67607710..30bfccbd 100644
--- a/src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.h
+++ b/src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.h
@@ -50,13 +50,17 @@ public:
EditPresentationId,
EditQmlStreamId,
EditPresentationName,
- EditQmlStreamName
+ EditQmlStreamName,
+ DuplicatePresentation,
+ DuplicateQmlStream
};
explicit EditPresentationIdDlg(const QString &src, DialogType type = EditPresentationId,
QWidget *parent = nullptr);
~EditPresentationIdDlg();
+ QString getDuplicateFile() const { return m_duplicateFile; }
+
public Q_SLOTS:
void accept() override;
@@ -71,6 +75,7 @@ private:
QString m_src; // src attribute value for the current presentation in the project file
QString m_presentationId;
DialogType m_dialogType;
+ QString m_duplicateFile;
};
#endif // EDITPRESENTATIONIDDLG_H
diff --git a/src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.ui b/src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.ui
index a894710c..5253ccb6 100644
--- a/src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.ui
+++ b/src/Authoring/Studio/Palettes/Project/EditPresentationIdDlg.ui
@@ -34,7 +34,7 @@
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QWidget" name="labelEditLayout" native="true">
- <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0">
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0">
<property name="leftMargin">
<number>0</number>
</property>
@@ -54,13 +54,13 @@
</property>
</widget>
</item>
- <item>
- <widget class="QLineEdit" name="lineEditPresentationId"/>
- </item>
</layout>
</widget>
</item>
<item>
+ <widget class="QLineEdit" name="lineEditPresentationId"/>
+ </item>
+ <item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.cpp b/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.cpp
index c2825718..5c985359 100644
--- a/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.cpp
+++ b/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.cpp
@@ -63,6 +63,11 @@ ProjectContextMenu::ProjectContextMenu(ProjectView *parent, int index)
connect(action, &QAction::triggered, this, &ProjectContextMenu::handleEditPresentationId);
addAction(action);
+ action = new QAction(tr("Duplicate Presentation"));
+ connect(action, &QAction::triggered,
+ this, &ProjectContextMenu::handleDuplicatePresentation);
+ addAction(action);
+
static const QIcon iconInitial = QIcon(QStringLiteral(":/images/initial_notUsed.png"));
if (m_view->isInitialPresentation(m_index)) {
@@ -87,6 +92,11 @@ ProjectContextMenu::ProjectContextMenu(ProjectView *parent, int index)
action = new QAction(tr("Edit Qml Stream Id"));
connect(action, &QAction::triggered, this, &ProjectContextMenu::handleEditQmlStreamId);
addAction(action);
+
+ action = new QAction(tr("Duplicate Qml Stream"));
+ connect(action, &QAction::triggered,
+ this, &ProjectContextMenu::handleDuplicatePresentation);
+ addAction(action);
}
if (m_view->isMaterialData(m_index)) {
@@ -195,6 +205,11 @@ void ProjectContextMenu::handleDuplicate()
m_view->duplicate(m_index);
}
+void ProjectContextMenu::handleDuplicatePresentation()
+{
+ m_view->duplicatePresentation(m_index);
+}
+
void ProjectContextMenu::handleInitialPresentation()
{
m_view->setInitialPresentation(m_index);
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.h b/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.h
index 9ed0e8fd..12cd2367 100644
--- a/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.h
+++ b/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.h
@@ -51,6 +51,7 @@ private Q_SLOTS:
void handleImportAssets();
void handleAddMaterial();
void handleDuplicate();
+ void handleDuplicatePresentation();
void handleInitialPresentation();
void handleRenamePresentation();
void handleRenameQmlStream();
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp
index 559fa16b..0a098a5b 100644
--- a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp
+++ b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp
@@ -248,6 +248,8 @@ void ProjectFileSystemModel::overridableCopyFile(const QString &srcFile, const Q
QFileInfo srcFileInfo(srcFile);
if (srcFileInfo.exists() && addUniqueImportFile(srcFile, outImportedFiles)) {
QFileInfo targetFileInfo(targetFile);
+ if (srcFileInfo == targetFileInfo)
+ return; // Autoskip when source and target is the same
if (!targetFileInfo.dir().exists())
targetFileInfo.dir().mkpath(QStringLiteral("."));
@@ -817,13 +819,9 @@ void ProjectFileSystemModel::importUrl(QDir &targetDir, const QUrl &url,
bool copyResult = SFileTools::FindAndCopyDestFile(targetDir, sourceFile, destPath);
Q_ASSERT(copyResult);
+ QString presentationPath;
if (CDialogs::isPresentationFileExtension(extension)) {
- // Don't override id with empty if it is already added, which can happen when
- // multi-importing both presentation and its subpresentation
- const QString presPath
- = doc->GetCore()->getProjectFile().getRelativeFilePathTo(destPath);
- if (!outPresentationNodes.contains(presPath))
- outPresentationNodes.insert(presPath, {});
+ presentationPath = doc->GetCore()->getProjectFile().getRelativeFilePathTo(destPath);
QSet<QString> dataInputs;
importPresentationAssets(fileInfo, QFileInfo(destPath), outPresentationNodes,
outImportedFiles, dataInputs, outOverrideChoice);
@@ -835,14 +833,36 @@ void ProjectFileSystemModel::importUrl(QDir &targetDir, const QUrl &url,
outDataInputs.insert(di, allDataInputs[di]);
}
} else if (qmlRoot && isQmlStream) { // importing a qml stream
- const QString presPath
- = doc->GetCore()->getProjectFile().getRelativeFilePathTo(destPath);
- if (!outPresentationNodes.contains(presPath))
- outPresentationNodes.insert(presPath, {});
+ presentationPath = doc->GetCore()->getProjectFile().getRelativeFilePathTo(destPath);
importQmlAssets(qmlRoot, fileInfo.dir(), targetDir, outImportedFiles,
outOverrideChoice);
}
+ // outPresentationNodes can already contain this presentation in case of multi-importing
+ // both a presentation and its subpresentation
+ if (!presentationPath.isEmpty() && !outPresentationNodes.contains(presentationPath)) {
+ const QString srcProjFile = PresentationFile::findProjectFile(sourceFile);
+ QString presId;
+ if (!srcProjFile.isEmpty()) {
+ QVector<SubPresentationRecord> subpresentations;
+ ProjectFile::getPresentations(srcProjFile, subpresentations);
+ QDir srcProjDir(QFileInfo(srcProjFile).path());
+ const QString relSrcPresFilePath = srcProjDir.relativeFilePath(sourceFile);
+ auto *sp = std::find_if(
+ subpresentations.begin(), subpresentations.end(),
+ [&relSrcPresFilePath](const SubPresentationRecord &spr) -> bool {
+ return spr.m_argsOrSrc == relSrcPresFilePath;
+ });
+ // Make sure we are not adding a duplicate id. In that case presId will be empty
+ // which causes autogeneration of an unique id.
+ if (sp != subpresentations.end()
+ && g_StudioApp.GetCore()->getProjectFile().isUniquePresentationId(sp->m_id)) {
+ presId = sp->m_id;
+ }
+ }
+ outPresentationNodes.insert(presentationPath, presId);
+ }
+
// For effect and custom material files, automatically copy related resources
if (CDialogs::IsEffectFileExtension(extension)
|| CDialogs::IsMaterialFileExtension(extension)) {
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectView.cpp b/src/Authoring/Studio/Palettes/Project/ProjectView.cpp
index 8997dd34..5aaee7d0 100644
--- a/src/Authoring/Studio/Palettes/Project/ProjectView.cpp
+++ b/src/Authoring/Studio/Palettes/Project/ProjectView.cpp
@@ -501,6 +501,11 @@ void ProjectView::duplicate(int row) const
m_ProjectModel->duplicate(row);
}
+void ProjectView::duplicatePresentation(int row) const
+{
+ g_StudioApp.duplicatePresentation(m_ProjectModel->filePath(row));
+}
+
void ProjectView::deleteFile(int row) const
{
if (isReferenced(row)) {
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectView.h b/src/Authoring/Studio/Palettes/Project/ProjectView.h
index e2055014..7533e677 100644
--- a/src/Authoring/Studio/Palettes/Project/ProjectView.h
+++ b/src/Authoring/Studio/Palettes/Project/ProjectView.h
@@ -79,6 +79,7 @@ public:
void addMaterial(int row) const;
void editMaterial(int row) const;
void duplicate(int row) const;
+ void duplicatePresentation(int row) const;
void deleteFile(int row) const;
bool isRefreshable(int row) const;
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.cpp b/src/Authoring/Studio/Palettes/Slide/SlideView.cpp
index c4a1d135..5bb5aa67 100644
--- a/src/Authoring/Studio/Palettes/Slide/SlideView.cpp
+++ b/src/Authoring/Studio/Palettes/Slide/SlideView.cpp
@@ -386,6 +386,8 @@ void SlideView::updateDataInputStatus()
// update UI
UpdateSlideViewTitleColor();
Q_EMIT controlledChanged();
+ if (m_dataInputSelector && m_dataInputSelector->isVisible())
+ m_dataInputSelector->setCurrentController(m_currentController);
}
}
void SlideView::initialize()
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.qml b/src/Authoring/Studio/Palettes/Slide/SlideView.qml
index 5661f162..c8f409d0 100644
--- a/src/Authoring/Studio/Palettes/Slide/SlideView.qml
+++ b/src/Authoring/Studio/Palettes/Slide/SlideView.qml
@@ -37,10 +37,9 @@ Rectangle {
readonly property bool masterSlide: _parentView.showMasterSlide
- function handleMouseClicks(mouse) {
+ function handleMouseClicks(mouse, mappedCoords) {
if (mouse.button === Qt.RightButton) {
- const coords = slideList.mapToItem(root, mouse.x, mouse.y);
- _parentView.showContextMenu(coords.x, coords.y, -1);
+ _parentView.showContextMenu(mappedCoords.x, mappedCoords.y, -1);
} else {
root.focus = true;
//Unselect All element when we click outside slider item in listView.
@@ -75,7 +74,10 @@ Rectangle {
propagateComposedEvents: true
acceptedButtons: Qt.AllButtons
- onClicked: root.handleMouseClicks(mouse)
+ onClicked: {
+ const coords = mapToItem(root, mouse.x, mouse.y);
+ root.handleMouseClicks(mouse, coords);
+ }
Column {
id: masterButtonColumn
@@ -177,10 +179,12 @@ Rectangle {
z: -1 // Only reached when clicking outside delegates
acceptedButtons: Qt.AllButtons
onClicked: {
- if (slideList.indexAt(mouse.x, mouse.y) === -1)
- root.handleMouseClicks(mouse);
- else
+ if (slideList.indexAt(mouse.x, mouse.y) === -1) {
+ const coords = mapToItem(root, mouse.x, mouse.y);
+ root.handleMouseClicks(mouse, coords);
+ } else {
mouse.accepted = false;
+ }
}
onPressed: {
if (slideList.indexAt(mouse.x, mouse.y) !== -1)
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp
index 14b1a0ef..936d60ae 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp
@@ -159,8 +159,10 @@ void KeyframeManager::commitMoveSelectedKeyframes()
{
CDoc *theDoc = g_StudioApp.GetCore()->GetDoc();
COffsetKeyframesCommandHelper h(*theDoc);
- for (Keyframe *keyframe : qAsConst(m_selectedKeyframes))
- keyframe->binding->UpdateKeyframesTime(&h, keyframe->time * 1000);
+ for (Keyframe *keyframe : qAsConst(m_selectedKeyframes)) {
+ const long msTime = round(keyframe->time * 1000);
+ keyframe->binding->UpdateKeyframesTime(&h, msTime);
+ }
}
void KeyframeManager::selectKeyframesInRect(const QRectF &rect)
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp
index 82ddfb51..e8c6730a 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp
@@ -339,6 +339,7 @@ TimelineGraphicsScene::~TimelineGraphicsScene()
{
disconnect(qApp, &QApplication::focusChanged,
this, &TimelineGraphicsScene::handleApplicationFocusLoss);
+ delete m_dataInputSelector;
}
void TimelineGraphicsScene::setTimelineScale(int scl)
@@ -1071,6 +1072,43 @@ void TimelineGraphicsScene::handleApplicationFocusLoss()
m_timebarToolTip->hide();
}
+void TimelineGraphicsScene::handleShowDISelector(const QString &propertyname,
+ qt3dsdm::Qt3DSDMInstanceHandle inInst,
+ const QPoint &pos)
+{
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ qt3dsdm::Qt3DSDMPropertyHandle propHandle = doc->GetPropertySystem()
+ ->GetAggregateInstancePropertyByName(inInst, propertyname);
+
+ QVector<EDataType> allowedTypes = CDataInputDlg::getAcceptedTypes(
+ doc->GetPropertySystem()->GetDataType(propHandle));
+
+ // Instantiate selector in TimelineGraphicsScene instead of the originating context menu,
+ // as context menu gets destructed when a selection is made.
+ if (!m_dataInputSelector)
+ m_dataInputSelector = new DataInputSelectView(allowedTypes, widgetTimeline());
+
+ QVector<QPair<QString, int>> dataInputList;
+ for (auto &it : qAsConst(g_StudioApp.m_dataInputDialogItems))
+ dataInputList.append({it->name, it->type});
+ // needs to be set just in case we are reusing an existing datainput selector instance
+ m_dataInputSelector->setMatchingTypes(allowedTypes);
+ m_dataInputSelector->setTypeFilter(DataInputTypeFilter::MatchingTypes);
+ m_dataInputSelector->setData(dataInputList, m_dataInputSelector->getNoneString(),
+ propHandle, inInst);
+ m_dataInputSelector->setCurrentController(doc->GetCurrentController(inInst, propHandle));
+
+ connect(m_dataInputSelector, &DataInputSelectView::dataInputChanged,
+ [&](int handle, int instance, const QString &controllerName) {
+ bool controlled = controllerName != m_dataInputSelector->getNoneString();
+ g_StudioApp.GetCore()->GetDoc()
+ ->SetInstancePropertyControlled(instance, {}, handle,
+ controllerName, controlled);
+ });
+
+ CDialogs::showWidgetBrowser(widgetTimeline(), m_dataInputSelector, pos);
+}
+
// Getters
Ruler *TimelineGraphicsScene::ruler() const { return m_ruler; }
PlayHead *TimelineGraphicsScene::playHead() const { return m_playHead; }
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h
index 11365cf2..e8eda8f3 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h
@@ -35,6 +35,7 @@
#include "RowTypes.h"
#include "TimelineConstants.h"
#include "MouseCursor.h"
+#include "DataInputSelectView.h"
#include <QtWidgets/qgraphicsscene.h>
#include <QtCore/qlist.h>
@@ -92,6 +93,8 @@ public:
void updateAutoScrolling(double scenePosY);
void stopAutoScroll();
QPoint getScrollbarOffsets() const;
+ void handleShowDISelector(const QString &propertyname, qt3dsdm::Qt3DSDMInstanceHandle inInst,
+ const QPoint &pos);
protected:
bool event(QEvent *event) override;
@@ -139,6 +142,8 @@ private:
QList<double> m_snapSteps;
CMouseCursor::Qt3DSMouseCursor m_currentCursor;
TimelineControl *m_timelineControl = nullptr;
+ DataInputSelectView *m_dataInputSelector = nullptr; // triggered by context menu but owned by
+ // rowtree
bool m_rulerPressed = false;
bool m_keyframePressed = false;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
index 08944351..0056d90e 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
@@ -1142,3 +1142,12 @@ void RowTree::setPropertyExpanded(bool expand)
else
animateExpand(ExpandState::Collapsed);
}
+
+void RowTree::showDataInputSelector(const QString &propertyname, const QPoint &pos)
+{
+ m_scene->handleShowDISelector(
+ propertyname, static_cast<Qt3DSDMTimelineItemBinding *>(m_binding)->GetInstance(),
+ pos);
+
+}
+
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h
index e890f414..bde2da48 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h
@@ -98,6 +98,7 @@ public:
void selectLabel();
void togglePropertyExpanded();
void setPropertyExpanded(bool expand);
+ void showDataInputSelector(const QString &propertyname, const QPoint &pos);
ITimelineItemProperty *propBinding();
TreeControlType getClickedControl(const QPointF &scenePos);
bool shy() const;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.cpp
index 821698fa..d6380fc9 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.cpp
@@ -37,6 +37,7 @@
#include "ChooseImagePropertyDlg.h"
#include "Qt3DSDMStudioSystem.h"
#include "ClientDataModelBridge.h"
+#include "qcursor.h"
RowTreeContextMenu::RowTreeContextMenu(RowTree *inRowTree, QWidget *parent)
: QMenu(parent)
@@ -52,6 +53,10 @@ RowTreeContextMenu::~RowTreeContextMenu()
void RowTreeContextMenu::initialize()
{
+ CDoc &doc(*g_StudioApp.GetCore()->GetDoc());
+ qt3dsdm::Qt3DSDMInstanceHandle instance
+ = static_cast<Qt3DSDMTimelineItemBinding *>(m_TimelineItemBinding)->GetInstance();
+
// add sub-presentations submenu
if (m_RowTree->rowType() & (OBJTYPE_LAYER | OBJTYPE_MATERIAL | OBJTYPE_IMAGE)) {
m_subpMenu = addMenu(tr("Set sub-presentation"));
@@ -64,6 +69,36 @@ void RowTreeContextMenu::initialize()
addSeparator();
}
+ // add datainput controller submenu
+ if (!(m_RowTree->rowType() & (OBJTYPE_GUIDE | OBJTYPE_EFFECT | OBJTYPE_ALIAS
+ | OBJTYPE_SCENE))) {
+ m_diMenu = addMenu(tr("Set datainput controller"));
+ connect(m_diMenu, &QMenu::triggered, this, &RowTreeContextMenu::addDiController);
+
+ const QVector<qt3dsdm::Qt3DSDMPropertyHandle> propList
+ = doc.GetStudioSystem()->GetPropertySystem()->GetControllableProperties(instance);
+
+ QMap<int, QAction *> sections;
+ for (const auto &prop : propList) {
+ QAction *action = new QAction(doc.GetPropertySystem()->GetFormalName(instance, prop));
+ action->setData(doc.GetPropertySystem()->GetName(prop));
+
+ auto metadata = doc.GetStudioSystem()->GetActionMetaData()->GetMetaDataPropertyInfo(
+ doc.GetStudioSystem()->GetActionMetaData()->GetMetaDataProperty(
+ instance, prop));
+
+ if (sections.contains(metadata->m_CompleteType) ) {
+ m_diMenu->insertAction(sections[metadata->m_CompleteType], action);
+ } else {
+ // Create a QAction for a section so that we can insert properties above it
+ // to maintain category groupings. Sections are shown as separators in Studio
+ // style i.e. enum text is not shown.
+ QAction *section = m_diMenu->addSection(QString(metadata->m_CompleteType));
+ sections.insert(metadata->m_CompleteType, section);
+ m_diMenu->insertAction(section, action);
+ }
+ }
+ }
m_renameAction = new QAction(tr("Rename Object"), this);
connect(m_renameAction, &QAction::triggered, this, &RowTreeContextMenu::renameObject);
addAction(m_renameAction);
@@ -151,6 +186,8 @@ void RowTreeContextMenu::showEvent(QShowEvent *event)
{
if (m_subpMenu)
m_subpMenu->setEnabled(canAddSubPresentation());
+ if (m_diMenu)
+ m_diMenu->setEnabled(true);
m_renameAction->setEnabled(canRenameObject());
m_duplicateAction->setEnabled(canDuplicateObject());
m_deleteAction->setEnabled(canDeleteObject());
@@ -233,6 +270,11 @@ void RowTreeContextMenu::addSubPresentation(QAction *action)
}
}
+void RowTreeContextMenu::addDiController(QAction *action)
+{
+ m_RowTree->showDataInputSelector(action->data().toString(), QCursor::pos());
+}
+
void RowTreeContextMenu::renameObject()
{
m_RowTree->selectLabel();
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.h
index 69ba8788..0ef87552 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeContextMenu.h
@@ -48,6 +48,7 @@ protected:
private Q_SLOTS:
void addSubPresentation(QAction *action);
+ void addDiController(QAction *action);
void renameObject();
void duplicateObject();
void deleteObject();
@@ -81,6 +82,7 @@ private:
RowTree *m_RowTree;
ITimelineItemBinding *m_TimelineItemBinding;
QMenu *m_subpMenu = nullptr; // sub-presentation submenu
+ QMenu *m_diMenu = nullptr; // datainput submenu
QAction *m_renameAction = nullptr;
QAction *m_duplicateAction = nullptr;
QAction *m_deleteAction = nullptr;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineToolbar.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineToolbar.cpp
index 7b957169..4d80d757 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineToolbar.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineToolbar.cpp
@@ -320,6 +320,8 @@ void TimelineToolbar::updateDataInputStatus()
}
m_diLabel->setText(m_currController);
emit controllerChanged(m_currController);
+ if (m_dataInputSelector && m_dataInputSelector->isVisible())
+ m_dataInputSelector->setCurrentController(m_currController);
}
}
diff --git a/src/Authoring/Studio/Render/IStudioRenderer.h b/src/Authoring/Studio/Render/IStudioRenderer.h
index 67c75a68..dfdc99b8 100644
--- a/src/Authoring/Studio/Render/IStudioRenderer.h
+++ b/src/Authoring/Studio/Render/IStudioRenderer.h
@@ -74,6 +74,8 @@ public:
virtual QT3DSI32 GetEditCamera() const = 0;
virtual void EditCameraZoomToFit() = 0;
+ virtual bool isMouseDown() const = 0;
+
// This must be safe to call from multiple places
virtual void Close() = 0;
diff --git a/src/Authoring/Studio/Render/Q3DStudioRenderer.cpp b/src/Authoring/Studio/Render/Q3DStudioRenderer.cpp
index 52334fdb..c8649ee7 100644
--- a/src/Authoring/Studio/Render/Q3DStudioRenderer.cpp
+++ b/src/Authoring/Studio/Render/Q3DStudioRenderer.cpp
@@ -296,6 +296,12 @@ void Q3DStudioRenderer::EditCameraZoomToFit()
}
+bool Q3DStudioRenderer::isMouseDown() const
+{
+ return m_mouseDown || m_scenePicker->state() == Q3DSScenePicker::Triggered
+ || m_scenePicker->state() == Q3DSScenePicker::Queued;
+}
+
void Q3DStudioRenderer::Close()
{
OnClosingPresentation();
@@ -851,6 +857,8 @@ void Q3DStudioRenderer::OnSceneMouseDown(SceneDragSenderType::Enum inSenderType,
if (m_translation.isNull())
return;
+ m_mouseDown = true;
+
inPoint.setX(int(inPoint.x() * StudioUtils::devicePixelRatio(m_window)));
inPoint.setY(int(inPoint.y() * StudioUtils::devicePixelRatio(m_window)));
@@ -1102,6 +1110,7 @@ void Q3DStudioRenderer::OnSceneMouseDrag(SceneDragSenderType::Enum, QPoint inPoi
void Q3DStudioRenderer::OnSceneMouseUp(SceneDragSenderType::Enum)
{
m_maybeDragStart = false;
+ m_mouseDown = false;
qt3dsdm::Qt3DSDMGuideHandle theSelectedGuide;
if (m_dragPickResult.getType() == StudioPickValueTypes::Guide) {
theSelectedGuide = m_dragPickResult.getData<qt3dsdm::Qt3DSDMGuideHandle>();
diff --git a/src/Authoring/Studio/Render/Q3DStudioRenderer.h b/src/Authoring/Studio/Render/Q3DStudioRenderer.h
index c9db7d42..d7d09e0b 100644
--- a/src/Authoring/Studio/Render/Q3DStudioRenderer.h
+++ b/src/Authoring/Studio/Render/Q3DStudioRenderer.h
@@ -99,6 +99,7 @@ public:
void SetEditCamera(QT3DSI32 inIndex) override;
QT3DSI32 GetEditCamera() const override;
void EditCameraZoomToFit() override;
+ bool isMouseDown() const override;
void Close() override;
void getPreviewFbo(QSize &outFboDim, qt3ds::QT3DSU32 &outFboTexture) override;
void RegisterSubpresentations(
@@ -191,6 +192,7 @@ private:
SStudioPickValue m_dragPickResult;
CUpdateableDocumentEditor m_updatableEditor;
QPoint m_mouseDownPoint;
+ bool m_mouseDown;
QPoint m_previousMousePoint;
MovementTypes m_lastDragToolMode = MovementTypes::Unknown;
bool m_maybeDragStart = false;
diff --git a/src/Authoring/Studio/Render/StudioRenderer.cpp b/src/Authoring/Studio/Render/StudioRenderer.cpp
index 009d32d5..76c5bf30 100644
--- a/src/Authoring/Studio/Render/StudioRenderer.cpp
+++ b/src/Authoring/Studio/Render/StudioRenderer.cpp
@@ -118,6 +118,7 @@ struct SRendererImpl : public IStudioRenderer,
QScopedPointer<Q3DSQmlStreamProxy> m_proxy;
QMap<QString, int> m_initialFrameMap;
bool m_fullSizePreview = false;
+ bool m_mouseDown = false;
SRendererImpl()
: m_Dispatch(*g_StudioApp.GetCore()->GetDispatch())
@@ -408,6 +409,11 @@ struct SRendererImpl : public IStudioRenderer,
}
}
+ bool isMouseDown() const override
+ {
+ return m_mouseDown;
+ }
+
void MakeContextCurrent() override
{
m_RenderContext->BeginRender();
@@ -763,6 +769,7 @@ struct SRendererImpl : public IStudioRenderer,
if (m_Translation == nullptr)
return;
+ m_mouseDown = true;
inPoint.setX(inPoint.x() * m_pixelRatio);
inPoint.setY(inPoint.y() * m_pixelRatio);
@@ -1026,6 +1033,7 @@ struct SRendererImpl : public IStudioRenderer,
void OnSceneMouseUp(SceneDragSenderType::Enum) override
{
m_MaybeDragStart = false;
+ m_mouseDown = false;
Qt3DSDMGuideHandle theSelectedGuide;
if (m_PickResult.getType() == StudioPickValueTypes::Guide) {
theSelectedGuide = m_PickResult.getData<Qt3DSDMGuideHandle>();
diff --git a/src/Authoring/Studio/Render/StudioRendererTranslation.cpp b/src/Authoring/Studio/Render/StudioRendererTranslation.cpp
index 41fa7b29..6d31ae44 100644
--- a/src/Authoring/Studio/Render/StudioRendererTranslation.cpp
+++ b/src/Authoring/Studio/Render/StudioRendererTranslation.cpp
@@ -463,11 +463,14 @@ struct STranslatorDataModelParser
#define Text_Tracking m_Text.m_Tracking
#define Text_DropShadow m_Text.m_DropShadow
#define Text_DropShadowStrength m_Text.m_DropShadowStrength
-#define Text_DropShadowOffset m_Text.m_DropShadowOffset
-#define Text_DropShadowHorizontalAlignment m_Text.m_DropShadowHorizontalAlignment
-#define Text_DropShadowVerticalAlignment m_Text.m_DropShadowVerticalAlignment
+#define Text_DropShadowOffset m_Text.m_DropShadowOffset // To be removed in 2.x (when UIP version is next updated)
+#define Text_DropShadowOffsetX m_Text.m_DropShadowOffsetX
+#define Text_DropShadowOffsetY m_Text.m_DropShadowOffsetY
+#define Text_DropShadowHorizontalAlignment m_Text.m_DropShadowHorizontalAlignment // To be removed in 2.x (when UIP version is next updated)
+#define Text_DropShadowVerticalAlignment m_Text.m_DropShadowVerticalAlignment // To be removed in 2.x (when UIP version is next updated)
#define Text_WordWrap m_Text.m_WordWrap
#define Text_BoundingBox m_Text.m_BoundingBox
+#define Text_Elide m_Text.m_Elide
#define Text_TextColor m_Text.m_TextColor
#define Text_EnableAcceleratedFont m_Text.m_EnableAcceleratedFont
#define Path_Width m_Path.m_Width
diff --git a/src/Authoring/Studio/Render/StudioSubPresentationRenderer.cpp b/src/Authoring/Studio/Render/StudioSubPresentationRenderer.cpp
index 893ee654..160343e0 100644
--- a/src/Authoring/Studio/Render/StudioSubPresentationRenderer.cpp
+++ b/src/Authoring/Studio/Render/StudioSubPresentationRenderer.cpp
@@ -46,7 +46,6 @@ public:
, m_mainThread(mainThread)
, m_semaphore(0)
{
-
}
QSize readPresentationSize(const QString &url)
@@ -127,8 +126,17 @@ public:
m_running = true;
m_semaphore.release();
+#ifdef Q_OS_LINUX
+ // TODO: Updating the subpresentation on loop crashes or hangs on Linux, this hack fixes
+ // it for now
+ m_surfaceViewer->update();
+#endif
+
m_context->doneCurrent();
+#ifndef Q_OS_LINUX
+ // TODO: Updating the subpresentation on loop crashes or hangs on Linux, this hack fixes
+ // it for now
while (true) {
QMutexLocker lock(&m_mutex);
if (!m_running)
@@ -140,7 +148,7 @@ public:
}
m_surfaceViewer->update();
-
+ m_context->functions()->glFlush();
m_updated = true;
m_context->doneCurrent();
lock.unlock();
@@ -149,14 +157,15 @@ public:
QThread::usleep(33000);
}
m_fbo.reset();
+ m_context->doneCurrent();
+ m_context.reset();
+#endif
#ifdef Q3DS_PREVIEW_SUBPRESENTATION_RT2
m_surfaceViewer->destroy();
#else
m_surfaceViewer->shutdown();
#endif
m_surfaceViewer.reset();
- m_context->doneCurrent();
- m_context.reset();
m_surface->moveToThread(m_mainThread);
m_semaphore.release();
}
diff --git a/src/Authoring/Studio/UI/StudioProjectSettingsPage.cpp b/src/Authoring/Studio/UI/StudioProjectSettingsPage.cpp
index 527de1d0..36e344c3 100644
--- a/src/Authoring/Studio/UI/StudioProjectSettingsPage.cpp
+++ b/src/Authoring/Studio/UI/StudioProjectSettingsPage.cpp
@@ -181,7 +181,8 @@ bool CStudioProjectSettingsPage::onApply()
return false;
}
if (!g_StudioApp.GetCore()->getProjectFile()
- .isUniquePresentationId(m_ui->m_PresentationId->text())) {
+ .isUniquePresentationId(m_ui->m_PresentationId->text(),
+ g_StudioApp.GetCore()->GetDoc()->getRelativePath())) {
g_StudioApp.showPresentationIdUniqueWarning();
return false;
}
diff --git a/src/Authoring/Studio/Workspace/Dialogs.cpp b/src/Authoring/Studio/Workspace/Dialogs.cpp
index 6a08bc45..c32d1568 100644
--- a/src/Authoring/Studio/Workspace/Dialogs.cpp
+++ b/src/Authoring/Studio/Workspace/Dialogs.cpp
@@ -922,12 +922,15 @@ CDialogs::ESavePromptResult CDialogs::PromptForSave()
* Prompt the user for a file to save to.
* If browsing for location for presentation (isProject == false), then
* allow browsing only inside current project.
+ * If browsing for a location for a project, then disallow browsing inside current project.
+ * If isCopy is true, then create a copy of the existing project rather than a new one.
+ * isCopy is ignored if isProject is false;
* Return an invalid file if the user cancels the save dialog.
*/
-QString CDialogs::GetSaveAsChoice(const QString &inDialogTitle, bool isProject)
+QString CDialogs::GetSaveAsChoice(const QString &inDialogTitle, bool isProject, bool isCopy)
{
QString projPath(QDir::cleanPath(g_StudioApp.GetCore()->getProjectFile().getProjectPath()));
-
+ QString previousFolder;
QString theFilename = g_StudioApp.GetCore()->GetDoc()->GetDocumentPath();
if (theFilename.isEmpty() || isProject)
@@ -951,7 +954,25 @@ QString CDialogs::GetSaveAsChoice(const QString &inDialogTitle, bool isProject)
if (isProject) {
theFileDlg.setLabelText(QFileDialog::FileName, QObject::tr("Project Name"));
- theFileDlg.setLabelText(QFileDialog::Accept, QObject::tr("Create"));
+ if (!isCopy)
+ theFileDlg.setLabelText(QFileDialog::Accept, QObject::tr("Create"));
+ // Limit browsing to outside project directory
+ if (!projPath.isEmpty()) {
+ QDir projDir(projPath);
+ projDir.cdUp();
+ previousFolder = projDir.absolutePath();
+ if (isCopy)
+ theFileDlg.setDirectory(previousFolder);
+ connect(&theFileDlg, &QFileDialog::directoryEntered,
+ [&](const QString &dir) {
+ QFileInfo fi(QDir::cleanPath(dir));
+ const QString absPath = fi.absoluteFilePath();
+ if (absPath.startsWith(projPath))
+ theFileDlg.setDirectory(previousFolder);
+ else
+ previousFolder = absPath;
+ });
+ }
} else {
// Limit browsing to project directory
connect(&theFileDlg, &QFileDialog::directoryEntered,
@@ -966,13 +987,15 @@ QString CDialogs::GetSaveAsChoice(const QString &inDialogTitle, bool isProject)
}
bool theShowDialog = true;
- QString theFile = {};
+ QString theFile;
while (theShowDialog && theFileDlg.exec()) {
theShowDialog = false;
QString selectedName = theFileDlg.selectedFiles().front();
// Make sure file name has correct extension
- if (!selectedName.endsWith(theFileExt))
+ if (isProject && isCopy && selectedName.endsWith(theFileExt))
+ selectedName.chop(theFileExt.length());
+ else if (!selectedName.endsWith(theFileExt))
selectedName.append(theFileExt);
if (!isProject) {
@@ -986,8 +1009,7 @@ QString CDialogs::GetSaveAsChoice(const QString &inDialogTitle, bool isProject)
theFile = selectedName;
m_LastSaveFile = selectedName;
- // New directory is only created when creating a new project. When doing a "save as"
- // or "save copy", a new directory is not created.
+ // New directory is only created when creating a new project.
if (isProject) {
QString theFinalDir;
QString theFinalDoc;
@@ -995,22 +1017,20 @@ QString CDialogs::GetSaveAsChoice(const QString &inDialogTitle, bool isProject)
theFinalDir, theFinalDoc);
// Update last save file to final doc
- m_LastSaveFile = theFinalDoc;
- QFileInfo info(theFinalDoc);
- if (info.exists()) {
- const QString theTitle(QObject::tr("Confirm Save As"));
- const QString filePath(theFinalDir + QLatin1Char('/') + info.fileName());
- const QString theString = QObject::tr("%1 already exists.\nDo you want to "
- "replace it?").arg(filePath);
-
- auto result = QMessageBox::question(nullptr, theTitle, theString);
- if (result != QMessageBox::Yes) {
- // Reset the file and show the file dialog again
- theFile.clear();
- theShowDialog = true;
- continue;
- }
- } // of over-writing case
+ m_LastSaveFile = QFileInfo(theFinalDoc).absoluteFilePath();
+
+ // File dialog shouldn't allow choosing existing folder for project, but since we
+ // are using native dialog, let's play it safe and check.
+ if (QFileInfo(theFinalDir).exists()) {
+ const QString title(QObject::tr("Existing directory"));
+ const QString warning = QObject::tr("%1 already exists.")
+ .arg(QFileInfo(theFinalDir).fileName());
+ QMessageBox::warning(nullptr, title, warning);
+ // Reset the file and show the file dialog again
+ theFile.clear();
+ theShowDialog = true;
+ continue;
+ }
}
}
@@ -1244,18 +1264,18 @@ void CDialogs::showWidgetBrowser(QWidget *screenWidget, QWidget *browser, const
}
QRect screenRect = screen->availableGeometry();
- const int CONTROL_H = 22;
+ const int controlH = CStudioPreferences::controlBaseHeight();
if (align == WidgetBrowserAlign::ComboBox) {
// position the popup below the combobox
- newPos -= QPoint(popupSize.width(), -CONTROL_H) + screenRect.topLeft();
+ newPos -= QPoint(popupSize.width(), -controlH) + screenRect.topLeft();
// if no space below the combobox, move it above it
if (newPos.y() + popupSize.height() > screenRect.height())
- newPos.setY(newPos.y() - popupSize.height() - CONTROL_H);
- } else if (align == WidgetBrowserAlign::ToolButton){
+ newPos.setY(newPos.y() - popupSize.height() - controlH);
+ } else if (align == WidgetBrowserAlign::ToolButton) {
// The point is assumed to be the lower right corner of the button
newPos -= QPoint(popupSize.width(), popupSize.height()) + screenRect.topLeft();
if (newPos.y() < 0)
- newPos.setY(newPos.y() + popupSize.height() - CONTROL_H);
+ newPos.setY(newPos.y() + popupSize.height() - controlH);
} else { // WidgetBrowserAlign::Center
newPos -= QPoint(popupSize.width() / 2, popupSize.height() / 2) + screenRect.topLeft();
}
diff --git a/src/Authoring/Studio/Workspace/Dialogs.h b/src/Authoring/Studio/Workspace/Dialogs.h
index cdfb505c..d8163eb8 100644
--- a/src/Authoring/Studio/Workspace/Dialogs.h
+++ b/src/Authoring/Studio/Workspace/Dialogs.h
@@ -116,7 +116,8 @@ public:
Qt3DSFile GetExportChoice(const QString &inExtension,
const QString &inDefaultName);
- QString GetSaveAsChoice(const QString &inDialogTitle = {}, bool isProject = false);
+ QString GetSaveAsChoice(const QString &inDialogTitle = {}, bool isProject = false,
+ bool isCopy = false);
QString GetNewDocumentChoice(const QString &inInitialDirectory = {}, bool isProject = true);
QString GetFileOpenChoice(const QString &inInitialDirectory = {});
diff --git a/src/Runtime/qt3d-runtime b/src/Runtime/qt3d-runtime
-Subproject 5e9a1798cc697136aae4125a157e654d7e49530
+Subproject 8e8cbe86c045a68e7db457dfe2913e1c2d2668c