summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2019-03-01 12:03:05 +0200
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-03-01 17:16:09 +0200
commit8cb20f516ee98c49b911efc01425e436073bd06a (patch)
treec0c652cd4eeb78ef355c3b414e9ea9bd6bc9478f
parentf9e560d6ffb7578674473d680c55bcf757dbe958 (diff)
parent12adbbf19d0d4113890fa76019245a7f2f42c770 (diff)
Merge branch '2.3' into wip/runtime2
-rw-r--r--doc/src/00-concepts.qdoc7
-rw-r--r--doc/src/03-studio/5-timeline-palette.qdoc3
-rw-r--r--doc/src/03-studio/7-inspector-palette.qdoc165
-rw-r--r--doc/src/2d-assets.qdoc121
-rw-r--r--doc/src/about-qt3dstudio.qdoc22
-rw-r--r--doc/src/comparison.qdoc180
-rw-r--r--doc/src/glossary.qdoc314
-rw-r--r--doc/src/images/area-light.pngbin0 -> 16552 bytes
-rw-r--r--doc/src/images/directional-light-scene.pngbin0 -> 8266 bytes
-rw-r--r--doc/src/images/directional-light.pngbin0 -> 38558 bytes
-rw-r--r--doc/src/images/exponential-fade-100.pngbin0 -> 2515 bytes
-rw-r--r--doc/src/images/exponential-fade-20.pngbin0 -> 1827 bytes
-rw-r--r--doc/src/images/exponential-fade-200.pngbin0 -> 4295 bytes
-rw-r--r--doc/src/images/exponential-fade-50.pngbin0 -> 2016 bytes
-rw-r--r--doc/src/images/linear-fade-100.pngbin0 -> 4194 bytes
-rw-r--r--doc/src/images/linear-fade-20.pngbin0 -> 1953 bytes
-rw-r--r--doc/src/images/linear-fade-200.pngbin0 -> 2794 bytes
-rw-r--r--doc/src/images/linear-fade-50.pngbin0 -> 2255 bytes
-rw-r--r--doc/src/images/point-light-scene.pngbin0 -> 15344 bytes
-rw-r--r--doc/src/images/point-light.pngbin0 -> 42606 bytes
-rw-r--r--doc/src/images/variant-tags-layer.pngbin0 -> 17170 bytes
-rw-r--r--doc/src/images/variant-tags-slide.pngbin0 -> 3053 bytes
-rw-r--r--doc/src/images/variant-tags.pngbin0 -> 9061 bytes
-rw-r--r--doc/src/known-issues.qdoc63
-rw-r--r--doc/src/layers.qdoc4
-rw-r--r--doc/src/lights.qdoc156
-rw-r--r--doc/src/tutorials.qdoc4
-rw-r--r--doc/src/variant-tags.qdoc120
-rw-r--r--src/Authoring/Client/Code/Core/Core/Core.cpp1
-rw-r--r--src/Authoring/Client/Code/Core/Doc/Doc.cpp14
-rw-r--r--src/Authoring/Client/Code/Core/Doc/Doc.h5
-rw-r--r--src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp37
-rw-r--r--src/Authoring/Client/Code/Core/Doc/IComposerSerializer.h16
-rw-r--r--src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h17
-rw-r--r--src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp15
-rw-r--r--src/Authoring/Client/Code/Core/Utility/StudioPreferences.h3
-rw-r--r--src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp15
-rw-r--r--src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h37
-rw-r--r--src/Authoring/Studio/Application/DataInputDlg.cpp34
-rw-r--r--src/Authoring/Studio/Application/DataInputDlg.h4
-rw-r--r--src/Authoring/Studio/Application/DataInputDlg.ui42
-rw-r--r--src/Authoring/Studio/Application/DataInputListDlg.cpp41
-rw-r--r--src/Authoring/Studio/Application/DurationEditDlg.cpp214
-rw-r--r--src/Authoring/Studio/Application/DurationEditDlg.h35
-rw-r--r--src/Authoring/Studio/Application/DurationEditDlg.ui59
-rw-r--r--src/Authoring/Studio/Application/ProjectFile.cpp677
-rw-r--r--src/Authoring/Studio/Application/ProjectFile.h25
-rw-r--r--src/Authoring/Studio/Application/StudioApp.cpp13
-rw-r--r--src/Authoring/Studio/Application/TimeEditDlg.cpp210
-rw-r--r--src/Authoring/Studio/Application/TimeEditDlg.h29
-rw-r--r--src/Authoring/Studio/Application/TimeEditDlg.ui68
-rw-r--r--src/Authoring/Studio/Info.plist6
-rw-r--r--src/Authoring/Studio/MainFrm.cpp7
-rw-r--r--src/Authoring/Studio/MainFrm.h2
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp18
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp66
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h14
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp92
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h5
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml215
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp27
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp8
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h1
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.cpp106
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.h73
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.ui113
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp237
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.h85
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.cpp108
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.h (renamed from src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h)51
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp18
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideModel.cpp64
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideModel.h6
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideView.cpp86
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideView.h5
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideView.qml11
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h1
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineTimebar.cpp2
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h4
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp115
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h25
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp22
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h5
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.cpp18
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.h4
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp133
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h6
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp146
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h10
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp22
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.h8
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp277
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h26
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp2
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp2
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp302
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h5
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeLabelItem.cpp2
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp43
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.h24
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h2
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp16
-rw-r--r--src/Authoring/Studio/Qt3DStudio.pro28
-rw-r--r--src/Authoring/Studio/UI/StudioAppPrefsPage.cpp1
-rw-r--r--src/Authoring/Studio/Utils/StudioUtils.cpp17
-rw-r--r--src/Authoring/Studio/Utils/StudioUtils.h1
-rw-r--r--src/Authoring/Studio/Workspace/Dialogs.cpp49
-rw-r--r--src/Authoring/Studio/Workspace/Dialogs.h8
-rw-r--r--src/Authoring/Studio/images.qrc23
-rw-r--r--src/Authoring/Studio/images/Action-Action@2x.pngbin0 -> 599 bytes
-rw-r--r--src/Authoring/Studio/images/Action-ChildAction@2x.pngbin0 -> 341 bytes
-rw-r--r--src/Authoring/Studio/images/Action-ChildMasterAction@2x.pngbin0 -> 344 bytes
-rw-r--r--src/Authoring/Studio/images/Action-ComponentAction@2x.pngbin0 -> 325 bytes
-rw-r--r--src/Authoring/Studio/images/Action-ComponentMasterAction@2x.pngbin0 -> 314 bytes
-rw-r--r--src/Authoring/Studio/images/Action-MasterAction@2x.pngbin0 -> 639 bytes
-rw-r--r--src/Authoring/Studio/images/Insert-Left@2x.pngbin0 -> 314 bytes
-rw-r--r--src/Authoring/Studio/images/Insert-Right@2x.pngbin0 -> 324 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Master-Disabled.pngbin3009 -> 2946 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Master-Disabled@2x.pngbin0 -> 606 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Master-Normal.pngbin2924 -> 2937 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Master-Normal@2x.pngbin0 -> 578 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Master-Selected.pngbin2985 -> 2947 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Master-Selected@2x.pngbin0 -> 498 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled.pngbin617 -> 263 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled@2x.pngbin0 -> 580 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.pngbin3010 -> 2959 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal@2x.pngbin0 -> 578 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.pngbin2981 -> 2949 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected@2x.pngbin0 -> 561 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Property-Disabled.pngbin2989 -> 2949 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Property-Disabled@2x.pngbin0 -> 435 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Property-Normal.pngbin2924 -> 2949 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Property-Normal@2x.pngbin0 -> 428 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Property-Selected.pngbin2981 -> 2951 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Property-Selected@2x.pngbin0 -> 424 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled.pngbin593 -> 291 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled@2x.pngbin0 -> 428 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.pngbin2971 -> 2949 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.pngbin0 -> 427 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png~bin0 -> 427 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.pngbin2973 -> 2947 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected@2x.pngbin0 -> 424 bytes
-rw-r--r--src/Authoring/Studio/images/Toggle-Empty@2x.pngbin0 -> 286 bytes
-rw-r--r--src/Authoring/Studio/images/keyframe-hidden-normal@2x.pngbin0 -> 226 bytes
-rw-r--r--src/Authoring/Studio/images/playback_tools_low-04@2x.pngbin0 -> 315 bytes
m---------src/Runtime/qt3d-runtime0
-rw-r--r--src/shared/header/foundation/ConvertUTF.h34
-rw-r--r--src/shared/header/foundation/StrConvertUTF.h12
-rw-r--r--src/shared/qt-breakpad/qtcrashhandler/mainwidget.h6
-rw-r--r--src/shared/source/ConvertUTF.cpp14
150 files changed, 4370 insertions, 1239 deletions
diff --git a/doc/src/00-concepts.qdoc b/doc/src/00-concepts.qdoc
index fa16e676..ef65f215 100644
--- a/doc/src/00-concepts.qdoc
+++ b/doc/src/00-concepts.qdoc
@@ -48,7 +48,6 @@ interactive presentations, UIs and applications.
\div {align="center"}
\image animation-index.png
\enddiv
-
\row
\li \b {\l{Getting Started}}
\list
@@ -61,10 +60,11 @@ interactive presentations, UIs and applications.
\endlist
\li \b {\l{Graphics}}
\list
+ \li \l{2D Assets}
\li \l{Working with 3D Content}{3D Assets}
\li \l{Layers}
\li \l{Materials and Shaders}
- \li \l{Light Properties}{Lights}
+ \li \l{Lights}
\li \l{Using Sub-Presentations}{Sub-Presentations}
\li \l{Stereoscopic Rendering}
\endlist
@@ -99,10 +99,11 @@ interactive presentations, UIs and applications.
\endlist
\li \b {\l{Getting Help}}
\list
+ \li \l{Known Issues}
+ \li \l{Glossary}
\li \l{Studio Keyboard Shortcuts}
\li \l{Viewer Keyboard Shortcuts}
\endlist
-
\row
\li {3,1} \note To report bugs and suggestions to the Qt Bug
Tracker, visit \l https://bugreports.qt.io.
diff --git a/doc/src/03-studio/5-timeline-palette.qdoc b/doc/src/03-studio/5-timeline-palette.qdoc
index f385ebbd..cf0c7739 100644
--- a/doc/src/03-studio/5-timeline-palette.qdoc
+++ b/doc/src/03-studio/5-timeline-palette.qdoc
@@ -171,6 +171,9 @@ cause an element to not appear on only certain slides, place your
element on the master slide and then eyeball it off on slides where it
should not be present.
+\note The visible property is disabled on the master slide, it can only be controlled
+on a per-slide basis.
+
The active state of an element controls more than just visibility.
Elements that are not active do not receive update notifications each
frame. which is particularly important for presentation behaviors.
diff --git a/doc/src/03-studio/7-inspector-palette.qdoc b/doc/src/03-studio/7-inspector-palette.qdoc
index 354d0580..70cc9f59 100644
--- a/doc/src/03-studio/7-inspector-palette.qdoc
+++ b/doc/src/03-studio/7-inspector-palette.qdoc
@@ -32,7 +32,7 @@
\page studio-inspector-palette.html
\ingroup qt3dstudio-studio
- The Inspector palette is the most-used
+The Inspector palette is the most-used
palette in Studio. It is used to control which properties are animated
or change on a per-slide basis and the values for each of those
properties.
@@ -116,7 +116,7 @@ shown in the Inspector palette \e{specific to the active slide}:
over at time 0.
\li
\c{PingPong} - Upon reaching the final time the playhead starts
- playing backwards; upon reaching time 0 the playeah starts playing
+ playing backwards; upon reaching time 0 the playhead starts playing
forwards again.
\li
\c{Ping} - Similar to \e{PingPong}, but when the playhead
@@ -134,6 +134,10 @@ shown in the Inspector palette \e{specific to the active slide}:
\b{Pause} setting is particularly useful when QML application is going
to control the time for the context and you don't
need or want the runtime attempting to do its own work.
+\li
+ \b{Use Background} - Clear the contents to a solid color before each frame.
+\li
+ \b{Background Color} - Color to use for the background.
\endlist
\target layer-properties
@@ -144,23 +148,6 @@ in the Inspector palette:
\list
\li
- \b{Disable Depth Test} - Controls whether depth-testing is used
- when rendering objects in the layer. For details see the discussion on
- the
- \e{\l{best-practices-disable-depth-test.html}{Disable Depth Test}} page.
-\li
- \b{Progressive AA} - Controls whether progressive anti-aliasing
- is used when rendering the layer. For details see the discussion on
- \e{\l{best-practices-antialiasing.html#progressive-aa}{Progressive Anti-Aliasing}}.
-\li
- \b{Multisample AA} - Controls whether multisample anti-aliasing
- is used when rendering the layer. For details see the discussion on
- \e{\l{best-practices-antialiasing.html#multisample-aa}{Multisample Anti-Aliasing}}.
-\li
- \b{Temporal AA} - Controls whether temporal anti-aliasing is used
- when rendering the layer. For details see the discussion on
- \e{\l{best-practices-antialiasing.html#temporal-aa}{Temporal Anti-Aliasing}}.
-\li
\b{Layer Background} - Controls how the layer clears when it
starts to render each frame:
\list
@@ -168,14 +155,14 @@ in the Inspector palette:
\c{Transparent} - Clear the layer to transparent each frame so
that content behind it can be seen.
\li
- \c{Unspecified} - Do not clear layer each frame. This provides a
- slight performance boost if the layer is filled with content, and
- hence will fully overwrite the previous result.
-\li
\c{Solid Color} - Clear this layer to a non-transparent color.
This provides a slight performance boost if the layer fills the
viewport \b{and} if you turn off \"Enable Background Color\" for
the Scene.
+\li
+ \c{Unspecified} - Do not clear layer each frame. This provides a
+ slight performance boost if the layer is filled with content, and
+ hence will fully overwrite the previous result.
\endlist
\li
\b{Blend Mode} - Controls how colors in the active layer blends with colors in the background
@@ -202,6 +189,23 @@ in the Inspector palette:
than \c Screen.
\endlist
\li
+ \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{Progressive AA} - Controls whether progressive anti-aliasing
+ is used when rendering the layer. For details see the discussion on
+ \e{\l{best-practices-antialiasing.html#progressive-aa}{Progressive Anti-Aliasing}}.
+\li
+ \b{Multisample AA} - Controls whether multisample anti-aliasing
+ is used when rendering the layer. For details see the discussion on
+ \e{\l{best-practices-antialiasing.html#multisample-aa}{Multisample Anti-Aliasing}}.
+\li
+ \b{Temporal AA} - Controls whether temporal anti-aliasing is used
+ when rendering the layer. For details see the discussion on
+ \e{\l{best-practices-antialiasing.html#temporal-aa}{Temporal Anti-Aliasing}}.
+\li
\b{Horizontal Fields} - Choose which two fields of \c{Left},
\c{Width}, and \c{Right} are used to control the horizontal
placement and sizing of the layer within the presentation.
@@ -232,11 +236,6 @@ in the Inspector palette:
presentation and the layer, either in pixels or as a percentage of the
presentation's height.
\li
- \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
causes non-directional self-shadowing where objects are close
@@ -305,35 +304,6 @@ in the Inspector palette:
to your content.
\endlist
\li
- \b{Shadow Strength} - Controls the strength of directional
- occlusion (DO). DO is a form of approximated directional shadowing. A
- value of \c{100} causes full darkness shadows; lower values cause
- the shadowing to appear lighter. A value of \c{0} disables DO
- entirely, improving performance at a cost to the visual realism of 3D
- objects rendered in the layer. All values other than \c{0} have
- the same impact to the performance.
- \list
- \li
- \note Directional occlusion will only render on \e{Standard Materials}
- that have the \l{standard-materials}{Lighting property} set to \c{Pixel}.
- \endlist
-\li
- \b{Shadow Distance} - Roughly how far (in world units) the faked
- shadows spread away from objects.
-\li
- \b{Shadow Softness} - Crossfade amount between sharp shadows and
- smooth gradations.
-\li
- \b{Shadow Threshold} - A cutoff distance preventing objects from
- self-shadowing. Higher values increase the distance required between
- objects before DO is seen.
- \list
- \li
- \note If you see DO shadowing in regions where there should be
- no shadowing, increase the Shadow Threshold value slightly to clip
- away close results.
- \endlist
-\li
\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
@@ -352,6 +322,14 @@ in the Inspector palette:
\b{Secondary Light Probe} - Select an image to use as secondary IBL light source.
\li
\b{Probe Crossfade} - The blend amount between the primary and secondary light probes.
+\li
+ \b{Disable Depth Test} - Controls whether depth-testing is used
+ when rendering objects in the layer. For details see the discussion on
+ the
+ \e{\l{best-practices-disable-depth-test.html}{Disable Depth Test}} page.
+\li
+ \b{Disable Depth Prepass} - Controls whether depth prepassing is used when rendering objects
+ in the layer. Can be enabled to optimize render speed on layers with low depth complexity.
\endlist
\target transform-properties
@@ -547,7 +525,7 @@ in the Inspector palette (in addition to the
- Simulate
shadows using this light?
\li
- \b{Shadow Darkness} - How dark should the cast shadows be?
+ \b{Shadow Darkness} - Darkness of the shadows.
\li
\b{Shadow Softness} - Amount of blur applied to the shadows.
\li
@@ -750,8 +728,8 @@ about working with materials, see \l {Materials and Shaders}.
by the Bump Amount property.
\list
\li
- \e{Tip: Bump maps will not affect the silhouette of a model. Use a
- displacement map if this is required.}
+ \note Bump maps will not affect the silhouette of a model. Use a
+ displacement map if this is required.
\endlist
\li
\b{Normal Map} - An RGB image used to \e{simulate} fine
@@ -760,8 +738,8 @@ about working with materials, see \l {Materials and Shaders}.
controlled by the Bump Amount property.
\list
\li
- \e{Tip: Normal maps will not affect the silhouette of a model. Use
- a displacement map if this is required.}
+ \note Normal maps will not affect the silhouette of a model. Use
+ a displacement map if this is required.
\endlist
\li
\b{Bump Amount} - Controls the amount of simulated displacement
@@ -773,14 +751,12 @@ about working with materials, see \l {Materials and Shaders}.
surface of the material. Brighter pixels indicate raised regions.
\list
\li
- \e{Tip: Displacement maps require vertices to offset. If your model
- is not high-enough resolution you may need to dynamically generate
- additional vertices by using the
- \l{model-properties}{Tessellation properties} on the model.}
+ \note Displacement maps require vertices to offset. I.e. the result will be
+ more accurate on a high poly model than on a low poly model.
\li
- \e{Tip: Displacement maps do not affect the normals of your
+ \note Displacement maps do not affect the normals of your
geometry. To look correct with lighting or reflections you will likely
- want to also add a matching bump map or normal map to your material.}
+ want to also add a matching bump map or normal map to your material.
\endlist
\li
\b{Displacement Amount} - Controls the offset amount for the displacement map.
@@ -789,7 +765,7 @@ about working with materials, see \l {Materials and Shaders}.
from the model.
\list
\li
- Note: Setting the opacity of a \e{model} very low (below 1\% or
+ \note Setting the opacity of a \e{model} very low (below 1\% or
less) will prevent it from receiving touch events, but setting the
opacity of its \e{material} very low still allows touch events to
occur.
@@ -829,7 +805,7 @@ about working with materials, see \l {Materials and Shaders}.
\b{Diffuse Light Wrap} - The amount of light wrap for the translucency map. A value of 0 will not
wrap the light at all while a value of 1 will wrap the light all around the object.
\endlist
-Note that the Runtime custom-compiles shaders for each unique
+\note 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.
@@ -851,11 +827,13 @@ The Inspector palette shows only a single property:
\li
\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
- visible or even active for this to work. It is valid to have a small
- pile of models with custom materials on them all eyeballed off, and
- then reference those materials for rendering on other objects.}
+ \list
+ \li
+ \note The material you reference does \b{not} have to be
+ visible or even active for this to work. It is valid to have a small
+ pile of models with custom materials on them all eyeballed off, and
+ then reference those materials for rendering on other objects.}
+ \endlist
\endlist
\section1 Image Properties
@@ -927,12 +905,9 @@ properties in the Inspector palette (in addition to the
\b{Text String} - The text to display for the text element.
\list
\li
- \e{Note: Qt 3D Studio does not (currently) support styled
+ \note Qt 3D Studio does not (currently) support styled
text. There is no way to make one word in a paragraph bold, larger, or
a different color.}
-\li
- \e{Note: Qt 3D Studio also does not (currently) support automatically
- wrapping text; you must manually inject line breaks to wrap your text.}
\endlist
\li
\b{Text Color} - The color for the text.
@@ -957,7 +932,7 @@ TODO: Only one font for now. More to be added?
also type a new value for the font.
\list
\li
- \e{Tip: Although the font size is just a number, it is
+ \note Although the font size is just a number, it is
intentionally not animatable. Each time the font size changes a rather
expensive rasterization of the text string occurs. You should animate
the scale of the text element instead.}
@@ -977,6 +952,36 @@ TODO: Only one font for now. More to be added?
\li
\b{Tracking} - Controls the amount of extra (or negative)
horizontal spacing between every character pair.
+\li
+ \b{Text Area} - Define size of fixed text area. If no values are set, the text size will
+ grow with the text.
+\li
+ \b{Word Wrapping} - Define how text will be wrapped when using a fixed text area size.
+ \list
+ \li
+ \c Clip - Cut the text if it doesn't fit in the text area.
+ \li
+ \c WrapWord - Wraps between words, if possible.
+ \li
+ \c WrapAnywhere - Wraps anywhere, also in the middle of words.
+ \endlist
+\li
+ \b{Eliding} - Elide text that does not fit into a fixed size text area.
+ \list
+ \li
+ \note Text eliding does not work with distance field rendering disabled or when
+ drop shadows are used.
+ \endlist
+\li
+ \b{Drop-Shadow} - Add a drop shadow to the text. The drop shadow will be a darker shade of the
+ text color.
+\li
+ \b{Shadow Darkness} - Darkness of the drop shadow. 100 is black and 0 is the same color as the
+ text.
+\li
+ \b{Horizonal Offset} - Horizontal offset of the shadow. The offset is relative to the font size.
+\li
+ \b{Vertical Offset} - Vertical offset of the shadow. The offset is relative to the font size.
\endlist
diff --git a/doc/src/2d-assets.qdoc b/doc/src/2d-assets.qdoc
new file mode 100644
index 00000000..d048959f
--- /dev/null
+++ b/doc/src/2d-assets.qdoc
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+/*!
+\page 2d-assets.html
+\title 2D Assets
+
+In Studio, you can import images to use as textures. The following image file formats
+are supported:
+
+\table
+ \header
+ \li File format
+ \li Extensions
+ \row
+ \li PNG
+ \li \c{.png}
+ \row
+ \li JPEG
+ \li \c{.jpg}, \c{.jpeg}
+ \row
+ \li DirectDraw Surface
+ \li \c{.dds}
+ \row
+ \li BMP
+ \li \c{.bmp}
+ \row
+ \li GIF
+ \li \c{.gif}
+ \row
+ \li HDRI (High Dynamic Range Imaging)
+ \li \c{.hdr}
+ \row
+ \li Khronos texture container
+ \li \c{.ktx}
+\endtable
+
+\section1 Using Textures on Materials
+Images can be used as the following textures on materials:
+
+\list
+ \li
+ Diffuse Map
+ \li
+ Roughness Map
+ \li
+ Opacity Map
+ \li
+ Emissive Map
+ \li
+ Bump Map
+ \li
+ Normal Map
+ \li
+ Displacement Map
+ \li
+ Translucency Map
+ \li
+ Specular Map
+ \li
+ Specular Reflection
+ \li
+ Indirect Lightmap
+ \li
+ Shadow Lightmap
+ \li
+ IBL Override
+\endlist
+
+Read more about working with \l Materials.
+
+\section1 Compressed Textures
+
+Qt 3D Studio supports the Khronos texture container file format \e ktx. You can apply \e ktx files
+as texture maps just as any other file format. However, if your system does not support the \e ktx
+format, the textures will not be visible in Qt 3D Studio.
+
+If you enable the \uicontrol {Use ktx textures if available} feature, you can use \e png
+images in Studio, and then use \e ktx images in their place in the Viewer.
+
+\list 1
+ \li In the Studio menu, click \uicontrol{Edit > Presentation Settings}
+ \li Check the \uicontrol {Use ktx textures if available} check box.
+\endlist
+
+\section1 Optimizing Images
+
+Optimizing the images in your presentation can substantially improve both the startup and runtime
+performance of your application, as well as the visual quality in certain situations. Read more
+about \l{Optimizing Images}.
+
+\section1 Image-Based Lighting
+
+HDR images can be used as light probes for environment lighting in Studio. Read more about
+\l{Image-Based Lighting}.
+
+*/
diff --git a/doc/src/about-qt3dstudio.qdoc b/doc/src/about-qt3dstudio.qdoc
index 4e0560a5..ecfe6683 100644
--- a/doc/src/about-qt3dstudio.qdoc
+++ b/doc/src/about-qt3dstudio.qdoc
@@ -70,6 +70,10 @@ The Qt 3D Studio suite includes:
For software and hardware requirements, see the \l{Requirements} page. For list of third-party
modules and copyright notices, see the \l{Copyright Notices} page.
+\section1 Qt 3D vs. Qt 3D Studio
+See the \l{Comparison of Qt 3D and Qt 3D Studio} section for a full comparison of Qt 3D and
+Qt 3D Studio.
+
\section1 Concepts
\section2 Project
@@ -109,22 +113,4 @@ are then composited with items on upper layers drawing on top of the content on
A Studio presentation combines 3D assets with animations and \e{slides}. Slides can be thought
of as states and provide visual variations within the presentation.
-
-\section1 Known Issues
-
-\section2 Possible problems after automatic mesh optimization
-
-When loading a presentation made with an earlier version (2.0 beta2 or older) of Qt 3D Studio
-which has imported FBX or DAE models, you may see the following messagebox:
-
-\image {mesh_optimization.png}{Old presentation version}
-
-If your \b{imported} models are not visible in the Viewer after seeing the message, you need to
-edit your \c{*.uip} file(s) manually. Some older versions of Studio referenced meshes with revision
-number in the \c{*.uip} file, and that revision causes it to be missing in the scope of the
-Viewer.
-
-You'll need to find all occurrences of \c{.mesh#<revision_number>} from you \c{*.uip} and
-replace them with \c{.mesh}.
-
*/
diff --git a/doc/src/comparison.qdoc b/doc/src/comparison.qdoc
new file mode 100644
index 00000000..372c4508
--- /dev/null
+++ b/doc/src/comparison.qdoc
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 Comparison of Qt 3D and Qt 3D Studio
+\page comparison-qt3d-qt3dstudio.html
+
+In short, Qt 3D Studio is built on top of Qt 3D. The flexible architecture of Qt 3D makes it
+suitable to build 3D runtimes, or engines, such as Qt 3D Studio.
+
+\section1 Qt 3D
+
+Qt 3D is programmer-oriented engine building toolkit and great for both simple and complex scenes.
+Qt 3D simplifies the implementation of advanced rendering techniques.
+
+\section1 Qt 3D Studio
+
+Qt 3D Studio consists of both a 3D editor and a 3D runtime. Qt 3D Studio is designer-oriented
+and makes it easy to build complex 3D scenes with states and transitions that can be used in
+and controlled by Qt applications.
+
+\section1 Use Case Comparison
+
+Whether you should use Qt 3D or Qt 3D Studio for your project depends on your use case.
+Below, we list some common use cases and how they apply to the two:
+
+\section2 Creating 3D Scenes
+
+\table
+ \header
+ \li
+ Use Case
+ \li
+ Qt 3D
+ \li
+ Qt 3D Studio
+ \row
+ \li
+ Graphically editing a 3D scene for use in a Qt application.
+ \li
+ No built-in editor. Support for importing common 3D formats.
+ \li
+ Yes, use the Qt 3D Studio Editor.
+ \row
+ \li
+ Creating a 3D scene programmatically.
+ \li
+ Suitable.
+ \li
+ Not possible.
+ \row
+ \li
+ Using existing materials and effects.
+ \li
+ Some available in Qt3D.Extras.
+ \li
+ Many available in the Qt 3D Studio editor.
+ \row
+ \li
+ Combine existing materials and effects.
+ \li
+ May require rewriting some of the shaders from Qt3D.Extras to form custom
+ combinations.
+ \li
+ Suitable.
+\endtable
+
+\section2 Effects
+
+\table
+ \header
+ \li
+ Use Case
+ \li
+ Qt 3D
+ \li
+ Qt 3D Studio
+ \row
+ \li
+ Creating a simple multi-pass rendering pipeline.
+ \li
+ Suitable.
+ \li
+ Suitable.
+ \row
+ \li
+ Using custom shaders.
+ \li
+ Suitable.
+ \li
+ Suitable.
+ \row
+ \li
+ Layer-based compositing.
+ \li
+ Suitable.
+ \li
+ Suitable.
+ \row
+ \li
+ Implementing custom rendering techniques such as volumetric rendering.
+ \li
+ Suitable.
+ \li
+ Not suitable.
+\endtable
+
+\section2 Formats
+
+\table
+ \header
+ \li
+ Use Case
+ \li
+ Qt 3D
+ \li
+ Qt 3D Studio
+ \row
+ \li
+ Importing external formats.
+ \li
+ All formats supported by plugins such as Assimp. See
+ \l{https://doc.qt.io/qt-5/qml-qt3d-render-sceneloader.html}{SceneLoader} for a full list.
+ \li
+ A number of formats are supported. See \l{2D Assets} and
+ \l{Working with 3D Content}{3D Assets} for details.
+\endtable
+
+\section2 Creating 3D Engines and Editors
+
+\table
+ \header
+ \li
+ Use Case
+ \li
+ Qt 3D
+ \li
+ Qt 3D Studio
+ \row
+ \li
+ Creating a custom graphical 3D editor.
+ \li
+ Suitable.
+ \li
+ Not possible.
+ \row
+ \li
+ Creating a custom 3D engine.
+ \li
+ Suitable.
+ \li
+ Not possible.
+\endtable
+
+*/
diff --git a/doc/src/glossary.qdoc b/doc/src/glossary.qdoc
new file mode 100644
index 00000000..950b64be
--- /dev/null
+++ b/doc/src/glossary.qdoc
@@ -0,0 +1,314 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 Glossary
+\page glossary.html
+
+This page provides short explanations of terms used in Qt 3D Studio.
+
+\table
+ \header
+ \li
+ Term
+ \li
+ Meaning
+ \row
+ \li
+ \l{Studio: Action Palette}{Action}
+ \li
+ Actions provide a way to create interactivity in a \l presentation without scripting.
+ \row
+ \li
+ \l{Studio: Action Palette}{Action palette}
+ \li
+ The action palette is used to manage \l {action}{actions} for the selected element.
+ \row
+ \li
+ \target {animation portion}
+ \l{Studio: Timeline Palette#Animation portion}{Animation Portion}
+ \li
+ To the right of the \l{scene graph} in the \l{timeline palette} is the actual \l timeline.
+ The \l{time bar}{time bars} for each element control element lifespan.
+ The \l keyframe markers control the timing of the animation. The \l playhead allows the
+ preview of animation effects.
+ \row
+ \li
+ \target application
+ \l{About Qt 3D Studio#Concepts}{Application}
+ \li
+ Your application is the entry point of your \l project. It is represented by a single
+ \l{uia}{.uia file} at the root of your project folder. This file references the
+ \l presentation and \l{sub-presentation}{sub-presentations} in your project.
+ The application is what is displayed by the \l Viewer.
+ \row
+ \li
+ \target asset
+ Asset
+ \li
+ Assets are elements which you can use in your \l presentation. Assets can be images, 3D
+ models, \l{effect}{effects}, fonts, \l{material}{materials}, \l{shader}{shaders},
+ \l {behavior}{scripts} and \l{sub-presentation}{sub-presentations}.
+ \row
+ \li
+ Asset library
+ \li
+ Included in \l studio is a set of \l{asset}{assets} ranging from images to 3d models.
+ \row
+ \li
+ \l{Studio: Basic Objects Palette}{Basic objects palette}
+ \li
+ The Basic objects palette provides a mechanism for creating objects unique to a
+ \l presentation, not represented by a file on disk in your \l {project palette}.
+ \row
+ \li
+ \target behavior
+ \l{Using Behavior Scripts}{Behavior}
+ \li
+ Behavior scripts can be applied to objects to give the specific object a certain behavior.
+ \row
+ \li
+ \l{Studio: Basic Objects Palette#Component}{Component}
+ \li
+ Components are somewhat like mini-scenes. Although they are 3D geometry (not a 2D
+ composition of rendered layers), they have their own \l {slide}{slides} and
+ \l {timeline}{timelines}.
+ \row
+ \li
+ \l{Using Data Inputs}{Data input}
+ \li
+ This makes it possible to control \l timeline animations, object properties and
+ \l{slide}{slides} with data.
+ \row
+ \li
+ \l{Studio: Toolbar#Edit Cameras}{Edit cameras}
+ \li
+ Sometimes you want to move around the 3D space of your scene in the editor without
+ adjusting the final rendered view. \l Studio calls this concept edit cameras.
+ \row
+ \li
+ \target effect
+ \l{Applying Layer Effects}{Effect}
+ \li
+ Each \l layer in a \l presentation may have one or more post-processing effects
+ applied to the visual result
+ \row
+ \li
+ \l{Studio: Basic Objects Palette#Group}{Group}
+ \li
+ A group is an empty transform element. Attaching models to the group
+ (placing them as children of the group in the \l {timeline palette}) allows you to
+ move/rotate/scale/hide the group and have this affect all items within it.
+ \row
+ \li
+ .import file
+ \li
+ When importing 3D models of \e .fbx and \e .dae format to \l studio, they are converted to
+ \e .import files.
+ \row
+ \li
+ \l{Studio: Inspector Palette}{Inspector palette}
+ \li
+ The inspector palette is used to control values and animations of element properties.
+ \row
+ \li
+ \l{Animations#Interpolation}{Interpolation}
+ \li
+ Interpolation defines the easing of \l keyframe animations.
+ \row
+ \li
+ \target keyframe
+ \l{Animations}{Keyframe}
+ \li
+ 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
+ \l timeline. \l Studio will determine the correct X position for all frames between the
+ two keyframes.
+ \row
+ \li
+ \target layer
+ \l{About Qt 3D Studio#Concepts}{Layer}
+ \li
+ A single Studio \l presentation combines one or more layers. The visual result of each
+ layer comes from rendering a 3D scene, 2D scene (via an orthographic camera),
+ or \l{sub-presentation}{sub-presentation}. Layers are then composited with items on upper
+ layers drawing on top of the content on lower layers.
+ \row
+ \li
+ \l{Studio: Slide Palette#The Master Slide}{Master slide}
+ \li
+ Each scene and \l component have one master slide.
+ Elements placed on this \l slide exist on all slides of that scene or \l component.
+ \row
+ \li
+ \l{Materials and Shaders#Materials}{Material}
+ \li
+ Materials define how object surfaces are rendered in \l studio and \l viewer. You can create
+ your own basic materials, save them in your \l project, and assign them to objects.
+ \row
+ \li
+ \l{Studio: Scene View and Matte#Matte}{Matte}
+ \li
+ Surrounding the \l {scene view} is the matte. The matte may not be visible if your
+ \l presentation is larger than the available space.
+ \row
+ \li
+ Mesh
+ \li
+ The actual geometry of a 3D shape.
+ \row
+ \li
+ \target playhead
+ \l{Animations}{Playhead}
+ \li
+ The playhead in the \l timeline is used to set the time for new keyframes, and for previewing
+ animations.
+ \row
+ \li
+ \target presentation
+ \l{About Qt 3D Studio#Concepts}{Presentation}
+ \li
+ Presentations are represented by \l{uip}{.uip files} in your project. A presentation
+ has one or more \l{layer}{layers} composited to the screen, comprised of 2D assets
+ and 3D assets created in other applications.
+
+ Each application can only have one main presentation shown on screen (specified by the
+ \l {uia}{.uia file}) but this presentation may reference other
+ \l{sub-presentation}{sub-presentations}, either on flat layers or as images and textures
+ drawn in a scene.
+ \row
+ \li
+ \target project
+ \l{About Qt 3D Studio#Concepts}{Project}
+ \li
+ A project is simply a folder on your computer holding all the assets needed for your
+ \l application. When you start a new project, a default folder structure will be created.
+ \row
+ \li
+ \target {project palette}
+ \l{Studio: Project Palette}{Project palette}
+ \li
+ The project palette displays the files and folders on disk for your \l project.
+ Only files usable by \l Studio are displayed in the palette.
+ \row
+ \li
+ QML Stream
+ \li
+ A QML stream is a \e .qml file used as a \l{sub-presentation}.
+ \row
+ \li
+ \l{Studio: Scene Camera Palette}{Scene Camera palette}
+ \li
+ The scene camera palette allows you to zoom in to pixel perfect level with the scene camera.
+ \row
+ \li
+ \target {scene graph}
+ \l{Studio: Timeline Palette#Scene Graph}{Scene graph}
+ \li
+ The left half of the \l{timeline palette} shows the scene graph where all elements in your
+ \l presentation for the current \l slide.
+ \row
+ \li
+ \target {scene view}
+ \l{Studio: Scene View and Matte#Scene View}{Scene view}
+ \li
+ The scene view is the center region of \l Studio, showing you the visual result of rendering
+ and compositing the \l{layer}{layers} of your \l presentation, and also allowing you to
+ select and transform elements graphically.
+ \row
+ \li
+ \target shader
+ \l{Materials}{Shader}
+ \li
+ Shaders are arbitrary GLSL Shaders, wrapped in a file format providing an artist-friendly
+ interface for adjusting properties in \l studio.
+ \row
+ \li
+ \l{Studio:Slide Palette}{Slide}
+ \li
+ A Studio \l presentation combines 3D assets with animations and slides.
+ Slides can be thought of as states and provide visual variations within the \l presentation.
+ \row
+ \li
+ \l{Studio:Slide Palette}{Slide palette}
+ \li
+ The slide palette shows all slides in a \l presentation or a \l component.
+ \row
+ \li
+ \target studio
+ \l{About Qt 3D Studio#Concepts}{Studio}
+ \li
+ An authoring tool for creating interactive 3D presentations and applications.
+ \row
+ \li
+ \target {sub-presentation}
+ \l{Using Sub-Presentations}{Sub-presentation}
+ \li
+ Sub-Presentations is a feature which allows a \l studio \l presentation (\l{uia}{.uia file})
+ or a QML file to be embedded in a \l studio \l presentation.
+ \row
+ \li
+ \target {time bar}
+ \l{Studio: Timeline Palette#Adjusting Time Bars}{Time bar}
+ \li
+ Each element has a time bar in the \l timeline. The time bar control the lifespan
+ during which the element is active.
+ \row
+ \li
+ \target {timeline palette}
+ \l{Studio: Timeline Palette}{Timeline palette}
+ \li
+ The timeline palette provides direct access to all elements in your scene,
+ and also gives you control over the animation and timing within a \l slide.
+
+ The timeline palette is comprised of two connected sections: the \l {scene graph} and the
+ \l {animation portion}.
+ \row
+ \li
+ \target uia
+ \l{About Qt 3D Studio#Concepts}{.uia file}
+ \li
+ The \e .uia file is the application file, it is by default located in the root folder of
+ your \l project.
+ \row
+ \li
+ \target uip
+ \l{About Qt 3D Studio#Concepts}{.uip file}
+ \li
+ The \e .iup file is a presentation file. A \l project can have one or more presentation files
+ located in \e presentations folder of your \l project.
+ \row
+ \li
+ \target viewer
+ \l{About Qt 3D Studio#Concepts}{Viewer}
+ \li
+ A runtime player to test and deploy interfaces created in \l Studio.
+\endtable
+
+*/
diff --git a/doc/src/images/area-light.png b/doc/src/images/area-light.png
new file mode 100644
index 00000000..f26e9bc1
--- /dev/null
+++ b/doc/src/images/area-light.png
Binary files differ
diff --git a/doc/src/images/directional-light-scene.png b/doc/src/images/directional-light-scene.png
new file mode 100644
index 00000000..5e98c40d
--- /dev/null
+++ b/doc/src/images/directional-light-scene.png
Binary files differ
diff --git a/doc/src/images/directional-light.png b/doc/src/images/directional-light.png
new file mode 100644
index 00000000..21ab865a
--- /dev/null
+++ b/doc/src/images/directional-light.png
Binary files differ
diff --git a/doc/src/images/exponential-fade-100.png b/doc/src/images/exponential-fade-100.png
new file mode 100644
index 00000000..1202f85c
--- /dev/null
+++ b/doc/src/images/exponential-fade-100.png
Binary files differ
diff --git a/doc/src/images/exponential-fade-20.png b/doc/src/images/exponential-fade-20.png
new file mode 100644
index 00000000..b1d40645
--- /dev/null
+++ b/doc/src/images/exponential-fade-20.png
Binary files differ
diff --git a/doc/src/images/exponential-fade-200.png b/doc/src/images/exponential-fade-200.png
new file mode 100644
index 00000000..7e6c2518
--- /dev/null
+++ b/doc/src/images/exponential-fade-200.png
Binary files differ
diff --git a/doc/src/images/exponential-fade-50.png b/doc/src/images/exponential-fade-50.png
new file mode 100644
index 00000000..cdad9cc6
--- /dev/null
+++ b/doc/src/images/exponential-fade-50.png
Binary files differ
diff --git a/doc/src/images/linear-fade-100.png b/doc/src/images/linear-fade-100.png
new file mode 100644
index 00000000..3e0e2d4a
--- /dev/null
+++ b/doc/src/images/linear-fade-100.png
Binary files differ
diff --git a/doc/src/images/linear-fade-20.png b/doc/src/images/linear-fade-20.png
new file mode 100644
index 00000000..4e3cb80d
--- /dev/null
+++ b/doc/src/images/linear-fade-20.png
Binary files differ
diff --git a/doc/src/images/linear-fade-200.png b/doc/src/images/linear-fade-200.png
new file mode 100644
index 00000000..76b191bd
--- /dev/null
+++ b/doc/src/images/linear-fade-200.png
Binary files differ
diff --git a/doc/src/images/linear-fade-50.png b/doc/src/images/linear-fade-50.png
new file mode 100644
index 00000000..aca3ab33
--- /dev/null
+++ b/doc/src/images/linear-fade-50.png
Binary files differ
diff --git a/doc/src/images/point-light-scene.png b/doc/src/images/point-light-scene.png
new file mode 100644
index 00000000..6e019a50
--- /dev/null
+++ b/doc/src/images/point-light-scene.png
Binary files differ
diff --git a/doc/src/images/point-light.png b/doc/src/images/point-light.png
new file mode 100644
index 00000000..70d198bc
--- /dev/null
+++ b/doc/src/images/point-light.png
Binary files differ
diff --git a/doc/src/images/variant-tags-layer.png b/doc/src/images/variant-tags-layer.png
new file mode 100644
index 00000000..f77527b5
--- /dev/null
+++ b/doc/src/images/variant-tags-layer.png
Binary files differ
diff --git a/doc/src/images/variant-tags-slide.png b/doc/src/images/variant-tags-slide.png
new file mode 100644
index 00000000..ecf868d4
--- /dev/null
+++ b/doc/src/images/variant-tags-slide.png
Binary files differ
diff --git a/doc/src/images/variant-tags.png b/doc/src/images/variant-tags.png
new file mode 100644
index 00000000..3eedc308
--- /dev/null
+++ b/doc/src/images/variant-tags.png
Binary files differ
diff --git a/doc/src/known-issues.qdoc b/doc/src/known-issues.qdoc
new file mode 100644
index 00000000..6eb002bf
--- /dev/null
+++ b/doc/src/known-issues.qdoc
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 Known Issues
+\page known-issues.html
+
+This section lists known issues in Qt 3D Studio. The development team is aware of them,
+and therefore, you do not need to report them as bugs.
+
+\section1 Possible Problems After Automatic Mesh Optimization
+
+When loading a presentation made with an earlier version (2.0 beta2 or older) of Qt 3D Studio
+which has imported FBX or DAE models, you may see the following message box:
+
+\image {mesh_optimization.png}{Old presentation version}
+
+If your \b{imported} models are not visible in the Viewer after seeing the message, you need to
+edit your \e .uip files manually. Some older versions of Studio referenced meshes with revision
+number in the \e .uip file, and that revision causes it to be missing in the scope of the
+Viewer.
+
+You need to find all occurrences of \c{.mesh#<revision_number>} from your \e .uip files and
+replace them with \c{.mesh}.
+
+\section1 QML Stream with Window Element Causes Viewer Crash
+
+Opening a project that has a QML stream including a Window element causes the viewer to crash.
+
+\section1 Changes to Material Definitions Saved Separately from the Project
+
+When importing a 3D model to your project, a material definition file is created for each material
+in the model. Material definitions are stored separately from the project, meaning that all
+changes to these materials are saved even if the project is not saved.
+
+Refreshing the 3D model import file resets the material properties.
+
+*/
diff --git a/doc/src/layers.qdoc b/doc/src/layers.qdoc
index 1128e0c1..6bec78dc 100644
--- a/doc/src/layers.qdoc
+++ b/doc/src/layers.qdoc
@@ -112,4 +112,8 @@ the colors of the background layer or object.
The \l{Disable Depth Test} property can be used to simultaneously override depth testing and
the order objects are rendered.
+\section2 Variant Tags
+\l{Using Variant Tags}{Variant tags} makes it possible to exclude layers during loading to
+optimize performance.
+
*/
diff --git a/doc/src/lights.qdoc b/doc/src/lights.qdoc
new file mode 100644
index 00000000..2776f8c9
--- /dev/null
+++ b/doc/src/lights.qdoc
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 Lights
+\page lights.html
+
+Lights are the primary source to provide lighting in a Studio scene. Another way to light a
+scene is \l{Using Image-based Lighting}{Image Based Lighting}.
+
+By default, all new presentations will be created with one directional light in them. Additionally,
+all layers created will be created with one directional light on them. The default scope of a light
+is the layer they are located on, meaning that all objects on that layer will be effected by the
+light.
+
+\note Each additional light will reduce rendering performance of your presentation. Keep it
+as simple as possible and use lights sparingly.
+
+\section1 Light Types
+
+\section2 Directional
+
+The directional light emits light in one direction from a unidentifiable source located infinitely
+far away. This is similar to the way sun light works in real life. If
+\l {light properties}{Cast Shadows} is enabled, shadows will be parallel to the light direction.
+A directional light has infinite range and does not diminish.
+
+\image directional-light.png
+
+Moving a directional light does not have any effect. The light will always
+be emitted in the direction of the lights Z axis, rotating the light along its X or Y axis will
+change the direction the light is emitted.
+
+Scaling a directional light will only have an effect in the following cases:
+
+\list
+ \li
+ If Z scale is set to a negative number, the light will be emitted in opposite direction.
+ \li
+ If the scale of any axis is set to 0, the light will be emitted along the world's Z axis.
+ Rotating the light will then have no effect.
+\endlist
+
+\image directional-light-scene.png
+
+By default, all new light objects created in Studio will be directional lights.
+
+\section2 Point
+
+The point light can be described as a sphere, emitting light with equal strength in all directions
+from the center of the light. This is similar to the way a light bulb emits light.
+
+\image point-light.png
+
+Rotating or scaling a point light does not have any effect. Moving a point light will change the
+position from where the light is emitted.
+
+\image point-light-scene.png
+
+By default, a point light has infinite range and does not diminish. However, the fade-off
+(and range) can be controlled with the \l {light properties}{Linear Fade}
+and \l {light properties}{Exponential Fade} properties.
+
+The table below shows the difference between linear and exponential fade. In this example the Z
+position of the light is 0, while the Z position of the cubes are 200, 400 and 700
+respectively. The brightness of the light is 200.
+
+\table
+ \header
+ \li
+ \li {4,1} Fade value
+ \row
+ \li
+ \li 20
+ \li 50
+ \li 100
+ \li 200
+ \row
+ \li Linear fade
+ \li \image linear-fade-20.png
+ \li \image linear-fade-50.png
+ \li \image linear-fade-100.png
+ \li \image linear-fade-200.png
+ \row
+ \li Exponential fade
+ \li \image exponential-fade-20.png
+ \li \image exponential-fade-50.png
+ \li \image exponential-fade-100.png
+ \li \image exponential-fade-200.png
+\endtable
+
+\section2 Area
+
+The area light is similar to the directional light, but instead of emitting equally bright light
+across the whole scene, the area light emits directional light from a rectangle shaped object. Aside
+from the size, an area light has the same characteristics and properties as the directional light.
+
+The image below shows an example on how to light an object with different colors using two
+different area lights.
+
+\image area-light.png
+
+Rotating, scaling and moving actions will all effect an area light.
+
+\section1 Working with Lights
+
+\section2 Add Lights
+
+To add a light to a layer, drag it from the basic objects palette to either the scene graph or the
+scene view.
+
+\section2 Delete Lights
+To delete a light, do one of the following:
+
+\list 1
+ \li Select the light in the scene graph or scene view, next press the \c Del key.
+ \li Right-click the light in the scene graph, next select \uicontrol {Delete Object} from the
+ context menu.
+\endlist
+
+\section1 Animating Lights
+
+It is possible to animate most of the properties for lights. To read more about animations, see
+the \l {Animations} section.
+
+\section1 Light Properties
+
+For full details on all light properties, see the
+\l{studio-inspector-palette.html#light-properties}{inspector palette documentation}.
+
+*/
diff --git a/doc/src/tutorials.qdoc b/doc/src/tutorials.qdoc
index c7b4d4ab..32ab7bc0 100644
--- a/doc/src/tutorials.qdoc
+++ b/doc/src/tutorials.qdoc
@@ -52,6 +52,10 @@
\l {Using Behavior Scripts}
Learn how to use behavior scripts in your project.
+ \li
+ \l {Using Variant Tags}
+
+ Learn how to use variant tags to exclude parts of a presentation during loading.
\endlist
*/
diff --git a/doc/src/variant-tags.qdoc b/doc/src/variant-tags.qdoc
new file mode 100644
index 00000000..142bce50
--- /dev/null
+++ b/doc/src/variant-tags.qdoc
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 Using Variant Tags
+\page using-variant-tags.html
+
+The variant tags feature in 3D Studio enables excluding parts of a presentation during loading.
+With variant tags you can avoid parsing and loading objects that are not needed in the presentation
+for certain variants, saving on loading time and resource usage.
+
+This makes it possible to create multiple variations of a product UI with one single Qt 3D Studio
+presentation.
+
+This page explains how to define and use variant tags in the editor. The variant tags will then
+be loaded from the QML application.
+
+\image variant-tags.png
+
+\section1 Create Variant Groups and Tags
+
+Variant filtering is done on layer level, to add a variant group and tags to that group,
+select a layer in the scene graph and follow the steps below:
+
+\list 1
+ \li In the inspector palette, press \uicontrol {+ Group} in the Variant Tags section.
+ \li Enter a group name, and press \uicontrol {Ok}.
+ \note Group names must be unique to the project.
+\endlist
+
+Once you have created a variant group, you can create variant tags under it. To do so,
+follow the steps below:
+
+\list 1
+ \li In the inspector palette, press the \uicontrol {+ Tag} next to the variant group name.
+ \li Enter a tag name, and press \uicontrol {Ok}.
+ \note Tag names must be unique to the variant group.
+\endlist
+
+\section1 Using Variant Tags
+
+To use a variant tag on a layer, follow the steps below:
+
+\list 1
+ \li In the scene graph, select desired layer
+ \li In the inspector palette, under the variant tag section, click desired variant tags to use
+ them on the layer.
+\endlist
+
+Once you have assigned variant tags to a layer, it is indicated in the scene graph which layers
+are using tags from which variant groups.
+
+\image variant-tags-layer.png
+
+It is also indicated in the slide palette, which slides are using tags from which variant groups.
+Here you can see the number of tags from each variant group used on each slide.
+
+\image variant-tags-slide.png
+
+\section1 Edit Variant Groups and Tags
+
+\section2 Edit a Variant Group
+
+You can edit name and color of a variant group. To do so, right-click the name of it in the
+inspector palette and select desired action from the context menu.
+
+\section2 Edit a Variant Tag
+You can edit the name of a variant tag. To do so, right-click the name of it in the inspector
+palette and select \uicontrol {Rename Tag} from the context menu.
+
+\section2 Delete a Variant Tag or Group
+
+You can delete a variant tag or group by right-clicking the name of it in the inspector palette and
+select \uicontrol {Delete Tag/Group}.
+
+\section1 Importing and Exporting Variant Groups
+
+You can import and export variant groups. Exporting will export all variant groups and tags to a
+\c {.variants} file, default location for the export file is the project's \e presentation folder.
+
+\section2 Export Variant Groups
+
+To export variant groups, select the \uicontrol {Export} button in the variant tags section
+in the inspector palette. Next, browse to the desired location, enter a file name,
+and press \uicontrol {Save}.
+
+\section2 Import Variant Groups
+
+To import variant groups, select the \uicontrol {Import} button in the variant tags section
+in the inspector palette. Next, browse to the desired \c .variants or \c .uia file and select
+\uicontrol{Ok}.
+
+When importing variant tags, imported tags will be merged with already existing tags.
+
+*/
diff --git a/src/Authoring/Client/Code/Core/Core/Core.cpp b/src/Authoring/Client/Code/Core/Core/Core.cpp
index e4e31267..46e4c646 100644
--- a/src/Authoring/Client/Code/Core/Core/Core.cpp
+++ b/src/Authoring/Client/Code/Core/Core/Core.cpp
@@ -274,6 +274,7 @@ bool CCore::OnNewDocument(const QString &inDocument, bool isNewProject, bool sil
// write a new presentation node to the uia file
m_projectFile.addPresentationNode(theDocument);
m_projectFile.updateDocPresentationId();
+ m_projectFile.loadVariants();
m_projectFile.loadSubpresentationsAndDatainputs(g_StudioApp.m_subpresentations,
g_StudioApp.m_dataInputDialogItems);
g_StudioApp.getRenderer().RegisterSubpresentations(g_StudioApp.m_subpresentations);
diff --git a/src/Authoring/Client/Code/Core/Doc/Doc.cpp b/src/Authoring/Client/Code/Core/Doc/Doc.cpp
index 599e0306..a59529d5 100644
--- a/src/Authoring/Client/Code/Core/Doc/Doc.cpp
+++ b/src/Authoring/Client/Code/Core/Doc/Doc.cpp
@@ -719,18 +719,14 @@ qt3dsdm::Qt3DSDMInstanceHandle CDoc::GetFirstSelectableLayer()
QVector<qt3dsdm::Qt3DSDMInstanceHandle> CDoc::getLayers()
{
- CClientDataModelBridge *bridge = m_StudioSystem->GetClientDataModelBridge();
-
Q3DStudio::CGraphIterator layerIterator;
GetAssetChildren(this, m_SceneInstance, layerIterator, OBJTYPE_LAYER);
QVector<qt3dsdm::Qt3DSDMInstanceHandle> layerList;
for (; !layerIterator.IsDone(); ++layerIterator) {
- if (m_StudioSystem->IsInstance(layerIterator.GetCurrent())
- && !bridge->IsLockedAtAll(layerIterator.GetCurrent())) {
+ if (m_StudioSystem->IsInstance(layerIterator.GetCurrent()))
layerList.append(layerIterator.GetCurrent());
- }
}
return layerList;
@@ -2373,7 +2369,7 @@ std::shared_ptr<Q3DStudio::IComposerSerializer> CDoc::CreateSerializer()
*theCoreSystem.GetActionCore(), *m_AssetGraph, *theFullSystem.GetSlideSystem(),
*theFullSystem.GetActionSystem(), *theCoreSystem.GetSlideGraphCore(),
theClientBridge.GetObjectDefinitions(), m_ImportFailedHandler,
- *theCoreSystem.GetGuideSystem());
+ *theCoreSystem.GetGuideSystem(), *theFullSystem.GetPropertySystem());
}
std::shared_ptr<Q3DStudio::IComposerSerializer> CDoc::CreateTransactionlessSerializer()
@@ -2390,9 +2386,9 @@ std::shared_ptr<Q3DStudio::IComposerSerializer> CDoc::CreateTransactionlessSeria
*theCoreSystem.GetTransactionlessAnimationCore(),
*theCoreSystem.GetTransactionlessActionCore(), *m_AssetGraph,
*theFullSystem.GetSlideSystem(), *theFullSystem.GetActionSystem(),
- *theCoreSystem.GetTransactionlessSlideGraphCore(), theClientBridge.GetObjectDefinitions(),
- m_ImportFailedHandler, *theCoreSystem.GetGuideSystem());
-
+ *theCoreSystem.GetTransactionlessSlideGraphCore(),
+ theClientBridge.GetObjectDefinitions(), m_ImportFailedHandler,
+ *theCoreSystem.GetGuideSystem(), *theFullSystem.GetPropertySystem());
}
std::shared_ptr<qt3dsdm::IDOMWriter> CDoc::CreateDOMWriter()
diff --git a/src/Authoring/Client/Code/Core/Doc/Doc.h b/src/Authoring/Client/Code/Core/Doc/Doc.h
index dad6b365..1cf64168 100644
--- a/src/Authoring/Client/Code/Core/Doc/Doc.h
+++ b/src/Authoring/Client/Code/Core/Doc/Doc.h
@@ -182,6 +182,11 @@ public:
QString name;
int type;
QVector<ControlledItem> ctrldElems;
+ // As per QT3DS-2992 we currently need only a single key-value pair per datainput.
+ // For efficiency we use separate QStrings for both, as there is no need for more
+ // elaborate containers.
+ QString metaDataKey;
+ QString metaData;
// Bindings in other subpresentations, of QMap format
// QMultiMap<subpresentation_id, QPair<datatype, strict>>.
diff --git a/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp b/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp
index 3a1907b7..4307b310 100644
--- a/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp
+++ b/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp
@@ -335,6 +335,7 @@ struct SComposerSerializerImpl : public IComposerSerializer
SComposerObjectDefinitions &m_ObjectDefinitions;
qt3dsdm::IStringTable &m_StringTable;
std::shared_ptr<Q3DStudio::IImportFailedHandler> m_ImportFailedHandler;
+ IPropertySystem &m_propertySystem;
// The instances we have discovered when we are writing
THandleToIdMap m_HandleToIdMap;
@@ -390,7 +391,7 @@ struct SComposerSerializerImpl : public IComposerSerializer
IActionSystem &inActionSystem, ISlideGraphCore &inSlideGraphCore,
SComposerObjectDefinitions &inObjectDefinitions,
std::shared_ptr<Q3DStudio::IImportFailedHandler> inFailedHandler,
- IGuideSystem &inGuideSystem)
+ IGuideSystem &inGuideSystem, IPropertySystem &inPropSystem)
: m_DataCore(inDataCore)
, m_MetaData(inMetaData)
, m_SlideCore(inSlideCore)
@@ -404,6 +405,7 @@ struct SComposerSerializerImpl : public IComposerSerializer
, m_ObjectDefinitions(inObjectDefinitions)
, m_StringTable(inDataCore.GetStringTable())
, m_ImportFailedHandler(inFailedHandler)
+ , m_propertySystem(inPropSystem)
, m_Foundation(Q3DStudio::Foundation::SStudioFoundation::Create())
, m_InputStreamFactory(Q3DStudio::IInputStreamFactory::Create())
, m_PreserveFileIds(true)
@@ -942,8 +944,11 @@ struct SComposerSerializerImpl : public IComposerSerializer
const pair<Qt3DSDMPropertyHandle, SValue> &theValue(inList[idx]);
QString theName(m_DataCore.GetProperty(theValue.first).m_Name);
WriteDataModelValue(theValue.second, theValueStr);
- if (GetValueType(theValue.second) == DataModelDataType::String || theValueStr.size())
- inWriter.Att(theName, theValueStr);
+ if (GetValueType(theValue.second) == DataModelDataType::String || theValueStr.size()) {
+ // this property is saved under the <Graph> node
+ if (theName != QStringLiteral("variants"))
+ inWriter.Att(theName, theValueStr);
+ }
}
}
@@ -1627,7 +1632,16 @@ struct SComposerSerializerImpl : public IComposerSerializer
}
IDOMWriter::Scope __instanceScope(inWriter, theType);
- inWriter.Att(L"id", GetInstanceId(inInstance));
+ inWriter.Att(QStringLiteral("id"), GetInstanceId(inInstance));
+
+ // for layers, save the variants property under the <Graph>
+ if (theType.getValue() == QStringLiteral("Layer")) {
+ auto prop = m_propertySystem.GetAggregateInstancePropertyByName(
+ inInstance, QStringLiteral("variants"));
+ SValue sVal;
+ if (m_propertySystem.GetInstancePropertyValue(inInstance, prop, sVal))
+ inWriter.Att(QStringLiteral("variants"), get<QString>(sVal));
+ }
m_InstanceSet.insert(inInstance);
@@ -2832,12 +2846,15 @@ struct SComposerSerializerImpl : public IComposerSerializer
std::shared_ptr<IComposerSerializer> IComposerSerializer::CreateGraphSlideSerializer(
IDataCore &inDataCore, IMetaData &inMetaData, ISlideCore &inSlideCore,
IAnimationCore &inAnimationCore, IActionCore &inActionCore, CGraph &inAssetGraph,
- ISlideSystem &inSlideSystem, IActionSystem &inActionSystem, ISlideGraphCore &inSlideGraphCore,
+ ISlideSystem &inSlideSystem, IActionSystem &inActionSystem,
+ ISlideGraphCore &inSlideGraphCore,
SComposerObjectDefinitions &inObjectDefinitions,
- std::shared_ptr<Q3DStudio::IImportFailedHandler> inFailedHandler, IGuideSystem &inGuideSystem)
+ std::shared_ptr<Q3DStudio::IImportFailedHandler> inFailedHandler,
+ IGuideSystem &inGuideSystem, IPropertySystem &inPropSystem)
{
- return std::shared_ptr<SComposerSerializerImpl>(new SComposerSerializerImpl(
- inDataCore, inMetaData, inSlideCore, inAnimationCore, inActionCore, inAssetGraph,
- inSlideSystem, inActionSystem, inSlideGraphCore, inObjectDefinitions, inFailedHandler,
- inGuideSystem));
+ return std::shared_ptr<SComposerSerializerImpl>(
+ new SComposerSerializerImpl(
+ inDataCore, inMetaData, inSlideCore, inAnimationCore, inActionCore,
+ inAssetGraph, inSlideSystem, inActionSystem, inSlideGraphCore,
+ inObjectDefinitions, inFailedHandler, inGuideSystem, inPropSystem));
}
diff --git a/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.h b/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.h
index 301a8144..1a18b262 100644
--- a/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.h
+++ b/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.h
@@ -49,6 +49,7 @@ class IActionSystem;
class ISlideGraphCore;
class IGuideSystem;
class SComposerObjectDefinitions;
+class IPropertySystem;
};
namespace Q3DStudio {
@@ -102,13 +103,14 @@ public:
friend class std::shared_ptr<IComposerSerializer>;
static std::shared_ptr<IComposerSerializer> CreateGraphSlideSerializer(
- qt3dsdm::IDataCore &inDataCore, qt3dsdm::IMetaData &inMetaData, qt3dsdm::ISlideCore &inSlideCore,
- qt3dsdm::IAnimationCore &inAnimationCore, qt3dsdm::IActionCore &inActionCore,
- CGraph &inAssetGraph, qt3dsdm::ISlideSystem &inSlideSystem,
- qt3dsdm::IActionSystem &inActionSystem, qt3dsdm::ISlideGraphCore &inSlideGraphCore,
- qt3dsdm::SComposerObjectDefinitions &inObjectDefinitions,
- std::shared_ptr<Q3DStudio::IImportFailedHandler> inFailedHandler,
- qt3dsdm::IGuideSystem &inGuideSystem);
+ qt3dsdm::IDataCore &inDataCore, qt3dsdm::IMetaData &inMetaData,
+ qt3dsdm::ISlideCore &inSlideCore,
+ qt3dsdm::IAnimationCore &inAnimationCore, qt3dsdm::IActionCore &inActionCore,
+ CGraph &inAssetGraph, qt3dsdm::ISlideSystem &inSlideSystem,
+ qt3dsdm::IActionSystem &inActionSystem, qt3dsdm::ISlideGraphCore &inSlideGraphCore,
+ qt3dsdm::SComposerObjectDefinitions &inObjectDefinitions,
+ std::shared_ptr<Q3DStudio::IImportFailedHandler> inFailedHandler,
+ qt3dsdm::IGuideSystem &inGuideSystem, qt3dsdm::IPropertySystem &inPropSystem);
};
}
diff --git a/src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h b/src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h
index da45d8a7..df028c3f 100644
--- a/src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h
+++ b/src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h
@@ -28,21 +28,14 @@
****************************************************************************/
#ifndef INCLUDED_IKEYFRAMES_MANAGER_H
-#define INCLUDED_IKEYFRAMES_MANAGER_H 1
+#define INCLUDED_IKEYFRAMES_MANAGER_H
-#pragma once
-
-//=============================================================================
-/**
- * Interface to manage keyframes related actions
- */
-//=============================================================================
class IKeyframesManager
{
public:
virtual ~IKeyframesManager() {}
- virtual bool HasSelectedKeyframes(bool inOnlyDynamic = false) = 0;
+ virtual bool HasSelectedKeyframes() = 0;
virtual bool HasDynamicKeyframes() = 0;
virtual bool CanPerformKeyframeCopy() = 0;
virtual bool CanPerformKeyframePaste() = 0;
@@ -50,9 +43,13 @@ public:
virtual bool RemoveKeyframes(bool inPerformCopy) = 0;
virtual void PasteKeyframes() = 0;
virtual void SetKeyframeInterpolation() = 0;
- virtual void SelectAllKeyframes() = 0;
virtual void DeselectAllKeyframes() = 0;
virtual void SetChangedKeyframes() = 0;
+
+ virtual void SetKeyframeTime(long inTime) = 0;
+ virtual void SetKeyframesDynamic(bool inDynamic) = 0;
+ virtual void CommitChangedKeyframes() = 0;
+ virtual void RollbackChangedKeyframes() = 0;
};
#endif // INCLUDED_IKEYFRAMES_MANAGER_H
diff --git a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp
index 810f9f3d..36d4956b 100644
--- a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp
+++ b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp
@@ -83,6 +83,8 @@ static QColor s_timelinePlayheadLineColor;
static QColor s_timelineFilterButtonSelectedColor;
static QColor s_timelineFilterButtonHoveredColor;
static QColor s_timelineRowCommentBgColor;
+static QColor s_timelinePressedKeyframeColor; // pressed keyframe from multiple selection
+static QColor s_invalidDataInputIndicatorColor;
static int s_fontSize;
static int s_controlBaseHeight;
@@ -195,6 +197,9 @@ void CStudioPreferences::loadPreferences(const QString &filePath)
s_timelineRowSubpColor = QColor("#e2ceff");
s_timelineRowSubpDescendantColor = QColor("#a263ff");
s_timelineRowCommentBgColor = QColor("#d0000000");
+ s_timelinePressedKeyframeColor = QColor("#ffff00");
+
+ s_invalidDataInputIndicatorColor = QColor("#ff2121");
s_fontSize = 12;
s_controlBaseHeight = 22;
@@ -1053,6 +1058,16 @@ QColor CStudioPreferences::timelineRowCommentBgColor()
return s_timelineRowCommentBgColor;
}
+QColor CStudioPreferences::timelinePressedKeyframeColor()
+{
+ return s_timelinePressedKeyframeColor;
+}
+
+QColor CStudioPreferences::invalidDataInputIndicatorColor()
+{
+ return s_invalidDataInputIndicatorColor;
+}
+
int CStudioPreferences::fontSize()
{
return s_fontSize;
diff --git a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h
index a138bd5c..ed9da243 100644
--- a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h
+++ b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h
@@ -197,6 +197,9 @@ public:
static QColor timelineRowSubpColor();
static QColor timelineRowSubpDescendantColor();
static QColor timelineRowCommentBgColor();
+ static QColor timelinePressedKeyframeColor();
+
+ static QColor invalidDataInputIndicatorColor();
static int fontSize();
static int controlBaseHeight();
diff --git a/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp b/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp
index 83e9384b..e3f3e97b 100644
--- a/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp
+++ b/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp
@@ -316,6 +316,7 @@ struct DataConstructor<SObjectRefType>
#define QT3DS_PROPNAME_lightmapradiosity "lightmapradiosity"
#define QT3DS_PROPNAME_lightmapshadow "lightmapshadow"
#define QT3DS_PROPNAME_controlledproperty "controlledproperty"
+#define QT3DS_PROPNAME_variants "variants"
QString ComposerObjectTypes::Convert(ComposerObjectTypes::Enum inType)
{
@@ -337,7 +338,7 @@ ComposerObjectTypes::Enum ComposerObjectTypes::Convert(const QString &inType)
{
#define HANDLE_COMPOSER_OBJECT_TYPE(name, propmacro) \
- if (inType == QLatin1String(QT3DS_PROPNAME_##name)) \
+ if (inType == QLatin1String(QT3DS_PROPNAME_##name)) \
return ComposerObjectTypes::name;
ITERATE_COMPOSER_OBJECT_TYPES
#undef HANDLE_COMPOSER_OBJECT_TYPE
@@ -372,7 +373,7 @@ ComposerPropertyNames::Enum ComposerPropertyNames::Convert(const QString &inType
{
#define HANDLE_COMPOSER_PROPERTY_DUPLICATE(name, memberName, type, defaultValue)
#define HANDLE_COMPOSER_PROPERTY_NO_DEFAULT(name, memberName, type) \
- if (inType == QLatin1String(QT3DS_PROPNAME_##name)) \
+ if (inType == QLatin1String(QT3DS_PROPNAME_##name)) \
return name;
#define HANDLE_COMPOSER_PROPERTY(name, memberName, type, defaultValue) \
HANDLE_COMPOSER_PROPERTY_NO_DEFAULT(name, memberName, type)
@@ -397,11 +398,11 @@ ComposerPropertyNames::Enum ComposerPropertyNames::Convert(const QString &inType
#define HANDLE_COMPOSER_OBJECT_TYPE(name, propmacro) \
SComposerTypePropertyDefinition<ComposerObjectTypes::name>::SComposerTypePropertyDefinition( \
- IDataCore &inCore, Qt3DSDMInstanceHandle inInstance) \
- : reserved(false) propmacro \
- { \
- Q_UNUSED(inCore);\
- Q_UNUSED(inInstance);\
+ IDataCore &inCore, Qt3DSDMInstanceHandle inInstance) \
+ : reserved(false) propmacro \
+ { \
+ Q_UNUSED(inCore); \
+ Q_UNUSED(inInstance); \
}
ITERATE_COMPOSER_OBJECT_TYPES
#undef HANDLE_COMPOSER_OBJECT_TYPE
diff --git a/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h b/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h
index 4d54ea07..172e53ab 100644
--- a/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h
+++ b/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h
@@ -70,7 +70,7 @@ class IPropertySystem;
HANDLE_COMPOSER_OBJECT_TYPE(Model, ITERATE_COMPOSER_MODEL_PROPERTIES) \
HANDLE_COMPOSER_OBJECT_TYPE(Light, ITERATE_COMPOSER_LIGHT_PROPERTIES) \
HANDLE_COMPOSER_OBJECT_TYPE(Camera, ITERATE_COMPOSER_CAMERA_PROPERTIES) \
- HANDLE_COMPOSER_OBJECT_TYPE(Component, ITERATE_COMPOSER_COMPONENT_PROPERTIES) \
+ HANDLE_COMPOSER_OBJECT_TYPE(Component, ITERATE_COMPOSER_COMPONENT_PROPERTIES) \
HANDLE_COMPOSER_OBJECT_TYPE(Text, ITERATE_COMPOSER_TEXT_PROPERTIES) \
HANDLE_COMPOSER_OBJECT_TYPE(RenderPlugin, ITERATE_COMPOSER_NO_ADDITIONAL_PROPERTIES) \
HANDLE_COMPOSER_OBJECT_TYPE(Alias, ITERATE_COMPOSER_ALIAS_PROPERTIES) \
@@ -93,8 +93,8 @@ class IPropertySystem;
HANDLE_COMPOSER_PROPERTY(importid, m_ImportId, TDataStrPtr, L"") \
HANDLE_COMPOSER_PROPERTY(importfile, m_ImportFile, TDataStrPtr, L"") \
HANDLE_COMPOSER_PROPERTY(fileid, m_FileId, TDataStrPtr, L"") \
- HANDLE_COMPOSER_PROPERTY(starttime, m_StartTime, qt3ds::QT3DSI32, 0) \
- HANDLE_COMPOSER_PROPERTY(endtime, m_EndTime, qt3ds::QT3DSI32, 10000) \
+ HANDLE_COMPOSER_PROPERTY(starttime, m_StartTime, qt3ds::QT3DSI32, 0) \
+ HANDLE_COMPOSER_PROPERTY(endtime, m_EndTime, qt3ds::QT3DSI32, 10000) \
HANDLE_COMPOSER_PROPERTY(eyeball, m_Eyeball, bool, true) \
HANDLE_COMPOSER_PROPERTY(shy, m_Shy, bool, false) \
HANDLE_COMPOSER_PROPERTY(locked, m_Locked, bool, false) \
@@ -118,12 +118,12 @@ class IPropertySystem;
HANDLE_COMPOSER_PROPERTY(opacity, m_Opacity, float, 100.f) \
HANDLE_COMPOSER_PROPERTY(rotationorder, m_RotationOrder, TDataStrPtr, L"YXZ") \
HANDLE_COMPOSER_PROPERTY(orientation, m_Orientation, TDataStrPtr, L"Left Handed") \
- HANDLE_COMPOSER_PROPERTY(boneid, m_BoneId, qt3ds::QT3DSI32, 0) \
+ HANDLE_COMPOSER_PROPERTY(boneid, m_BoneId, qt3ds::QT3DSI32, 0) \
HANDLE_COMPOSER_PROPERTY(ignoresparent, m_IgnoresParent, bool, false) \
HANDLE_COMPOSER_PROPERTY_DUPLICATE(controlledproperty, m_ControlledProperty, TDataStrPtr, L"")
#define ITERATE_COMPOSER_MODEL_PROPERTIES \
- HANDLE_COMPOSER_PROPERTY(poseroot, m_PoseRoot, qt3ds::QT3DSI32, -1) \
+ HANDLE_COMPOSER_PROPERTY(poseroot, m_PoseRoot, qt3ds::QT3DSI32, -1) \
HANDLE_COMPOSER_PROPERTY(tessellation, m_Tessellation, TDataStrPtr, L"None") \
HANDLE_COMPOSER_PROPERTY(edgetess, m_EdgeTess, float, 1.0) \
HANDLE_COMPOSER_PROPERTY(innertess, m_InnerTess, float, 1.0) \
@@ -219,7 +219,7 @@ class IPropertySystem;
HANDLE_COMPOSER_PROPERTY(aodistance, m_AoDistance, float, 0) \
HANDLE_COMPOSER_PROPERTY(aosoftness, m_AoSoftness, float, 0) \
HANDLE_COMPOSER_PROPERTY(aobias, m_AoBias, float, 0) \
- HANDLE_COMPOSER_PROPERTY(aosamplerate, m_AoSamplerate, qt3ds::QT3DSI32, 1) \
+ HANDLE_COMPOSER_PROPERTY(aosamplerate, m_AoSamplerate, qt3ds::QT3DSI32, 1) \
HANDLE_COMPOSER_PROPERTY(aodither, m_AoDither, bool, false) \
HANDLE_COMPOSER_PROPERTY(shadowstrength, m_ShadowStrength, float, 0) \
HANDLE_COMPOSER_PROPERTY(shadowdist, m_ShadowDist, float, 0) \
@@ -234,6 +234,7 @@ class IPropertySystem;
HANDLE_COMPOSER_PROPERTY(probe2fade, m_Probe2Fade, float, 1) \
HANDLE_COMPOSER_PROPERTY(probe2window, m_Probe2Window, float, 1) \
HANDLE_COMPOSER_PROPERTY(probe2pos, m_Probe2Pos, float, 0.5f) \
+ HANDLE_COMPOSER_PROPERTY(variants, m_variants, TDataStrPtr, L"") \
HANDLE_COMPOSER_PROPERTY_DUPLICATE(controlledproperty, m_ControlledProperty, TDataStrPtr, L"")
#define ITERATE_COMPOSER_LIGHT_PROPERTIES \
@@ -250,7 +251,7 @@ class IPropertySystem;
HANDLE_COMPOSER_PROPERTY(castshadow, m_CastShadow, bool, false) \
HANDLE_COMPOSER_PROPERTY(shdwbias, m_ShadowBias, float, 0.0f) \
HANDLE_COMPOSER_PROPERTY(shdwfactor, m_ShadowFactor, float, 5.0f) \
- HANDLE_COMPOSER_PROPERTY(shdwmapres, m_ShadowMapRes, qt3ds::QT3DSI32, 9) \
+ HANDLE_COMPOSER_PROPERTY(shdwmapres, m_ShadowMapRes, qt3ds::QT3DSI32, 9) \
HANDLE_COMPOSER_PROPERTY(shdwmapfar, m_ShadowMapFar, float, 5000.0f) \
HANDLE_COMPOSER_PROPERTY(shdwmapfov, m_ShadowMapFov, float, 90.0f) \
HANDLE_COMPOSER_PROPERTY(shdwfilter, m_ShadowFilter, float, 35.0f) \
@@ -280,13 +281,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(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(elide, m_Elide, TDataStrPtr, L"ElideNone") \
HANDLE_COMPOSER_PROPERTY(enableacceleratedfont, m_EnableAcceleratedFont, bool, false) \
HANDLE_COMPOSER_PROPERTY_DUPLICATE(controlledproperty, m_ControlledProperty, TDataStrPtr, L"")
@@ -373,14 +374,14 @@ struct DataTypeToTypeMap
bool force_compile_error;
};
-#define QT3DSDM_DEFINE_TYPE_TO_DATA_TYPE(enumName, type) \
+#define QT3DSDM_DEFINE_TYPE_TO_DATA_TYPE(enumName, type) \
template <> \
struct TypeToDataTypeMap<type> \
{ \
- static DataModelDataType::Value GetDataType() { return enumName; } \
+ static DataModelDataType::Value GetDataType() { return enumName; } \
}; \
template <> \
- struct DataTypeToTypeMap<enumName> \
+ struct DataTypeToTypeMap<enumName> \
{ \
typedef type TDataType; \
};
@@ -449,9 +450,9 @@ struct SComposerTypePropertyDefinition
template <> \
struct SComposerTypePropertyDefinition<ComposerObjectTypes::name> \
{ \
- bool reserved; \
+ bool reserved; \
propmacro SComposerTypePropertyDefinition(IDataCore &inCore, \
- Qt3DSDMInstanceHandle inInstance); \
+ Qt3DSDMInstanceHandle inInstance); \
};
ITERATE_COMPOSER_OBJECT_TYPES
@@ -933,7 +934,7 @@ public:
IDataCore &inDataCore,
IMetaData &inMetaData /*, ISlideCore& inSlideCore, IPropertySystem& inPropertySystem */);
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////////////////////
// RTTI API
bool IsA(Qt3DSDMInstanceHandle inInstance, ComposerObjectTypes::Enum inType);
// Could easily return None, meaning we can't identify the object type.
diff --git a/src/Authoring/Studio/Application/DataInputDlg.cpp b/src/Authoring/Studio/Application/DataInputDlg.cpp
index 0a31424d..9bfec2a0 100644
--- a/src/Authoring/Studio/Application/DataInputDlg.cpp
+++ b/src/Authoring/Studio/Application/DataInputDlg.cpp
@@ -28,6 +28,7 @@
#include "DataInputDlg.h"
#include "ui_DataInputDlg.h"
+#include "Qt3DSMessageBox.h"
#include <QtWidgets/qabstractbutton.h>
#include <QtGui/qstandarditemmodel.h>
@@ -43,6 +44,8 @@ CDataInputDlg::CDataInputDlg(CDataInputDialogItem **datainput, QStandardItemMode
, m_type(0)
, m_min(0.0)
, m_max(10.0)
+ , m_metadataKey(m_dataInput->metaDataKey)
+ , m_metadata(m_dataInput->metaData)
, m_acceptedTypes(acceptedTypes)
{
m_ui->setupUi(this);
@@ -87,6 +90,10 @@ CDataInputDlg::CDataInputDlg(CDataInputDialogItem **datainput, QStandardItemMode
this, &CDataInputDlg::onMaxChanged);
connect(m_ui->lineEditInputName, &QLineEdit::textChanged, this, &CDataInputDlg::onNameChanged);
connect(m_ui->lineEditEvaluation, &QLineEdit::textChanged, this, &CDataInputDlg::onTextChanged);
+ connect(m_ui->lineEditMetadata, &QLineEdit::textChanged, this,
+ &CDataInputDlg::onMetadataChanged);
+ connect(m_ui->lineEditMetadataKey, &QLineEdit::textChanged, this,
+ &CDataInputDlg::onMetadataKeyChanged);
}
CDataInputDlg::~CDataInputDlg()
@@ -127,11 +134,20 @@ void CDataInputDlg::initDialog()
m_ui->doubleSpinBoxMax->setValue(m_dataInput->maxValue);
}
+ m_metadata = m_dataInput->metaData;
+ m_metadataKey = m_dataInput->metaDataKey;
+ m_ui->lineEditMetadata->setText(m_metadata);
+ m_ui->lineEditMetadataKey->setText(m_metadataKey);
updateVisibility(m_dataInput->type);
}
void CDataInputDlg::accept()
{
+ if (m_metadataKey.isEmpty() && !m_metadata.isEmpty()) {
+ Qt3DSMessageBox::Show(tr("Metadata Error"), tr("Metadata key cannot be empty."),
+ Qt3DSMessageBox::ICON_WARNING, false, this);
+ return;
+ }
if (m_dataInput->name != m_name)
m_dataInput->name = getUniqueId(m_name);
@@ -145,6 +161,8 @@ void CDataInputDlg::accept()
m_dataInput->valueString = m_text;
}
#endif
+ m_dataInput->metaData = m_metadata;
+ m_dataInput->metaDataKey = m_metadataKey;
QDialog::accept();
}
@@ -181,6 +199,22 @@ void CDataInputDlg::onTextChanged(const QString &text)
m_text = text;
}
+void CDataInputDlg::onMetadataChanged(const QString &metadata)
+{
+ int cursorPos = m_ui->lineEditMetadata->cursorPosition();
+ m_metadata = metadata;
+ m_ui->lineEditMetadata->setText(metadata);
+ m_ui->lineEditMetadata->setCursorPosition(cursorPos);
+}
+
+void CDataInputDlg::onMetadataKeyChanged(const QString &metadataKey)
+{
+ int cursorPos = m_ui->lineEditMetadataKey->cursorPosition();
+ m_metadataKey = metadataKey;
+ m_ui->lineEditMetadataKey->setText(metadataKey);
+ m_ui->lineEditMetadataKey->setCursorPosition(cursorPos);
+}
+
QString CDataInputDlg::getUniqueId(const QString &id)
{
QString retval = QStringLiteral("%1").arg(id);
diff --git a/src/Authoring/Studio/Application/DataInputDlg.h b/src/Authoring/Studio/Application/DataInputDlg.h
index b560c7cc..49593cd4 100644
--- a/src/Authoring/Studio/Application/DataInputDlg.h
+++ b/src/Authoring/Studio/Application/DataInputDlg.h
@@ -99,6 +99,8 @@ private Q_SLOTS:
void onMaxChanged(float max);
void onNameChanged(const QString &name);
void onTextChanged(const QString &text);
+ void onMetadataChanged(const QString &metadata);
+ void onMetadataKeyChanged(const QString &metadataKey);
private:
Ui::DataInputDlg *m_ui;
@@ -109,6 +111,8 @@ private:
float m_min;
int m_type;
QString m_text;
+ QString m_metadataKey;
+ QString m_metadata;
QVector<EDataType> m_acceptedTypes;
};
diff --git a/src/Authoring/Studio/Application/DataInputDlg.ui b/src/Authoring/Studio/Application/DataInputDlg.ui
index b27218c4..982e2d4f 100644
--- a/src/Authoring/Studio/Application/DataInputDlg.ui
+++ b/src/Authoring/Studio/Application/DataInputDlg.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>533</width>
- <height>244</height>
+ <height>300</height>
</rect>
</property>
<property name="windowTitle">
@@ -133,6 +133,32 @@
</spacer>
</item>
<item>
+ <widget class="QLabel" name="labelMetadataKey">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>24</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Metadata Key</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelMetadata">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>24</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Metadata</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QLabel" name="labelEvaluation">
<property name="minimumSize">
<size>
@@ -261,6 +287,20 @@
</spacer>
</item>
<item>
+ <widget class="QLineEdit" name="lineEditMetadataKey">
+ <property name="toolTip">
+ <string>Key for accessing the metadata for this Data Input</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineEditMetadata">
+ <property name="toolTip">
+ <string>Metadata associated with this Data Input</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QLineEdit" name="lineEditEvaluation">
<property name="toolTip">
<string/>
diff --git a/src/Authoring/Studio/Application/DataInputListDlg.cpp b/src/Authoring/Studio/Application/DataInputListDlg.cpp
index 4ba31ca9..dbf8d5e5 100644
--- a/src/Authoring/Studio/Application/DataInputListDlg.cpp
+++ b/src/Authoring/Studio/Application/DataInputListDlg.cpp
@@ -141,7 +141,7 @@ void CDataInputListDlg::initDialog()
m_ui->elementInfo->setFocusPolicy(Qt::NoFocus);
m_ui->elementInfo->resizeColumnsToContents();
m_ui->elementInfo->horizontalHeader()->setStretchLastSection(true);
- m_ui->elementInfo->horizontalHeader()->setMinimumSectionSize(125);
+ m_ui->elementInfo->horizontalHeader()->setMinimumSectionSize(140);
m_ui->elementInfo->setModel(m_infoContents);
m_ui->elementInfo->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
@@ -190,7 +190,7 @@ void CDataInputListDlg::updateContents()
for (auto &it : qAsConst(m_dataInputs)) {
dataInput.clear();
- int dataInputType = it->type;
+ EDataType dataInputType = (EDataType)it->type;
if ((dataInputType == m_typeFilter || m_typeFilter == -1)
&& it->name.contains(m_searchString)){
@@ -235,6 +235,26 @@ void CDataInputListDlg::updateContents()
// highlight datainputs that are in use
if (it->ctrldElems.size() || it->externalPresBoundTypes.size())
dataInput.first()->setForeground(QBrush(CStudioPreferences::dataInputColor()));
+
+ // warn if any datainputs have mismatching datatype with an icon after datatype
+ // indicator
+ static QString warning(tr("Data Input type is not matching with one "
+ "or several bound properties"));
+ for (const auto &ctrlElem : qAsConst(it->ctrldElems)) {
+ if (!CDataInputDlg::getAcceptedTypes(ctrlElem.dataType.first)
+ .contains(dataInputType)) {
+ dataInput[1]->setIcon(QIcon(":/images/warning.png"));
+ dataInput[1]->setToolTip(warning);
+ }
+ }
+
+ for (const auto &extBoundType : qAsConst(it->externalPresBoundTypes)) {
+ if (!CDataInputDlg::getAcceptedTypes(extBoundType.first).contains(dataInputType)) {
+ dataInput[1]->setIcon(QIcon(":/images/warning.png"));
+ dataInput[1]->setToolTip(warning);
+ }
+ }
+
m_tableContents->appendRow(dataInput);
}
}
@@ -260,6 +280,7 @@ void CDataInputListDlg::updateInfo()
if (m_ui->tableView->selectionModel()->selectedRows(0).size() == 1) {
for (auto allCtrldElemsIt = m_dataInputs[m_currentDataInputName]->ctrldElems.begin();
allCtrldElemsIt != m_dataInputs[m_currentDataInputName]->ctrldElems.end();) {
+ bool typeNotMatching = false;
QStandardItem *item = new QStandardItem(
g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()
->GetClientDataModelBridge()->GetName(
@@ -297,6 +318,13 @@ void CDataInputListDlg::updateInfo()
}
count++;
+
+ // Check if there is a non-matching datatype binding with one or several
+ // properties for this element.
+ if (!CDataInputDlg::getAcceptedTypes(allCtrldElemsIt->dataType.first).contains(
+ (EDataType)(m_dataInputs[m_currentDataInputName]->type))) {
+ typeNotMatching = true;
+ }
// Advance main iterator so that after the inner loop we end up
// at the start of next instance's batch of controlleditems.
allCtrldElemsIt++;
@@ -310,6 +338,15 @@ void CDataInputListDlg::updateInfo()
QStandardItem *item3 = new QStandardItem(propNames);
item3->setToolTip(propNames);
item3->setEditable(false);
+
+ // Highlight the entire property name item if a non-match was found.
+ if (typeNotMatching) {
+ item3->setForeground(
+ QBrush(CStudioPreferences::invalidDataInputIndicatorColor()));
+ static QString warning(tr("\n\nData Input type is not matching with one or "
+ "several bound properties"));
+ item3->setToolTip(propNames + warning);
+ }
m_infoContents->appendRow(QList<QStandardItem *>({item, item2, item3}));
}
}
diff --git a/src/Authoring/Studio/Application/DurationEditDlg.cpp b/src/Authoring/Studio/Application/DurationEditDlg.cpp
index 0d7c4899..f0707a56 100644
--- a/src/Authoring/Studio/Application/DurationEditDlg.cpp
+++ b/src/Authoring/Studio/Application/DurationEditDlg.cpp
@@ -29,33 +29,15 @@
#include "ui_DurationEditDlg.h"
#include "DurationEditDlg.h"
-#include "IDoc.h"
-#include "Bindings/ITimelineKeyframesManager.h"
-
+#include "TimeEnums.h"
#include <QtGui/qvalidator.h>
-//=============================================================================
-/**
- * Constructor
- */
-CDurationEditDlg::CDurationEditDlg(QWidget *pParent)
- : QDialog(pParent)
+CDurationEditDlg::CDurationEditDlg(QWidget *parent)
+ : QDialog(parent)
, m_ui(new Ui::DurationEditDlg)
- , m_Doc(nullptr)
- , m_KeyframesManager(nullptr)
- , m_Callback(nullptr)
- , m_MaxTime(0)
- , m_MaxTimeDisplay(0)
- , m_MinTimeDisplay(0)
- , m_InitialTimeStart(0)
- , m_InitialTimeEnd(0)
- , m_minStart(-1)
- , m_secStart(-1)
- , m_minEnd(-1)
- , m_secEnd(-1)
{
m_ui->setupUi(this);
- setAutoFillBackground(true);
+ setWindowFlag(Qt::WindowContextHelpButtonHint, false); // remove '?' from the dialog title bar
QIntValidator *minValidator = new QIntValidator(this);
minValidator->setRange(0, 9999);
@@ -83,8 +65,6 @@ CDurationEditDlg::CDurationEditDlg(QWidget *pParent)
this, &CDurationEditDlg::onEndTimeChanged);
connect(m_ui->lineEditEndMilliseconds, &QLineEdit::textEdited,
this, &CDurationEditDlg::onEndTimeChanged);
-
- window()->setFixedSize(size());
}
CDurationEditDlg::~CDurationEditDlg()
@@ -92,72 +72,50 @@ CDurationEditDlg::~CDurationEditDlg()
delete m_ui;
}
-void CDurationEditDlg::setKeyframesManager(ITimelineKeyframesManager *inKeyframesManager)
-{
- m_KeyframesManager = inKeyframesManager;
-}
-
-//=============================================================================
/**
- * showDialog: Initializes and shows the Duration Edit Dialog Box.
+ * Initializes and shows the Duration Edit Dialog Box.
* @param startTime is the initial start time, which will be shown when the time edit
* dialog box pops up
* @param endTime is the initial end time, which will be shown when the time edit
* dialog box pops up
- * @param inDoc this can be nullptr where its not applicable
* @param inCallback is the target object for the callbacks
*/
-void CDurationEditDlg::showDialog(long startTime, long endTime, IDoc *inDoc,
- ITimeChangeCallback *inCallback)
+void CDurationEditDlg::showDialog(long startTime, long endTime, ITimeChangeCallback *inCallback)
{
- m_InitialTimeStart = startTime;
- m_InitialTimeEnd = endTime;
- m_Doc = inDoc;
m_Callback = inCallback;
- m_MinTimeDisplay = 0;
- // if it is a Timebar, this will be adjusted, else this should be initialized to some value at
- // least, for OverflowHandling to work correctly
- m_MaxTimeDisplay = LONG_MAX;
-
- // 9999:59:999 converted to milliseconds
- m_MaxTime = timeConversion(9999, CONVERT_MIN_TO_MSEC)
- + timeConversion(59, CONVERT_SEC_TO_MSEC) + 999;
-
// Set initial values to dialog
- formatTime(m_InitialTimeStart, true);
- formatTime(m_InitialTimeEnd, false);
+ formatTime(startTime, true);
+ formatTime(endTime, false);
- // Present the dialog
exec();
}
void CDurationEditDlg::formatTime(long inTime, bool startTime)
{
- long theTime = inTime;
- long min = 0;
- long sec = 0;
- long msec = 0;
+ long mins = 0;
+ long secs = 0;
+ long mils = 0;
- // Translates the m_initialTime (in milliseconds) into Minutes, Seconds and Milliseconds
if (inTime != 0) {
- min = timeConversion(theTime, CONVERT_MSEC_TO_MIN);
- theTime = theTime - timeConversion(min, CONVERT_MIN_TO_MSEC);
- sec = timeConversion(theTime, CONVERT_MSEC_TO_SEC);
- theTime = theTime - timeConversion(sec, CONVERT_SEC_TO_MSEC);
- msec = theTime;
+ mins = inTime % 3600000 / 60000;
+ secs = inTime % 60000 / 1000;
+ mils = inTime % 1000;
}
+ // display milliseconds in 3 digits (5 -> 005)
+ QString milsStr = QString("%1").arg(mils, 3, 10, QChar('0'));
+
if (startTime) {
- m_ui->lineEditMinutes->setText(QString::number(min));
- m_ui->lineEditSeconds->setText(QString::number(sec));
- m_ui->lineEditMilliseconds->setText(QString::number(msec));
+ m_ui->lineEditMinutes->setText(QString::number(mins));
+ m_ui->lineEditSeconds->setText(QString::number(secs));
+ m_ui->lineEditMilliseconds->setText(milsStr);
// Select the biggest non-zero unit
- if (min > 0) {
+ if (mins > 0) {
m_ui->lineEditMinutes->setFocus();
m_ui->lineEditMinutes->selectAll();
- } else if (sec > 0) {
+ } else if (secs > 0) {
m_ui->lineEditSeconds->setFocus();
m_ui->lineEditSeconds->selectAll();
} else {
@@ -165,17 +123,12 @@ void CDurationEditDlg::formatTime(long inTime, bool startTime)
m_ui->lineEditMilliseconds->selectAll();
}
} else {
- m_ui->lineEditEndMinutes->setText(QString::number(min));
- m_ui->lineEditEndSeconds->setText(QString::number(sec));
- m_ui->lineEditEndMilliseconds->setText(QString::number(msec));
+ m_ui->lineEditEndMinutes->setText(QString::number(mins));
+ m_ui->lineEditEndSeconds->setText(QString::number(secs));
+ m_ui->lineEditEndMilliseconds->setText(milsStr);
}
}
-void CDurationEditDlg::showEvent(QShowEvent *ev)
-{
- QDialog::showEvent(ev);
-}
-
void CDurationEditDlg::accept()
{
m_Callback->Commit();
@@ -188,94 +141,6 @@ void CDurationEditDlg::reject()
QDialog::reject();
}
-long CDurationEditDlg::numberOfDigits(long number)
-{
- long theNumberOfDigits = 0;
- for (long theNumber = number; theNumber >= 1; theNumber = theNumber / 10)
- theNumberOfDigits++;
- return theNumberOfDigits;
-}
-
-//==============================================================================
-/**
- * timeConversion: Converts inTime to the format specified by inFlags.
- * For example:
- * inTime = 5 sec inFlags = CONVERT_SEC_TO_MSEC
- * The method will convert 5 sec into 5000 msec and
- * returns the result.
- * @param inTime stores the time to be converted.
- * inOperationCode determines the type of time conversion to be done on the
- * inTime.
- * @return theResult stores the result of the time conversion.
- */
-long CDurationEditDlg::timeConversion(long inTime, long inOperationCode)
-{
- long theResult = 0;
- switch (inOperationCode) {
- case CONVERT_MIN_TO_MSEC:
- theResult = inTime * 60 * 1000;
- break;
- case CONVERT_SEC_TO_MSEC:
- theResult = inTime * 1000;
- break;
- case CONVERT_MSEC_TO_MIN:
- theResult = inTime / (60 * 1000);
- break;
- case CONVERT_MSEC_TO_SEC:
- theResult = inTime / 1000;
- break;
- }
- return theResult;
-}
-
-//==============================================================================
-/**
- * timeConversion: Takes in the time in mins:secs:msec and convert it to
- * the corresponding time in msec.
- * @param inMin stores the minutes to be converted.
- * inSec stores the seconds to be converted.
- * inMsec stores the milliseconds to be converted.
- * inOperationCode determines the type of time conversion to be done on the
- * inMin, inSec and inMsec.
- * @return theResult stores the result of the time conversion.
- */
-long CDurationEditDlg::timeConversion(long inMin, long inSec, long inMsec, long inOperationCode)
-{
- long theResult = 0;
- switch (inOperationCode) {
- case CONVERT_TIME_TO_MSEC:
- theResult = timeConversion(inMin, CONVERT_MIN_TO_MSEC)
- + timeConversion(inSec, CONVERT_SEC_TO_MSEC) + inMsec;
- break;
- }
- return theResult;
-}
-
-//==============================================================================
-/**
- * timeConversion: Takes in the time in milliseconds and converts them
- * to min : sec : msec.
- * @param inTotalTime stores the total time in msec.
- * ioMin stores the mins result of the time conversion
- * ioSec stores the secs result of the time conversion
- * ioMsec stores the msecs result of the time conversion
- * inOperationCode determines the type of time conversion to be done on the
- * inTotalTime.
- */
-void CDurationEditDlg::timeConversion(long inTotalTime, long *ioMin, long *ioSec, long *ioMsec,
- long inOperationCode)
-{
- switch (inOperationCode) {
- case CONVERT_MSEC_TO_MIN_SEC_MSEC:
- *ioMin = timeConversion(inTotalTime, CONVERT_MSEC_TO_MIN);
- *ioSec = inTotalTime - timeConversion(*ioMin, CONVERT_MIN_TO_MSEC);
- *ioSec = timeConversion(*ioSec, CONVERT_MSEC_TO_SEC);
- *ioMsec = inTotalTime - timeConversion(*ioMin, CONVERT_MIN_TO_MSEC)
- - timeConversion(*ioSec, CONVERT_SEC_TO_MSEC);
- break;
- }
-}
-
void CDurationEditDlg::updateObjectTime(long inTime, bool startTime)
{
if (m_Callback) {
@@ -288,59 +153,42 @@ void CDurationEditDlg::updateObjectTime(long inTime, bool startTime)
void CDurationEditDlg::onStartTimeChanged()
{
- // Making sure that the start time is not greater than the end time, when
- // the user modifies the start time of the timebar
- m_MaxTimeDisplay = m_InitialTimeEnd; // the initial end time
- m_MinTimeDisplay = 0;
-
long min = m_ui->lineEditMinutes->text().toInt();
long sec = m_ui->lineEditSeconds->text().toInt();
long msec = m_ui->lineEditMilliseconds->text().toInt();
- long theGoToTime = timeConversion(min, CONVERT_MIN_TO_MSEC)
- + timeConversion(sec, CONVERT_SEC_TO_MSEC) + msec;
+ long theGoToTime = min * 60000 + sec * 1000 + msec;
// Go to the time specified in the start time edit display
updateObjectTime(theGoToTime, true);
// If max number of digits reached in a number field, select the next
- if (m_minStart != min && numberOfDigits(min) == 4) {
+ if (m_ui->lineEditMinutes->hasFocus() && min > 999) {
m_ui->lineEditSeconds->setFocus();
m_ui->lineEditSeconds->selectAll();
- } else if (m_secStart != sec && numberOfDigits(sec) == 2) {
+ } else if (m_ui->lineEditSeconds->hasFocus() && sec > 9) {
m_ui->lineEditMilliseconds->setFocus();
m_ui->lineEditMilliseconds->selectAll();
}
-
- m_minStart = min;
- m_secStart = sec;
}
void CDurationEditDlg::onEndTimeChanged()
{
- // Let the end time of the time bar go as far as possible
- m_MaxTimeDisplay = m_MaxTime;
- m_MinTimeDisplay = m_InitialTimeStart; // the initial start time
-
long min = m_ui->lineEditEndMinutes->text().toInt();
long sec = m_ui->lineEditEndSeconds->text().toInt();
long msec = m_ui->lineEditEndMilliseconds->text().toInt();
- long theGoToTime = timeConversion(min, CONVERT_MIN_TO_MSEC)
- + timeConversion(sec, CONVERT_SEC_TO_MSEC) + msec;
+ long theGoToTime = min * 60000 + sec * 1000 + msec;
// Go to the time specified in the end time edit display
updateObjectTime(theGoToTime, false);
// If max number of digits reached in a number field, select the next
- if (m_minEnd != min && numberOfDigits(min) == 4) {
+ if (m_ui->lineEditEndMinutes->hasFocus() && min > 999) {
m_ui->lineEditEndSeconds->setFocus();
m_ui->lineEditEndSeconds->selectAll();
- } else if (m_secEnd != sec && numberOfDigits(sec) == 2) {
+ } else if (m_ui->lineEditEndSeconds->hasFocus() && sec > 9) {
m_ui->lineEditEndMilliseconds->setFocus();
m_ui->lineEditEndMilliseconds->selectAll();
}
-
- m_minEnd = min;
- m_secEnd = sec;
}
diff --git a/src/Authoring/Studio/Application/DurationEditDlg.h b/src/Authoring/Studio/Application/DurationEditDlg.h
index 7630b02a..ddb42ec0 100644
--- a/src/Authoring/Studio/Application/DurationEditDlg.h
+++ b/src/Authoring/Studio/Application/DurationEditDlg.h
@@ -30,12 +30,9 @@
#ifndef DURATION_EDIT_DIALOG_H
#define DURATION_EDIT_DIALOG_H
-#include "TimeEnums.h"
#include <QtWidgets/qdialog.h>
-class CTimebarControl;
class IDoc;
-class ITimelineKeyframesManager;
class ITimeChangeCallback
{
@@ -62,43 +59,23 @@ class CDurationEditDlg : public QDialog
Q_OBJECT
public:
- CDurationEditDlg(QWidget *pParent = nullptr); // standard constructor
- virtual ~CDurationEditDlg();
- void setKeyframesManager(ITimelineKeyframesManager *inKeyframeManager);
- void showDialog(long startTime, long endTime, IDoc *inDoc,
- ITimeChangeCallback *inCallback = nullptr);
+ CDurationEditDlg(QWidget *parent = nullptr);
+ ~CDurationEditDlg() override;
+
+ void showDialog(long startTime, long endTime, ITimeChangeCallback *inCallback = nullptr);
public Q_SLOTS:
void accept() override;
void reject() override;
-protected:
- void showEvent(QShowEvent *) override;
-
+private:
void onStartTimeChanged();
void onEndTimeChanged();
void formatTime(long inTime, bool startTime);
- long numberOfDigits(long number);
- long timeConversion(long inTime, long inOperationCode);
- long timeConversion(long inMin, long inSec, long inMsec, long inOperationCode);
- void timeConversion(long inTotalTime, long *ioMin, long *ioSec, long *ioMsec,
- long inOperationCode);
void updateObjectTime(long inTime, bool startTime);
-protected:
Ui::DurationEditDlg *m_ui;
- IDoc *m_Doc;
- ITimelineKeyframesManager *m_KeyframesManager;
- ITimeChangeCallback *m_Callback;
- long m_MaxTime;
- long m_MaxTimeDisplay;
- long m_MinTimeDisplay;
- long m_InitialTimeStart;
- long m_InitialTimeEnd;
- int m_minStart;
- int m_secStart;
- int m_minEnd;
- int m_secEnd;
+ ITimeChangeCallback *m_Callback = nullptr;
};
#endif // DURATION_EDIT_DIALOG_H
diff --git a/src/Authoring/Studio/Application/DurationEditDlg.ui b/src/Authoring/Studio/Application/DurationEditDlg.ui
index 062a5051..4f6bb7de 100644
--- a/src/Authoring/Studio/Application/DurationEditDlg.ui
+++ b/src/Authoring/Studio/Application/DurationEditDlg.ui
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
- <width>300</width>
+ <width>343</width>
<height>152</height>
</rect>
</property>
@@ -14,6 +14,9 @@
<string>Set Timebar Start / End Time</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetFixedSize</enum>
+ </property>
<property name="leftMargin">
<number>0</number>
</property>
@@ -70,7 +73,14 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditMinutes"/>
+ <widget class="QLineEdit" name="lineEditMinutes">
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
<item>
<widget class="QLabel" name="label_2">
@@ -80,7 +90,14 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditSeconds"/>
+ <widget class="QLineEdit" name="lineEditSeconds">
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
<item>
<widget class="QLabel" name="label_3">
@@ -90,7 +107,14 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditMilliseconds"/>
+ <widget class="QLineEdit" name="lineEditMilliseconds">
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
</layout>
</widget>
@@ -124,7 +148,14 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditEndMinutes"/>
+ <widget class="QLineEdit" name="lineEditEndMinutes">
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
<item>
<widget class="QLabel" name="label_7">
@@ -134,7 +165,14 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditEndSeconds"/>
+ <widget class="QLineEdit" name="lineEditEndSeconds">
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
<item>
<widget class="QLabel" name="label_8">
@@ -144,7 +182,14 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditEndMilliseconds"/>
+ <widget class="QLineEdit" name="lineEditEndMilliseconds">
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
</layout>
</widget>
diff --git a/src/Authoring/Studio/Application/ProjectFile.cpp b/src/Authoring/Studio/Application/ProjectFile.cpp
index a2792049..a4b5b9c0 100644
--- a/src/Authoring/Studio/Application/ProjectFile.cpp
+++ b/src/Authoring/Studio/Application/ProjectFile.cpp
@@ -43,6 +43,8 @@
#include <QtCore/qdiriterator.h>
#include <QtCore/qsavefile.h>
#include <QtCore/qtimer.h>
+#include <QtCore/qrandom.h>
+#include <QtWidgets/qmessagebox.h>
ProjectFile::ProjectFile()
{
@@ -493,6 +495,8 @@ void ProjectFile::parseDataInputElem(const QDomElement &elem,
item->valueString = elem.attribute(QStringLiteral("evaluator"));
}
#endif
+ item->metaDataKey = elem.attribute((QStringLiteral("metadatakey")));
+ item->metaData = elem.attribute((QStringLiteral("metadata")));
dataInputs.insert(item->name, item);
}
}
@@ -926,3 +930,676 @@ ProjectFile::getDiBindingtypesFromSubpresentations() const
return map;
}
+
+/**
+ * Load variants data to m_variantsDef
+ *
+ * @param filePath the file path to load the variants from. If empty, variants are loaded from the
+ * project file and replace m_variantsDef. If a filePath is specified, the loaded
+ * variants are merged with m_variantsDef
+ */
+void ProjectFile::loadVariants(const QString &filePath)
+{
+ if (!m_fileInfo.exists())
+ return;
+
+ bool isProj = filePath.isEmpty() || filePath == getProjectFilePath();
+ QFile file(isProj ? getProjectFilePath() : filePath);
+ if (!file.open(QFile::Text | QFile::ReadOnly)) {
+ qWarning() << file.errorString();
+ return;
+ }
+
+ if (isProj)
+ m_variantsDef.clear();
+
+ QXmlStreamReader reader(&file);
+ reader.setNamespaceProcessing(false);
+
+ VariantGroup *currentGroup = nullptr;
+ while (!reader.atEnd()) {
+ if (reader.readNextStartElement()) {
+ if (reader.name() == QLatin1String("variantgroup")) {
+ QString groupId = reader.attributes().value(QLatin1String("id")).toString();
+ QString groupColor = reader.attributes().value(QLatin1String("color")).toString();
+ currentGroup = &m_variantsDef[groupId];
+ currentGroup->m_color = groupColor;
+ } else if (reader.name() == QLatin1String("variant")) {
+ if (currentGroup) {
+ QString tagId = reader.attributes().value(QLatin1String("id")).toString();
+ if (!currentGroup->m_tags.contains(tagId))
+ currentGroup->m_tags.append(tagId);
+ } else {
+ qWarning() << "Error parsing variant tags.";
+ }
+ } else if (currentGroup) {
+ break;
+ }
+ }
+ }
+
+ if (!isProj) {
+ // if loading variants from a file, update the uia
+ QDomDocument domDoc;
+ QSaveFile fileProj(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(fileProj, domDoc))
+ return;
+
+ QDomElement vElem = domDoc.documentElement().firstChildElement(QStringLiteral("variants"));
+ if (!vElem.isNull())
+ domDoc.documentElement().removeChild(vElem);
+
+ vElem = domDoc.createElement(QStringLiteral("variants"));
+ domDoc.documentElement().appendChild(vElem);
+
+ const auto keys = m_variantsDef.keys();
+ for (auto &g : keys) {
+ QDomElement gElem = domDoc.createElement(QStringLiteral("variantgroup"));
+ gElem.setAttribute(QStringLiteral("id"), g);
+ gElem.setAttribute(QStringLiteral("color"), m_variantsDef[g].m_color);
+ vElem.appendChild(gElem);
+
+ for (auto &t : qAsConst(m_variantsDef[g].m_tags)) {
+ QDomElement tElem = domDoc.createElement(QStringLiteral("variant"));
+ tElem.setAttribute(QStringLiteral("id"), t);
+ gElem.appendChild(tElem);
+ }
+ }
+
+ StudioUtils::commitDomDocumentSave(fileProj, domDoc);
+ }
+}
+
+// Add a new tag to a variants group
+void ProjectFile::addVariantTag(const QString &group, const QString &newTag)
+{
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ QDomElement newTagElem = domDoc.createElement(QStringLiteral("variant"));
+ newTagElem.setAttribute(QStringLiteral("id"), newTag);
+
+ QDomNodeList groupsElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"))
+ .elementsByTagName(QStringLiteral("variantgroup"));
+
+ // update and save the uia
+ for (int i = 0; i < groupsElems.count(); ++i) {
+ QDomElement gElem = groupsElems.at(i).toElement();
+ if (gElem.attribute(QStringLiteral("id")) == group) {
+ gElem.appendChild(newTagElem);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+ break;
+ }
+ }
+
+ // update m_variantsDef
+ m_variantsDef[group].m_tags.append(newTag);
+}
+
+// Add a new group, it is assumes that the new group name is unique
+void ProjectFile::addVariantGroup(const QString &newGroup)
+{
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ QDomElement variantsElem = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"));
+
+ if (variantsElem.isNull()) {
+ QDomElement newVariantsElem = domDoc.createElement(QStringLiteral("variants"));
+ domDoc.documentElement().appendChild(newVariantsElem);
+ variantsElem = newVariantsElem;
+ }
+
+ // generate random semi-bright color
+ int r = 0x555555 + QRandomGenerator::global()->generate() % 0x555555; // 0x555555 = 0xffffff / 3
+ QString newColor = QLatin1Char('#') + QString::number(r, 16);
+
+ QDomElement newGroupElem = domDoc.createElement(QStringLiteral("variantgroup"));
+ newGroupElem.setAttribute(QStringLiteral("id"), newGroup);
+ newGroupElem.setAttribute(QStringLiteral("color"), newColor);
+ variantsElem.appendChild(newGroupElem);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+
+ // update m_variantsDef
+ VariantGroup g;
+ g.m_color = newColor;
+ m_variantsDef[newGroup] = g;
+}
+
+void ProjectFile::renameVariantTag(const QString &group, const QString &oldTag,
+ const QString &newTag)
+{
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ // rename the tag in all uip files
+ QDomNodeList presElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("assets"))
+ .elementsByTagName(QStringLiteral("presentation"));
+ for (int i = 0; i < presElems.count(); ++i) {
+ QString pPath = m_fileInfo.path() + QLatin1Char('/')
+ + presElems.at(i).toElement().attribute(QStringLiteral("src"));
+ renameTagInUip(pPath, group, oldTag, newTag);
+ }
+
+ // update and save the uia
+ QDomNodeList groupsElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"))
+ .elementsByTagName(QStringLiteral("variantgroup"));
+
+ bool renamed = false;
+ for (int i = 0; i < groupsElems.count(); ++i) {
+ QDomElement gElem = groupsElems.at(i).toElement();
+ if (gElem.attribute(QStringLiteral("id")) == group) {
+ QDomNodeList tagsElems = gElem.childNodes();
+ for (int j = 0; j < tagsElems.count(); ++j) {
+ QDomElement tElem = tagsElems.at(j).toElement();
+ if (tElem.attribute(QStringLiteral("id")) == oldTag) {
+ tElem.setAttribute(QStringLiteral("id"), newTag);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+ renamed = true;
+ break;
+ }
+ }
+ if (renamed)
+ break;
+ }
+ }
+
+ // update the property
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+ const auto layers = doc->getLayers();
+ auto property = bridge->GetLayer().m_variants;
+ for (auto layer : layers) {
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(layer, property, sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ QString oldGroupTagPair = QStringLiteral("%1:%2").arg(group).arg(oldTag);
+ if (propVal.contains(oldGroupTagPair)) {
+ propVal.replace(oldGroupTagPair, QStringLiteral("%1:%2").arg(group).arg(newTag));
+ qt3dsdm::SValue sVal
+ = std::make_shared<qt3dsdm::CDataStr>(Q3DStudio::CString::fromQString(propVal));
+ propertySystem->SetInstancePropertyValue(layer, property, sVal);
+ }
+ }
+ }
+
+ // update m_variantsDef
+ for (auto &t : m_variantsDef[group].m_tags) {
+ if (t == oldTag) {
+ t = newTag;
+ renamed = true;
+ break;
+ }
+ }
+}
+
+// rename a variant group, newGroup is assumed to be unique
+void ProjectFile::renameVariantGroup(const QString &oldGroup, const QString &newGroup)
+{
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ // rename the group in all uip files
+ QDomNodeList presElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("assets"))
+ .elementsByTagName(QStringLiteral("presentation"));
+ for (int i = 0; i < presElems.count(); ++i) {
+ QString pPath = m_fileInfo.path() + QLatin1Char('/')
+ + presElems.at(i).toElement().attribute(QStringLiteral("src"));
+ renameGroupInUip(pPath, oldGroup, newGroup);
+ }
+
+ // update and save the uia
+ QDomNodeList groupsElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"))
+ .elementsByTagName(QStringLiteral("variantgroup"));
+
+ for (int i = 0; i < groupsElems.count(); ++i) {
+ QDomElement gElem = groupsElems.at(i).toElement();
+ if (gElem.attribute(QStringLiteral("id")) == oldGroup) {
+ gElem.setAttribute(QStringLiteral("id"), newGroup);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+ break;
+ }
+ }
+
+ // update the property
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+ const auto layers = doc->getLayers();
+ auto property = bridge->GetLayer().m_variants;
+ for (auto layer : layers) {
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(layer, property, sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ QString oldGroupWithColon = QStringLiteral("%1:").arg(oldGroup);
+ if (propVal.contains(oldGroupWithColon)) {
+ propVal.replace(oldGroupWithColon, QStringLiteral("%1:").arg(newGroup));
+ qt3dsdm::SValue sVal = std::make_shared<qt3dsdm::CDataStr>(
+ Q3DStudio::CString::fromQString(propVal));
+ propertySystem->SetInstancePropertyValue(layer, property, sVal);
+ }
+ }
+ }
+
+ // update m_variantsDef
+ m_variantsDef[newGroup] = m_variantsDef[oldGroup];
+ m_variantsDef.remove(oldGroup);
+}
+
+void ProjectFile::deleteVariantGroup(const QString &group)
+{
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ // check if group is in use in other presentations in the porject
+ int inUseIdx = -1; // index of first presentation that has the group in-use
+ QDomNodeList presElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("assets"))
+ .elementsByTagName(QStringLiteral("presentation"));
+ for (int i = 0; i < presElems.count(); ++i) {
+ QString pPath = m_fileInfo.path() + QLatin1Char('/')
+ + presElems.at(i).toElement().attribute(QStringLiteral("src"));
+ if (pPath != doc->GetDocumentPath() && groupExistsInUip(pPath, group)) {
+ inUseIdx = i;
+ break;
+ }
+ }
+
+ if (inUseIdx != -1) {
+ QMessageBox box;
+ box.setWindowTitle(tr("Group tags in use"));
+ box.setText(tr("Some tags in the Group '%1' are in use in the project, are you sure you"
+ " want to delete the group?").arg(group));
+ box.setIcon(QMessageBox::Warning);
+ box.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
+ box.setButtonText(QMessageBox::Yes, QStringLiteral("Delete"));
+ switch (box.exec()) {
+ case QMessageBox::Yes:
+ // delete the group from all uips that use it
+ for (int i = inUseIdx; i < presElems.count(); ++i) {
+ QString pPath = m_fileInfo.path() + QLatin1Char('/')
+ + presElems.at(i).toElement().attribute(QStringLiteral("src"));
+ if (pPath != doc->GetDocumentPath())
+ deleteGroupFromUip(pPath, group);
+ }
+ break;
+
+ default:
+ // abort deletion
+ return;
+ }
+ }
+
+ // delete the group from current uip, if exists
+ deleteGroupFromUip(doc->GetDocumentPath(), group);
+
+ // delete the group from the property (if set)
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+ const auto layers = doc->getLayers();
+ auto property = bridge->GetLayer().m_variants;
+ for (auto layer : layers) {
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(layer, property, sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ if (propVal.contains(QStringLiteral("%1:").arg(group))) {
+ // property has the deleted group, need to update it, else the deleted group
+ // will be saved the uip if the user saves the presentation.
+ QRegExp rgx(QStringLiteral("%1:\\w*,*|,%1:\\w*").arg(group));
+ propVal.replace(rgx, {});
+ qt3dsdm::SValue sVal = std::make_shared<qt3dsdm::CDataStr>(
+ Q3DStudio::CString::fromQString(propVal));
+ propertySystem->SetInstancePropertyValue(layer, property, sVal);
+ }
+ }
+ }
+
+ // update and save the uia
+ QDomElement variantsElem = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"));
+ QDomNodeList groupsElems = variantsElem.elementsByTagName(QStringLiteral("variantgroup"));
+
+ bool deleted = false;
+ for (int i = 0; i < groupsElems.count(); ++i) {
+ QDomElement gElem = groupsElems.at(i).toElement();
+ if (gElem.attribute(QStringLiteral("id")) == group) {
+ variantsElem.removeChild(gElem);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+ deleted = true;
+ break;
+ }
+ }
+
+ // update m_variantsDef
+ m_variantsDef.remove(group);
+}
+
+void ProjectFile::changeVariantGroupColor(const QString &group, const QString &newColor)
+{
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ // update and save the uia
+ QDomNodeList groupsElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"))
+ .elementsByTagName(QStringLiteral("variantgroup"));
+
+ for (int i = 0; i < groupsElems.count(); ++i) {
+ QDomElement gElem = groupsElems.at(i).toElement();
+ if (gElem.attribute(QStringLiteral("id")) == group) {
+ gElem.setAttribute(QStringLiteral("color"), newColor);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+ break;
+ }
+ }
+
+ // update m_variantsDef
+ m_variantsDef[group].m_color = newColor;
+}
+
+bool ProjectFile::tagExistsInUip(const QString &src, const QString &group, const QString &tag) const
+{
+ QFile file(src);
+ if (!file.open(QFile::Text | QFile::ReadOnly)) {
+ qWarning() << file.errorString();
+ return false;
+ }
+
+ QXmlStreamReader reader(&file);
+ reader.setNamespaceProcessing(false);
+
+ while (!reader.atEnd()) {
+ if (reader.readNextStartElement()) {
+ if (reader.name() == QLatin1String("Layer")
+ && reader.attributes().hasAttribute(QLatin1String("variants"))) {
+ QStringRef v = reader.attributes().value(QLatin1String("variants"));
+ if (v.contains(group + QLatin1Char(':') + tag))
+ return true;
+ } else if (reader.name() == QLatin1String("Logic")) {
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ProjectFile::groupExistsInUip(const QString &src, const QString &group) const
+{
+ QFile file(src);
+ if (!file.open(QFile::Text | QFile::ReadOnly)) {
+ qWarning() << file.errorString();
+ return false;
+ }
+
+ QXmlStreamReader reader(&file);
+ reader.setNamespaceProcessing(false);
+
+ while (!reader.atEnd()) {
+ if (reader.readNextStartElement()) {
+ if (reader.name() == QLatin1String("Layer")
+ && reader.attributes().hasAttribute(QLatin1String("variants"))) {
+ QStringRef v = reader.attributes().value(QLatin1String("variants"));
+ if (v.contains(group + QLatin1Char(':')))
+ return true;
+ } else if (reader.name() == QLatin1String("Logic")) {
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+// renames a tag (if exists) in all layers in a uip file
+void ProjectFile::renameTagInUip(const QString &src, const QString &group, const QString &tag,
+ const QString &newName)
+{
+ QDomDocument domDoc;
+ QSaveFile file(src);
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ QDomNodeList layerElems = domDoc.documentElement()
+ .elementsByTagName(QStringLiteral("Layer"));
+ bool needSave = false;
+ for (int i = 0; i < layerElems.count(); ++i) {
+ QDomElement lElem = layerElems.at(i).toElement();
+ if (lElem.hasAttribute(QStringLiteral("variants"))) {
+ QStringList tagPairs = lElem.attribute(QStringLiteral("variants"))
+ .split(QLatin1Char(','));
+ QString tagFrom = group + QLatin1Char(':') + tag;
+ QString tagTo = group + QLatin1Char(':') + newName;
+
+ if (tagPairs.contains(tagFrom)) {
+ tagPairs.replaceInStrings(tagFrom, tagTo);
+ lElem.setAttribute(QStringLiteral("variants"), tagPairs.join(QLatin1Char(',')));
+ needSave = true;
+ }
+ }
+ }
+
+ if (needSave)
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+}
+
+void ProjectFile::renameGroupInUip(const QString &src, const QString &group, const QString &newName)
+{
+ QDomDocument domDoc;
+ QSaveFile file(src);
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ QDomNodeList layerElems = domDoc.documentElement()
+ .elementsByTagName(QStringLiteral("Layer"));
+ bool needSave = false;
+ for (int i = 0; i < layerElems.count(); ++i) {
+ QDomElement lElem = layerElems.at(i).toElement();
+ if (lElem.hasAttribute(QStringLiteral("variants"))) {
+ QString variants = lElem.attribute(QStringLiteral("variants"));
+ if (variants.contains(group + QLatin1Char(':'))) {
+ variants.replace(group + QLatin1Char(':'), newName + QLatin1Char(':'));
+ lElem.setAttribute(QStringLiteral("variants"), variants);
+ needSave = true;
+ }
+ }
+ }
+
+ if (needSave)
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+}
+
+// deletes a tag (if exists) from all layers in a uip file
+void ProjectFile::deleteTagFromUip(const QString &src, const QString &group, const QString &tag)
+{
+ QDomDocument domDoc;
+ QSaveFile file(src);
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ QDomNodeList layerElems = domDoc.documentElement()
+ .elementsByTagName(QStringLiteral("Layer"));
+ bool needSave = false;
+ for (int i = 0; i < layerElems.count(); ++i) {
+ QDomElement lElem = layerElems.at(i).toElement();
+ if (lElem.hasAttribute(QStringLiteral("variants"))) {
+ QStringList tagPairs = lElem.attribute(QStringLiteral("variants"))
+ .split(QLatin1Char(','));
+ QString tagPair = group + QLatin1Char(':') + tag;
+ if (tagPairs.contains(tagPair)) {
+ tagPairs.removeOne(tagPair);
+ lElem.setAttribute(QStringLiteral("variants"), tagPairs.join(QLatin1Char(',')));
+ needSave = true;
+ }
+ }
+ }
+
+ if (needSave)
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+}
+
+// deletes a group (if exists) from all layers in a uip file
+void ProjectFile::deleteGroupFromUip(const QString &src, const QString &group)
+{
+ QDomDocument domDoc;
+ QSaveFile file(src);
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ QDomNodeList layerElems = domDoc.documentElement()
+ .elementsByTagName(QStringLiteral("Layer"));
+ bool needSave = false;
+ QRegExp rgx(group + ":\\w*,*|," + group + ":\\w*");
+ for (int i = 0; i < layerElems.count(); ++i) {
+ QDomElement lElem = layerElems.at(i).toElement();
+ if (lElem.hasAttribute(QStringLiteral("variants"))) {
+ QString val = lElem.attribute(QStringLiteral("variants"));
+ if (rgx.indexIn(val) != -1) {
+ val.replace(rgx, "");
+ lElem.setAttribute(QStringLiteral("variants"), val);
+ needSave = true;
+ }
+ }
+ }
+
+ if (needSave)
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+}
+
+bool ProjectFile::isVariantGroupUnique(const QString &group) const
+{
+ return !m_variantsDef.contains(group);
+}
+
+bool ProjectFile::isVariantTagUnique(const QString &group, const QString &tag) const
+{
+ if (!m_variantsDef.contains(group))
+ return true;
+
+ return !m_variantsDef[group].m_tags.contains(tag);
+}
+
+void ProjectFile::deleteVariantTag(const QString &group, const QString &tag)
+{
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ // check if tag is in use in other presentations in the porject
+ int inUseIdx = -1; // list of presentations that has the tag in use
+ QDomNodeList presElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("assets"))
+ .elementsByTagName(QStringLiteral("presentation"));
+ for (int i = 0; i < presElems.count(); ++i) {
+ QString pPath = m_fileInfo.path() + QLatin1Char('/')
+ + presElems.at(i).toElement().attribute(QStringLiteral("src"));
+ if (pPath != doc->GetDocumentPath()
+ && tagExistsInUip(pPath, group, tag)) {
+ inUseIdx = i;
+ break;
+ }
+ }
+
+ if (inUseIdx != -1) {
+ QMessageBox box;
+ box.setWindowTitle(tr("Tag in use"));
+ box.setText(tr("The tag '%1' is in use in another presentation, are you sure you want to"
+ " delete it?").arg(tag));
+ box.setIcon(QMessageBox::Warning);
+ box.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
+ box.setButtonText(QMessageBox::Yes, QStringLiteral("Delete"));
+ switch (box.exec()) {
+ case QMessageBox::Yes:
+ // delete the tag from all uips that use it
+ for (int i = inUseIdx; i < presElems.count(); ++i) {
+ QString pPath = m_fileInfo.path() + QLatin1Char('/')
+ + presElems.at(i).toElement().attribute(QStringLiteral("src"));
+ if (pPath != doc->GetDocumentPath())
+ deleteTagFromUip(pPath, group, tag);
+ }
+ break;
+
+ default:
+ // abort deletion
+ return;
+ }
+ }
+
+ // delete the tag from current doc, if exists
+ deleteTagFromUip(doc->GetDocumentPath(), group, tag);
+
+ QDomNodeList groupsElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"))
+ .elementsByTagName(QStringLiteral("variantgroup"));
+
+ // delete the tag from the property (if set)
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+ const auto layers = doc->getLayers();
+ auto property = bridge->GetLayer().m_variants;
+ for (auto layer : layers) {
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(layer, property, sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ if (propVal.contains(QStringLiteral("%1:%2").arg(group).arg(tag))) {
+ // property has the deleted tag, need to update it, else the deleted tag will be
+ // saved in the uip if the user saves the presentation.
+ QRegExp rgx(QStringLiteral("%1:%2,*|,%1:%2").arg(group).arg(tag));
+ propVal.replace(rgx, {});
+ qt3dsdm::SValue sVal = std::make_shared<qt3dsdm::CDataStr>(
+ Q3DStudio::CString::fromQString(propVal));
+ propertySystem->SetInstancePropertyValue(layer, property, sVal);
+ }
+ }
+ }
+
+ // update and save the uia
+ bool deleted = false;
+ for (int i = 0; i < groupsElems.count(); ++i) {
+ QDomElement gElem = groupsElems.at(i).toElement();
+ if (gElem.attribute(QStringLiteral("id")) == group) {
+ QDomNodeList tagsElems = gElem.childNodes();
+ for (int j = 0; j < tagsElems.count(); ++j) {
+ QDomElement tElem = tagsElems.at(j).toElement();
+ if (tElem.attribute(QStringLiteral("id")) == tag) {
+ gElem.removeChild(tElem);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+ deleted = true;
+ break;
+ }
+ }
+ if (deleted)
+ break;
+ }
+ }
+
+ // update m_variantsDef
+ m_variantsDef[group].m_tags.removeOne(tag);
+}
diff --git a/src/Authoring/Studio/Application/ProjectFile.h b/src/Authoring/Studio/Application/ProjectFile.h
index 3e47da28..78ecc6d6 100644
--- a/src/Authoring/Studio/Application/ProjectFile.h
+++ b/src/Authoring/Studio/Application/ProjectFile.h
@@ -46,6 +46,11 @@ class ProjectFile : public QObject
public:
ProjectFile();
+ struct VariantGroup {
+ QString m_color;
+ QStringList m_tags;
+ };
+
void create(const QString &uiaPath);
void ensureProjectFile();
void initProjectFile(const QString &presPath);
@@ -81,6 +86,18 @@ public:
void deletePresentationFile(const QString &filePath);
void renameMaterial(const QString &oldName, const QString &newName);
bool duplicatePresentation(const QString &oldPres, const QString &newPres);
+ void loadVariants(const QString &filePath = {});
+ void addVariantTag(const QString &group, const QString &newTag);
+ void renameVariantTag(const QString &group, const QString &oldTag, const QString &newTag);
+ void deleteVariantTag(const QString &group, const QString &tag);
+ void addVariantGroup(const QString &newGroup);
+ void renameVariantGroup(const QString &oldGroup, const QString &newGroup);
+ void deleteVariantGroup(const QString &group);
+ void changeVariantGroupColor(const QString &group, const QString &newColor);
+ bool isVariantGroupUnique(const QString &group) const;
+ bool isVariantTagUnique(const QString &group, const QString &tag) const;
+
+ QHash<QString, VariantGroup> variantsDef() const { return m_variantsDef; }
Q_SIGNALS:
void presentationIdChanged(const QString &path, const QString &id);
@@ -88,9 +105,17 @@ Q_SIGNALS:
private:
QString ensureUniquePresentationId(const QString &id) const;
+ bool tagExistsInUip(const QString &src, const QString &group, const QString &tag) const;
+ bool groupExistsInUip(const QString &src, const QString &group) const;
+ void deleteTagFromUip(const QString &src, const QString &group, const QString &tag);
+ void deleteGroupFromUip(const QString &src, const QString &group);
+ void renameTagInUip(const QString &src, const QString &group, const QString &tag,
+ const QString &newName);
+ void renameGroupInUip(const QString &src, const QString &group, const QString &newName);
QFileInfo m_fileInfo; // uia file info
QString m_initialPresentation;
+ QHash<QString, VariantGroup> m_variantsDef; // definition of variants
};
#endif // PROJECTFILE_H
diff --git a/src/Authoring/Studio/Application/StudioApp.cpp b/src/Authoring/Studio/Application/StudioApp.cpp
index d6e589a4..c0fa435e 100644
--- a/src/Authoring/Studio/Application/StudioApp.cpp
+++ b/src/Authoring/Studio/Application/StudioApp.cpp
@@ -84,11 +84,15 @@ int main(int argc, char *argv[])
bool isOpenGLES = false;
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#if !defined(Q_OS_MACOS)
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
#endif
SharedTools::QtSingleApplication guiApp(QStringLiteral("Qt3DStudio"), argc, argv);
+ // Fix for uia and uip file attribute random ordering (see QTBUG-8158)
+ qSetGlobalQHashSeed(1720419);
+
#if defined(Q_OS_MACOS)
QSurfaceFormat openGL33Format;
openGL33Format.setRenderableType(QSurfaceFormat::OpenGL);
@@ -1726,6 +1730,8 @@ bool CStudioApp::OnLoadDocument(const QString &inDocument, bool inShowStartupDia
m_core->getProjectFile().updateDocPresentationId();
m_core->getProjectFile().loadSubpresentationsAndDatainputs(m_subpresentations,
m_dataInputDialogItems);
+ m_core->getProjectFile().loadVariants();
+ GetViews()->getMainFrame()->getSlideView()->refreshVariants();
getRenderer().RegisterSubpresentations(m_subpresentations);
m_authorZoom = false;
@@ -1786,6 +1792,13 @@ void CStudioApp::saveDataInputsToProjectFile()
diNode.setAttribute(QStringLiteral("evaluator"), item->valueString);
}
#endif
+ // Let's allow storing key even if actual metadata is empty, as we
+ // do not know how the user code is going to interpret metadata contents.
+ if (!item->metaDataKey.isEmpty()) {
+ diNode.setAttribute(QStringLiteral("metadatakey"), item->metaDataKey);
+ if (!item->metaData.isEmpty())
+ diNode.setAttribute(QStringLiteral("metadata"), item->metaData);
+ }
assetsNode.appendChild(diNode);
}
StudioUtils::commitDomDocumentSave(file, doc);
diff --git a/src/Authoring/Studio/Application/TimeEditDlg.cpp b/src/Authoring/Studio/Application/TimeEditDlg.cpp
index 499d6d57..eb9d0324 100644
--- a/src/Authoring/Studio/Application/TimeEditDlg.cpp
+++ b/src/Authoring/Studio/Application/TimeEditDlg.cpp
@@ -29,24 +29,17 @@
#include "ui_TimeEditDlg.h"
#include "TimeEditDlg.h"
+#include "KeyframeManager.h"
#include "IDoc.h"
-#include "Bindings/ITimelineKeyframesManager.h"
-
+#include "TimeEnums.h"
#include <QtGui/qvalidator.h>
-CTimeEditDlg::CTimeEditDlg(QWidget *pParent)
- : QDialog(pParent)
- , m_ui(new Ui::TimeEditDlg)
- , m_Doc(nullptr)
- , m_KeyframesManager(nullptr)
- , m_InitialTime(0)
- , m_ObjectAssociation(0)
- , m_OffsetFromInitialTime(0)
- , m_min(-1)
- , m_sec(-1)
+CTimeEditDlg::CTimeEditDlg(KeyframeManager *keyframeManager)
+ : m_ui(new Ui::TimeEditDlg)
+ , m_keyframeManager(keyframeManager)
{
m_ui->setupUi(this);
- setAutoFillBackground(true);
+ setWindowFlag(Qt::WindowContextHelpButtonHint, false); // remove '?' from the dialog title bar
QIntValidator *minValidator = new QIntValidator(this);
minValidator->setRange(0, 9999);
@@ -61,8 +54,6 @@ CTimeEditDlg::CTimeEditDlg(QWidget *pParent)
connect(m_ui->lineEditMinutes, &QLineEdit::textEdited, this, &CTimeEditDlg::onTimeChanged);
connect(m_ui->lineEditSeconds, &QLineEdit::textEdited, this, &CTimeEditDlg::onTimeChanged);
connect(m_ui->lineEditMilliseconds, &QLineEdit::textEdited, this, &CTimeEditDlg::onTimeChanged);
-
- window()->setFixedSize(size());
}
CTimeEditDlg::~CTimeEditDlg()
@@ -70,57 +61,48 @@ CTimeEditDlg::~CTimeEditDlg()
delete m_ui;
}
-void CTimeEditDlg::setKeyframesManager(ITimelineKeyframesManager *inKeyframesManager)
-{
- m_KeyframesManager = inKeyframesManager;
-}
-
-//=============================================================================
/**
- * showDialog: Initializes and shows the Time Edit Dialog Box.
- * @param inTime is the initial time, which will be shown when the time edit
- * dialog box pops up
+ * Initializes and shows the dialog
+ * @param inTime the initial time which will be shown when the dialog pops up
* @param inDoc this can be nullptr where its not applicable
- * @param inObjectAssociation is the identifier for that identifies the object
- * associated with the time edit dialog
- * (e.g. playhead, keyframe)
+ * @param inObjectAssociation the identifier for the object associated with the dialog (playhead
+ * or keyframe)
*/
void CTimeEditDlg::showDialog(long inTime, IDoc *inDoc, long inObjectAssociation)
{
- m_InitialTime = inTime;
- m_ObjectAssociation = inObjectAssociation;
+ m_initialTime = inTime;
+ m_objectAssociation = inObjectAssociation;
m_Doc = inDoc;
// Set initial values to dialog
- formatTime(m_InitialTime);
+ formatTime(m_initialTime);
exec();
}
void CTimeEditDlg::formatTime(long inTime)
{
- long theTime = inTime;
- long min = 0;
- long sec = 0;
- long msec = 0;
+ long mins = 0;
+ long secs = 0;
+ long mils = 0;
- // Translates the m_initialTime (in milliseconds) into Minutes, Seconds and Milliseconds
if (inTime != 0) {
- min = timeConversion(theTime, CONVERT_MSEC_TO_MIN);
- theTime = theTime - timeConversion(min, CONVERT_MIN_TO_MSEC);
- sec = timeConversion(theTime, CONVERT_MSEC_TO_SEC);
- theTime = theTime - timeConversion(sec, CONVERT_SEC_TO_MSEC);
- msec = theTime;
+ mins = inTime % 3600000 / 60000;
+ secs = inTime % 60000 / 1000;
+ mils = inTime % 1000;
}
- m_ui->lineEditMinutes->setText(QString::number(min));
- m_ui->lineEditSeconds->setText(QString::number(sec));
- m_ui->lineEditMilliseconds->setText(QString::number(msec));
+
+ // display milliseconds in 3 digits (5 -> 005)
+ QString milsStr = QString("%1").arg(mils, 3, 10, QChar('0'));
+ m_ui->lineEditMinutes->setText(QString::number(mins));
+ m_ui->lineEditSeconds->setText(QString::number(secs));
+ m_ui->lineEditMilliseconds->setText(milsStr);
// Select the biggest non-zero unit
- if (min > 0) {
+ if (mins > 0) {
m_ui->lineEditMinutes->setFocus();
m_ui->lineEditMinutes->selectAll();
- } else if (sec > 0) {
+ } else if (secs > 0) {
m_ui->lineEditSeconds->setFocus();
m_ui->lineEditSeconds->selectAll();
} else {
@@ -129,22 +111,23 @@ void CTimeEditDlg::formatTime(long inTime)
}
}
-void CTimeEditDlg::showEvent(QShowEvent *ev)
+void CTimeEditDlg::showEvent(QShowEvent *e)
{
onInitDialog();
- QDialog::showEvent(ev);
+ QDialog::showEvent(e);
}
void CTimeEditDlg::onInitDialog()
{
QString title;
// Display the window captions for the correct object type
- switch (m_ObjectAssociation) {
+ switch (m_objectAssociation) {
case PLAYHEAD:
title = QObject::tr("Go To Time");
break;
case ASSETKEYFRAME:
title = QObject::tr("Set Keyframe Time");
+ Q_ASSERT(m_keyframeManager != nullptr);
break;
}
setWindowTitle(title);
@@ -154,11 +137,11 @@ void CTimeEditDlg::onInitDialog()
void CTimeEditDlg::accept()
{
// Only commit here, cos dup keyframes will be deleted.
- if (m_ObjectAssociation == ASSETKEYFRAME && m_Doc && m_KeyframesManager) {
- if (m_OffsetFromInitialTime == 0)
- m_KeyframesManager->RollbackChangedKeyframes();
+ if (m_objectAssociation == ASSETKEYFRAME && m_Doc) {
+ if (m_endTime == m_initialTime)
+ m_keyframeManager->RollbackChangedKeyframes();
else
- m_KeyframesManager->CommitChangedKeyframes();
+ m_keyframeManager->CommitChangedKeyframes();
}
QDialog::accept();
@@ -167,119 +150,26 @@ void CTimeEditDlg::accept()
void CTimeEditDlg::reject()
{
// Only commit here, cos dup keyframes will be deleted.
- if (m_ObjectAssociation == ASSETKEYFRAME && m_Doc && m_KeyframesManager)
- m_KeyframesManager->RollbackChangedKeyframes();
+ if (m_objectAssociation == ASSETKEYFRAME && m_Doc)
+ m_keyframeManager->RollbackChangedKeyframes();
QDialog::reject();
}
-int CTimeEditDlg::numberOfDigits(long number)
-{
- long theNumberOfDigits = 0;
- for (long theNumber = number; theNumber >= 1; theNumber = theNumber / 10)
- theNumberOfDigits++;
- return theNumberOfDigits;
-}
-
-//==============================================================================
/**
- * timeConversion: Converts inTime to the format specified by inFlags.
- * For example:
- * inTime = 5 sec inFlags = CONVERT_SEC_TO_MSEC
- * The method will convert 5 sec into 5000 msec and
- * returns the result.
- * @param inTime stores the time to be converted.
- * inOperationCode determines the type of time conversion to be done on the
- * inTime.
- * @return theResult stores the result of the time conversion.
- */
-long CTimeEditDlg::timeConversion(long inTime, long inOperationCode)
-{
- long theResult = 0;
- switch (inOperationCode) {
- case CONVERT_MIN_TO_MSEC:
- theResult = inTime * 60 * 1000;
- break;
- case CONVERT_SEC_TO_MSEC:
- theResult = inTime * 1000;
- break;
- case CONVERT_MSEC_TO_MIN:
- theResult = inTime / (60 * 1000);
- break;
- case CONVERT_MSEC_TO_SEC:
- theResult = inTime / 1000;
- break;
- }
- return theResult;
-}
-
-//==============================================================================
-/**
- * timeConversion: Takes in the time in mins:secs:msec and convert it to
- * the corresponding time in msec.
- * @param inMin stores the minutes to be converted.
- * inSec stores the seconds to be converted.
- * inMsec stores the milliseconds to be converted.
- * inOperationCode determines the type of time conversion to be done on the
- * inMin, inSec and inMsec.
- * @return theResult stores the result of the time conversion.
- */
-long CTimeEditDlg::timeConversion(long inMin, long inSec, long inMsec, long inOperationCode)
-{
- long theResult = 0;
- switch (inOperationCode) {
- case CONVERT_TIME_TO_MSEC:
- theResult = timeConversion(inMin, CONVERT_MIN_TO_MSEC)
- + timeConversion(inSec, CONVERT_SEC_TO_MSEC) + inMsec;
- break;
- }
- return theResult;
-}
-
-//==============================================================================
-/**
- * timeConversion: Takes in the time in milliseconds and converts them
- * to min : sec : msec.
- * @param inTotalTime stores the total time in msec.
- * ioMin stores the mins result of the time conversion
- * ioSec stores the secs result of the time conversion
- * ioMsec stores the msecs result of the time conversion
- * inOperationCode determines the type of time conversion to be done on the
- * inTotalTime.
- */
-void CTimeEditDlg::timeConversion(long inTotalTime, long *ioMin, long *ioSec, long *ioMsec,
- long inOperationCode)
-{
- switch (inOperationCode) {
- case CONVERT_MSEC_TO_MIN_SEC_MSEC:
- *ioMin = timeConversion(inTotalTime, CONVERT_MSEC_TO_MIN);
- *ioSec = inTotalTime - timeConversion(*ioMin, CONVERT_MIN_TO_MSEC);
- *ioSec = timeConversion(*ioSec, CONVERT_MSEC_TO_SEC);
- *ioMsec = inTotalTime - timeConversion(*ioMin, CONVERT_MIN_TO_MSEC)
- - timeConversion(*ioSec, CONVERT_SEC_TO_MSEC);
- break;
- }
-}
-
-//==============================================================================
-/**
- * updateObjectTime: It updates the playhead or keyframe time according
- * to the time displayed in the time edit dialogue.
- * @param inTime is the time that will be updated.
+ * Updates the playhead or keyframe time according to the time displayed in the time edit dialogue.
+ * @param inTime the time that will be updated.
*/
void CTimeEditDlg::updateObjectTime(long inTime)
{
- long theDiff = 0;
- switch (m_ObjectAssociation) {
+ switch (m_objectAssociation) {
case PLAYHEAD: // Update the playhead time
if (m_Doc)
m_Doc->NotifyTimeChanged(inTime);
break;
case ASSETKEYFRAME: // Update the keyframe time
if (m_Doc) {
- theDiff = inTime - m_OffsetFromInitialTime - m_InitialTime;
- m_OffsetFromInitialTime = m_OffsetFromInitialTime + theDiff;
- if (theDiff != 0 && m_KeyframesManager)
- m_KeyframesManager->OffsetSelectedKeyframes(theDiff);
+ m_endTime = inTime;
+ m_keyframeManager->moveSelectedKeyframes(inTime);
}
break;
}
@@ -291,21 +181,23 @@ void CTimeEditDlg::onTimeChanged()
long sec = m_ui->lineEditSeconds->text().toInt();
long msec = m_ui->lineEditMilliseconds->text().toInt();
- long theGoToTime = timeConversion(min, CONVERT_MIN_TO_MSEC)
- + timeConversion(sec, CONVERT_SEC_TO_MSEC) + msec;
+ long theGoToTime = min * 60000 + sec * 1000 + msec;
+ // make sure min keyframe time doesn't go below zero
+ long offset = m_keyframeManager->getPressedKeyframeOffset();
+ if (theGoToTime - offset < 0) {
+ theGoToTime = offset;
+ formatTime(theGoToTime);
+ }
// Go to the time specified in the time edit display
updateObjectTime(theGoToTime);
// If max number of digits reached in a number field, select the next
- if (m_min != min && numberOfDigits(min) == 4) {
+ if (m_ui->lineEditMinutes->hasFocus() && min > 999) {
m_ui->lineEditSeconds->setFocus();
m_ui->lineEditSeconds->selectAll();
- } else if (m_sec != sec && numberOfDigits(sec) == 2) {
+ } else if (m_ui->lineEditSeconds->hasFocus() && sec > 9) {
m_ui->lineEditMilliseconds->setFocus();
m_ui->lineEditMilliseconds->selectAll();
}
-
- m_min = min;
- m_sec = sec;
}
diff --git a/src/Authoring/Studio/Application/TimeEditDlg.h b/src/Authoring/Studio/Application/TimeEditDlg.h
index 8d8ed08f..ef4f8d1a 100644
--- a/src/Authoring/Studio/Application/TimeEditDlg.h
+++ b/src/Authoring/Studio/Application/TimeEditDlg.h
@@ -30,12 +30,11 @@
#ifndef TIME_EDIT_DIALOG_H
#define TIME_EDIT_DIALOG_H
-#include "TimeEnums.h"
#include <QtWidgets/qdialog.h>
class CTimebarControl;
class IDoc;
-class ITimelineKeyframesManager;
+class KeyframeManager;
#ifdef QT_NAMESPACE
using namespace QT_NAMESPACE;
@@ -52,9 +51,8 @@ class CTimeEditDlg : public QDialog
Q_OBJECT
public:
- CTimeEditDlg(QWidget *pParent = nullptr); // standard constructor
- virtual ~CTimeEditDlg();
- void setKeyframesManager(ITimelineKeyframesManager *inKeyframeManager);
+ CTimeEditDlg(KeyframeManager *keyframeManager);
+ virtual ~CTimeEditDlg() override;
void showDialog(long inTime, IDoc *inDoc, long inObjectAssociation);
public Q_SLOTS:
@@ -64,25 +62,18 @@ public Q_SLOTS:
protected:
void showEvent(QShowEvent *) override;
+private:
void onInitDialog();
void onTimeChanged();
void formatTime(long inTime);
- int numberOfDigits(long number);
- long timeConversion(long inTime, long inOperationCode);
- long timeConversion(long inMin, long inSec, long inMsec, long inOperationCode);
- void timeConversion(long inTotalTime, long *ioMin, long *ioSec, long *ioMsec,
- long inOperationCode);
void updateObjectTime(long inTime);
-protected:
- Ui::TimeEditDlg *m_ui;
- IDoc *m_Doc;
- ITimelineKeyframesManager *m_KeyframesManager;
- long m_InitialTime;
- long m_ObjectAssociation;
- long m_OffsetFromInitialTime;
- int m_min;
- int m_sec;
+ Ui::TimeEditDlg *m_ui = nullptr;
+ IDoc *m_Doc = nullptr;
+ KeyframeManager *m_keyframeManager = nullptr;
+ long m_initialTime = 0;
+ long m_endTime = 0;
+ long m_objectAssociation = 0;
};
#endif // TIME_EDIT_DIALOG_H
diff --git a/src/Authoring/Studio/Application/TimeEditDlg.ui b/src/Authoring/Studio/Application/TimeEditDlg.ui
index 6bcb11b3..54a8dbd7 100644
--- a/src/Authoring/Studio/Application/TimeEditDlg.ui
+++ b/src/Authoring/Studio/Application/TimeEditDlg.ui
@@ -6,14 +6,29 @@
<rect>
<x>0</x>
<y>0</y>
- <width>300</width>
- <height>114</height>
+ <width>343</width>
+ <height>119</height>
</rect>
</property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>535</width>
+ <height>119</height>
+ </size>
+ </property>
<property name="windowTitle">
<string>Set Keyframe Time</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetFixedSize</enum>
+ </property>
<property name="leftMargin">
<number>0</number>
</property>
@@ -70,7 +85,20 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditMinutes"/>
+ <widget class="QLineEdit" name="lineEditMinutes">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
<item>
<widget class="QLabel" name="label_2">
@@ -80,7 +108,20 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditSeconds"/>
+ <widget class="QLineEdit" name="lineEditSeconds">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
<item>
<widget class="QLabel" name="label_3">
@@ -90,7 +131,20 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditMilliseconds"/>
+ <widget class="QLineEdit" name="lineEditMilliseconds">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
</layout>
</widget>
@@ -152,7 +206,7 @@
<widget class="QLabel" name="label_4">
<property name="minimumSize">
<size>
- <width>40</width>
+ <width>0</width>
<height>0</height>
</size>
</property>
@@ -174,7 +228,7 @@
<widget class="QLabel" name="label">
<property name="minimumSize">
<size>
- <width>40</width>
+ <width>0</width>
<height>0</height>
</size>
</property>
diff --git a/src/Authoring/Studio/Info.plist b/src/Authoring/Studio/Info.plist
index 6d81aee3..22709e99 100644
--- a/src/Authoring/Studio/Info.plist
+++ b/src/Authoring/Studio/Info.plist
@@ -54,7 +54,7 @@
</dict>
</array>
<key>NSHumanReadableCopyright</key>
- <string>(C) 2018 The Qt Company Ltd</string>
+ <string>(C) 2019 The Qt Company Ltd</string>
<key>CFBundleExecutable</key>
<string>Qt3DStudio</string>
<key>CFBundleIconFile</key>
@@ -62,7 +62,9 @@
<key>CFBundleIdentifier</key>
<string>org.qt-project.qt3dstudio</string>
<key>CFBundleVersion</key>
- <string>2.0</string>
+ <string>2.3.0</string>
+ <key>CFBundleShortVersionString</key>
+ <string>2.3</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
diff --git a/src/Authoring/Studio/MainFrm.cpp b/src/Authoring/Studio/MainFrm.cpp
index 2fc6ad91..9bf14265 100644
--- a/src/Authoring/Studio/MainFrm.cpp
+++ b/src/Authoring/Studio/MainFrm.cpp
@@ -59,6 +59,7 @@
#include "ProjectView.h"
#include "RowTree.h"
#include "WidgetControl.h"
+#include "SlideView.h"
#include <QtGui/qevent.h>
#include <QtGui/qdesktopservices.h>
@@ -1901,6 +1902,12 @@ TimelineWidget *CMainFrame::getTimelineWidget() const
return static_cast<TimelineWidget *>(control->getControl());
}
+SlideView *CMainFrame::getSlideView() const
+{
+ return static_cast<SlideView *>(m_paletteManager->GetControl(CPaletteManager::CONTROLTYPE_SLIDE)
+ ->widget());
+}
+
CRecentItems *CMainFrame::GetRecentItems()
{
return m_recentItems.data();
diff --git a/src/Authoring/Studio/MainFrm.h b/src/Authoring/Studio/MainFrm.h
index 275ea8c2..d81e9b12 100644
--- a/src/Authoring/Studio/MainFrm.h
+++ b/src/Authoring/Studio/MainFrm.h
@@ -56,6 +56,7 @@ class ITimelineTimebar;
class RemoteDeploymentSender;
class TimelineWidget;
class CStudioPreferencesPropSheet;
+class SlideView;
#ifdef QT_NAMESPACE
using namespace QT_NAMESPACE;
@@ -234,6 +235,7 @@ public:
void onCtrlNPressed();
TimelineWidget *getTimelineWidget() const;
+ SlideView *getSlideView() const;
void EditPreferences(short inPageIndex);
diff --git a/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp b/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp
index 84e31178..3a1a008b 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp
@@ -231,6 +231,24 @@ void ChooserModelBase::expand(const QModelIndex &modelIndex)
void ChooserModelBase::setRootPath(const QString &path)
{
+ // Delete the old model. If the new project is in a totally different directory tree, not
+ // doing this will result in unexplicable crashes when trying to parse something that should
+ // not be parsed.
+ disconnect(m_model, &QAbstractItemModel::rowsInserted,
+ this, &ChooserModelBase::modelRowsInserted);
+ disconnect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &ChooserModelBase::modelRowsRemoved);
+ disconnect(m_model, &QAbstractItemModel::layoutChanged,
+ this, &ChooserModelBase::modelLayoutChanged);
+ delete m_model;
+ m_model = new QFileSystemModel(this);
+ connect(m_model, &QAbstractItemModel::rowsInserted,
+ this, &ChooserModelBase::modelRowsInserted);
+ connect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &ChooserModelBase::modelRowsRemoved);
+ connect(m_model, &QAbstractItemModel::layoutChanged,
+ this, &ChooserModelBase::modelLayoutChanged);
+
setRootIndex(m_model->setRootPath(path));
}
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp
index 48cdfe1c..1e94d85a 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp
@@ -62,6 +62,7 @@
#include "foundation/Qt3DSLogging.h"
#include "Dialogs.h"
#include "Dispatch.h"
+#include "VariantsGroupModel.h"
static QStringList renderableItems()
{
@@ -108,8 +109,9 @@ static std::pair<bool, bool> getSlideCharacteristics(qt3dsdm::Qt3DSDMInstanceHan
return std::make_pair(hasNextSlide, hasPreviousSlide);
}
-InspectorControlModel::InspectorControlModel(QObject *parent)
- : QAbstractListModel(parent)
+InspectorControlModel::InspectorControlModel(VariantsGroupModel *variantsModel, QObject *parent)
+ : m_variantsModel(variantsModel)
+ , QAbstractListModel(parent)
, m_UpdatableEditor(*g_StudioApp.GetCore()->GetDoc())
{
m_modifiedProperty.first = 0;
@@ -129,7 +131,7 @@ void InspectorControlModel::setInspectable(CInspectableBase *inInspectable)
if (m_notifier.get() == nullptr) {
m_notifier = signalProvider->ConnectInstancePropertyValue(
- std::bind(&InspectorControlModel::notifyInstancePropertyValue,
+ std::bind(&InspectorControlModel::onPropertyChanged,
this, std::placeholders::_1, std::placeholders::_2));
}
if (m_slideNotifier.get() == nullptr) {
@@ -172,14 +174,20 @@ CInspectableBase *getReferenceMaterialInspectable(CInspectableBase *inspectBase)
return nullptr;
}
-void InspectorControlModel::notifyInstancePropertyValue(qt3dsdm::Qt3DSDMInstanceHandle inHandle,
- qt3dsdm::Qt3DSDMPropertyHandle inProperty)
+void InspectorControlModel::onPropertyChanged(qt3dsdm::Qt3DSDMInstanceHandle inInstance,
+ qt3dsdm::Qt3DSDMPropertyHandle inProperty)
{
auto doc = g_StudioApp.GetCore()->GetDoc();
- const auto bridge = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()
- ->GetClientDataModelBridge();
- if (!bridge->IsSceneGraphInstance(inHandle))
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+ if (!bridge->IsSceneGraphInstance(inInstance))
return;
+
+ if (inProperty == bridge->GetLayer().m_variants) {
+ // only update the variants model if its property changes
+ m_variantsModel->refresh();
+ return;
+ }
+
bool changed = false;
for (int row = 0; row < m_groupElements.count(); ++row) {
auto group = m_groupElements[row];
@@ -192,7 +200,7 @@ void InspectorControlModel::notifyInstancePropertyValue(qt3dsdm::Qt3DSDMInstance
imageInstance = doc->GetDocumentReader().GetImageInstanceForProperty(
property->m_instance, property->m_property);
}
- if (property->m_property == inProperty || imageInstance == inHandle) {
+ if (property->m_property == inProperty || imageInstance == inInstance) {
updatePropertyValue(property);
changed = true;
}
@@ -621,6 +629,31 @@ QString InspectorControlModel::getDefaultMaterialString() const
return QObject::tr("Default");
}
+bool InspectorControlModel::isGroupCollapsed(int groupIdx) const
+{
+ const auto inspectable = dynamic_cast<Qt3DSDMInspectable *>(m_inspectableBase);
+ if (inspectable && groupIdx > -1 && groupIdx < m_groupElements.size()) {
+ auto instance = inspectable->GetGroupInstance(0);
+
+ if (m_collapseMap.contains(instance))
+ return m_collapseMap[instance].contains(groupIdx);
+ }
+
+ return false;
+}
+
+void InspectorControlModel::updateGroupCollapseState(int groupIdx, bool isCollapsed)
+{
+ const auto inspectable = dynamic_cast<Qt3DSDMInspectable *>(m_inspectableBase);
+ if (inspectable && groupIdx > -1 && groupIdx < m_groupElements.size()) {
+ auto instance = inspectable->GetGroupInstance(0);
+ if (isCollapsed)
+ m_collapseMap[instance][groupIdx] = true;
+ else
+ m_collapseMap[instance].remove(groupIdx);
+ }
+}
+
void InspectorControlModel::updateFontValues(InspectorControlBase *element) const
{
// Find if there are any font items and update the values of those
@@ -968,10 +1001,8 @@ bool InspectorControlModel::isTreeRebuildRequired(CInspectableBase* inspectBase)
long theCount = m_inspectableBase->GetGroupCount();
auto refMaterial = getReferenceMaterial(inspectBase);
- if (refMaterial != m_refMaterial) {
- m_refMaterial = refMaterial;
+ if (refMaterial != m_refMaterial)
return true;
- }
long refMaterialGroupCount = 0;
if (refMaterial.Valid())
refMaterialGroupCount = 1; // Only the last group of the refMaterial is used
@@ -1163,6 +1194,8 @@ void InspectorControlModel::rebuildTree()
// Clean the old objects after reset is done so that qml will not freak out about null pointers
for (int i = 0; i < deleteVector.count(); ++i)
deleteVector[i]->deleteLater();
+
+ m_refMaterial = getReferenceMaterial(m_inspectableBase);
}
int InspectorControlModel::rowCount(const QModelIndex &parent) const
@@ -1198,7 +1231,6 @@ void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) c
metaDataProvider->GetMetaDataProperty(instance, element->m_property));
}
-
bool skipEmits = false;
switch (element->m_dataType) {
case qt3dsdm::DataModelDataType::String: {
@@ -1208,6 +1240,7 @@ void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) c
if (index != -1)
stringValue = stringValue.mid(index + 1);
}
+
element->m_value = stringValue;
} // intentional fall-through for other String-derived datatypes
case qt3dsdm::DataModelDataType::StringOrInt:
@@ -1223,7 +1256,7 @@ void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) c
}
auto slideSystem = studioSystem->GetSlideSystem();
- if (element->m_title == QStringLiteral("Play Mode")) {
+ if (element->m_title == QLatin1String("Play Mode")) {
std::pair<bool, bool> slideData(
getSlideCharacteristics(element->m_instance, *studioSystem->GetSlideCore(),
*slideSystem));
@@ -1231,7 +1264,7 @@ void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) c
bool hasPreviousSlide(slideData.second);
if (!hasNextSlide && !hasPreviousSlide)
stringlist.removeAll("Play Through To...");
- } else if (element->m_title == QStringLiteral("Play Through To")) {
+ } else if (element->m_title == QLatin1String("Play Through To")) {
// the code duplication is intentional as we may ask for slide characteristics
// only if the property refers to slides
std::pair<bool, bool> slideData(
@@ -1274,7 +1307,8 @@ void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) c
}
element->m_value = QString(selectedIndex > 0 ? stringlist[selectedIndex]
- : stringlist.first()).replace("|separator", "");
+ : stringlist.first()).replace(QLatin1String("|separator"),
+ QString());
}
element->m_values = stringlist;
} else if (element->m_propertyType == qt3dsdm::AdditionalMetaDataType::Import) {
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h
index 13413bb4..300247c7 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h
@@ -42,6 +42,7 @@
class CInspectableBase;
class Qt3DSDMInspectable;
class SGuideInspectableImpl;
+class VariantsGroupModel;
namespace qt3dsdm {
class ISignalConnection;
@@ -107,7 +108,7 @@ class InspectorControlModel : public QAbstractListModel
{
Q_OBJECT
public:
- explicit InspectorControlModel(QObject *parent);
+ explicit InspectorControlModel(VariantsGroupModel *variantsModel, QObject *parent);
~InspectorControlModel() = default;
enum Roles {
@@ -153,6 +154,8 @@ public:
Q_INVOKABLE bool isDefaultMaterial() const;
Q_INVOKABLE void addMaterial();
Q_INVOKABLE void duplicateMaterial();
+ Q_INVOKABLE bool isGroupCollapsed(int groupIdx) const;
+ Q_INVOKABLE void updateGroupCollapseState(int groupIdx, bool state);
private:
void onSlideRearranged(const qt3dsdm::Qt3DSDMSlideHandle &inMaster, int inOldIndex,
@@ -168,7 +171,7 @@ private:
}
};
- mutable QVector<GroupInspectorControl> m_groupElements;
+ QVector<GroupInspectorControl> m_groupElements;
CInspectableBase *m_inspectableBase = nullptr;
SGuideInspectableImpl *m_guideInspectable = nullptr;
@@ -197,6 +200,8 @@ private:
qt3dsdm::SValue m_previouslyCommittedValue;
+ QHash<int, QHash<int, bool> > m_collapseMap;
+
QString getBasicMaterialString() const;
QString getAnimatableMaterialString() const;
QString getReferencedMaterialString() const;
@@ -215,7 +220,8 @@ private:
void updatePropertyValue(InspectorControlBase *element) const;
void rebuildTree();
void refreshTree();
- void notifyInstancePropertyValue(qt3dsdm::Qt3DSDMInstanceHandle, qt3dsdm::Qt3DSDMPropertyHandle inProperty);
+ void onPropertyChanged(qt3dsdm::Qt3DSDMInstanceHandle inInstance,
+ qt3dsdm::Qt3DSDMPropertyHandle inProperty);
void updateAnimateToggleState(InspectorControlBase *inItem);
void updateControlledToggleState(InspectorControlBase *inItem) const;
@@ -243,6 +249,8 @@ private:
bool isGroupRebuildRequired(CInspectableBase *inspectable, int theIndex) const;
static int handleToGuidePropIndex(int handle) { return handle - 1; }
+
+ VariantsGroupModel *m_variantsModel = nullptr;
};
#endif // INSPECTORCONTROLMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp
index b6037011..5b2a69d9 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp
@@ -57,6 +57,13 @@
#include "ProjectFile.h"
#include "MaterialRefView.h"
#include "BasicObjectsModel.h"
+#include "Qt3DSDMSlides.h"
+#include "VariantsGroupModel.h"
+#include "VariantTagDialog.h"
+#include "Views.h"
+#include "MainFrm.h"
+#include "SlideView.h"
+#include "TimelineWidget.h"
#include <QtCore/qtimer.h>
#include <QtQml/qqmlcontext.h>
@@ -68,7 +75,8 @@
InspectorControlView::InspectorControlView(const QSize &preferredSize, QWidget *parent)
: QQuickWidget(parent),
TabNavigable(),
- m_inspectorControlModel(new InspectorControlModel(this)),
+ m_variantsGroupModel(new VariantsGroupModel(this)),
+ m_inspectorControlModel(new InspectorControlModel(m_variantsGroupModel, this)),
m_meshChooserView(new MeshChooserView(this)),
m_instance(0),
m_handle(0),
@@ -235,6 +243,7 @@ void InspectorControlView::initialize()
CStudioPreferences::setQmlContextProperties(rootContext());
rootContext()->setContextProperty(QStringLiteral("_parentView"), this);
rootContext()->setContextProperty(QStringLiteral("_inspectorModel"), m_inspectorControlModel);
+ rootContext()->setContextProperty(QStringLiteral("_variantsGroupModel"), m_variantsGroupModel);
rootContext()->setContextProperty(QStringLiteral("_resDir"), StudioUtils::resourceImageUrl());
rootContext()->setContextProperty(QStringLiteral("_tabOrderHandler"), tabOrderHandler());
rootContext()->setContextProperty(QStringLiteral("_mouseHelper"), &m_mouseHelper);
@@ -288,6 +297,8 @@ bool InspectorControlView::canLinkProperty(int instance, int handle) const
&& (type & (OBJTYPE_CUSTOMMATERIAL | OBJTYPE_MATERIAL | OBJTYPE_REFERENCEDMATERIAL))) {
return false;
}
+ if (doc->GetStudioSystem()->GetPropertySystem()->GetName(handle) == QStringLiteral("eyeball"))
+ return false;
return doc->GetDocumentReader().CanPropertyBeLinked(instance, handle);
}
@@ -372,6 +383,17 @@ QString InspectorControlView::titleIcon() const
return {};
}
+bool InspectorControlView::isEditable(int handle) const
+{
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ if (doc->GetStudioSystem()->GetSlideSystem()->IsMasterSlide(doc->GetActiveSlide())
+ && doc->GetStudioSystem()->GetPropertySystem()->GetName(handle)
+ == QStringLiteral("eyeball")) {
+ return false;
+ }
+ return true;
+}
+
void InspectorControlView::OnSelectionSet(Q3DStudio::SSelectedValue inSelectable)
{
updateInspectable(g_StudioApp.GetInspectableFromSelectable(inSelectable));
@@ -394,6 +416,8 @@ void InspectorControlView::setInspectable(CInspectableBase *inInspectable)
m_inspectorControlModel->setInspectable(inInspectable);
Q_EMIT titleChanged();
+
+ m_variantsGroupModel->refresh();
}
}
@@ -434,6 +458,72 @@ void InspectorControlView::showContextMenu(int x, int y, int handle, int instanc
m_handle = 0;
}
+// context menu for the variants tags
+void InspectorControlView::showTagContextMenu(int x, int y, const QString &group,
+ const QString &tag)
+{
+ QMenu theContextMenu;
+
+ auto actionRename = theContextMenu.addAction(QObject::tr("Rename Tag"));
+ connect(actionRename, &QAction::triggered, this, [&]() {
+ VariantTagDialog dlg(VariantTagDialog::RenameTag, group, tag);
+ if (dlg.exec() == QDialog::Accepted) {
+ g_StudioApp.GetCore()->getProjectFile().renameVariantTag(group, dlg.getNames().first,
+ dlg.getNames().second);
+ m_variantsGroupModel->refresh();
+ }
+ });
+
+ auto actionDelete = theContextMenu.addAction(QObject::tr("Delete Tag"));
+ connect(actionDelete, &QAction::triggered, this, [&]() {
+ g_StudioApp.GetCore()->getProjectFile().deleteVariantTag(group, tag);
+ g_StudioApp.GetViews()->getMainFrame()->getTimelineWidget()->refreshVariants();
+ g_StudioApp.GetViews()->getMainFrame()->getSlideView()->refreshVariants();
+ m_variantsGroupModel->refresh();
+ });
+
+ theContextMenu.exec(mapToGlobal({x, y}));
+}
+
+// context menu for the variants groups
+void InspectorControlView::showGroupContextMenu(int x, int y, const QString &group)
+{
+ QMenu theContextMenu;
+
+ ProjectFile &projectFile = g_StudioApp.GetCore()->getProjectFile();
+
+ auto actionRename = theContextMenu.addAction(QObject::tr("Rename Group"));
+ connect(actionRename, &QAction::triggered, this, [&]() {
+ VariantTagDialog dlg(VariantTagDialog::RenameGroup, {}, group);
+ if (dlg.exec() == QDialog::Accepted) {
+ projectFile.renameVariantGroup(dlg.getNames().first, dlg.getNames().second);
+ g_StudioApp.GetViews()->getMainFrame()->getTimelineWidget()->refreshVariants();
+ m_variantsGroupModel->refresh();
+ }
+ });
+
+ auto actionColor = theContextMenu.addAction(QObject::tr("Change Group Color"));
+ connect(actionColor, &QAction::triggered, this, [&]() {
+ const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef();
+ QColor newColor = this->showColorDialog(variantsDef[group].m_color);
+ projectFile.changeVariantGroupColor(group, newColor.name());
+ // no need to refresh variants in the timeline widget as it references the group color in
+ // the project file m_variants, and a redraw is triggered upon color selection dialog close.
+ g_StudioApp.GetViews()->getMainFrame()->getSlideView()->refreshVariants();
+ m_variantsGroupModel->refresh();
+ });
+
+ auto actionDelete = theContextMenu.addAction(QObject::tr("Delete Group"));
+ connect(actionDelete, &QAction::triggered, this, [&]() {
+ projectFile.deleteVariantGroup(group);
+ g_StudioApp.GetViews()->getMainFrame()->getTimelineWidget()->refreshVariants();
+ g_StudioApp.GetViews()->getMainFrame()->getSlideView()->refreshVariants();
+ m_variantsGroupModel->refresh();
+ });
+
+ theContextMenu.exec(mapToGlobal({x, y}));
+}
+
void InspectorControlView::toggleMasterLink()
{
Q3DStudio::ScopedDocumentEditor editor(*g_StudioApp.GetCore()->GetDoc(),
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h
index 6cb7fd21..14936b57 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h
@@ -39,6 +39,7 @@
#include "DataInputSelectView.h"
class InspectorControlModel;
+class VariantsGroupModel;
class CInspectableBase;
class ImageChooserView;
class DataInputSelectView;
@@ -72,6 +73,8 @@ public:
QString titleIcon() const;
Q_INVOKABLE void showContextMenu(int x, int y, int handle, int instance);
+ Q_INVOKABLE void showTagContextMenu(int x, int y, const QString &group, const QString &tag);
+ Q_INVOKABLE void showGroupContextMenu(int x, int y, const QString &group);
Q_INVOKABLE QObject *showImageChooser(int handle, int instance, const QPoint &point);
Q_INVOKABLE QObject *showFilesChooser(int handle, int instance, const QPoint &point);
Q_INVOKABLE QObject *showMeshChooser(int handle, int instance, const QPoint &point);
@@ -84,6 +87,7 @@ public:
Q_INVOKABLE QString convertPathToProjectRoot(const QString &presentationPath);
Q_INVOKABLE bool isRefMaterial(int instance) const;
Q_INVOKABLE QString noneString() const;
+ Q_INVOKABLE bool isEditable(int handle) const;
// IDataModelListener
void OnBeginDataModelNotifications() override;
@@ -125,6 +129,7 @@ private:
std::vector<std::shared_ptr<qt3dsdm::ISignalConnection>> m_connections;
QColor m_backgroundColor;
+ VariantsGroupModel *m_variantsGroupModel = nullptr;
InspectorControlModel *m_inspectorControlModel = nullptr;
CInspectableBase *m_inspectableBase = nullptr;
QPointer<ImageChooserView> m_imageChooserView;
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml
index 3677bc0e..ab0b8db3 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml
@@ -28,6 +28,8 @@
import QtQuick 2.8
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.2
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Extras 1.4
import Qt3DStudio 1.0
import "../controls"
@@ -205,12 +207,45 @@ Rectangle {
width: parent.width - x
spacing: 4
- StyledLabel {
- text: model.title
+ Rectangle { // group header
+ x: -10
+ width: delegateItem.width
+ height: 25
+ color: "#111111"
+
+ StyledLabel {
+ x: 30
+ text: model.title
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Image {
+ id: collapseButton
+ x: 10
+ anchors.verticalCenter: parent.verticalCenter
+ source: {
+ _resDir + (groupItems.visible ? "arrow_down.png" : "arrow.png")
+ }
+ }
+
+ MouseArea {
+ id: collapseButtonMouseArea
+ anchors.fill: parent
+ onClicked: {
+ if (mouse.button === Qt.LeftButton) {
+ groupItems.visible = !groupItems.visible;
+ _inspectorModel.updateGroupCollapseState(indexOfThisDelegate,
+ !groupItems.visible)
+ }
+ }
+ }
}
Column {
spacing: 4
+ id: groupItems
+
+ visible: !_inspectorModel.isGroupCollapsed(indexOfThisDelegate)
Repeater {
model: delegateItem.values
@@ -237,6 +272,7 @@ Rectangle {
RowLayout {
id: groupDelegateItem
spacing: 0
+ enabled: _parentView.isEditable(modelData.handle)
property alias loadedItem: loader.item
@@ -252,6 +288,7 @@ Rectangle {
ColumnLayout { // Property row and datainput control
Layout.alignment: Qt.AlignTop
+ visible: modelData.title !== "variants"
spacing: 0
RowLayout { // Property row
Layout.alignment: Qt.AlignLeft
@@ -281,7 +318,7 @@ Rectangle {
anchors.fill: parent
acceptedButtons: Qt.RightButton | Qt.LeftButton
hoverEnabled: true
- onClicked: {
+ onClicked: {
if (mouse.button === Qt.LeftButton) {
_inspectorModel.setPropertyAnimated(
model.modelData.instance,
@@ -389,6 +426,9 @@ Rectangle {
opacity: enabled ? 1 : .5
Layout.alignment: Qt.AlignTop
sourceComponent: {
+ if (modelData.title === "variants")
+ return variantTagsComponent;
+
const dataType = modelData.dataType;
switch (dataType) {
case DataModelDataType.Long:
@@ -1064,4 +1104,173 @@ Rectangle {
}
}
}
+
+ Component {
+ id: variantTagsComponent
+
+ Column {
+ width: root.width - 10
+ spacing: 10
+
+ Row {
+ anchors.right: parent.right
+ anchors.rightMargin: 5
+ spacing: 5
+
+ ToolButton {
+ id: importButton
+ text: qsTr("Import...")
+ width: 70
+ height: 20
+
+ onClicked: {
+ _variantsGroupModel.importVariants()
+ }
+ }
+
+ ToolButton {
+ id: exportButton
+ text: qsTr("Export...")
+ width: 70
+ height: 20
+ enabled: !_variantsGroupModel.variantsEmpty
+
+ onClicked: {
+ _variantsGroupModel.exportVariants()
+ }
+ }
+ }
+
+ Text {
+ text: qsTr("There are no variant tags yet. Click [+ Group] to add a new tags group and start adding tags.")
+ color: "#ffffff"
+ visible: _variantsGroupModel.variantsEmpty
+ }
+
+ Repeater {
+ id: tagsRepeater
+ model: _variantsGroupModel
+ property int maxGroupLabelWidth;
+
+ onItemAdded: {
+ // make all group labels have equal width as the widest one
+ if (index == 0)
+ maxGroupLabelWidth = 20; // min group label width
+
+ if (item.groupLabelWidth > maxGroupLabelWidth) {
+ maxGroupLabelWidth = item.groupLabelWidth;
+
+ if (maxGroupLabelWidth > 150) // max group label width
+ maxGroupLabelWidth = 150;
+ }
+ }
+
+ Row {
+ id: variantTagsRow
+ spacing: 5
+
+ readonly property var tagsModel: model.tags
+ readonly property var groupModel: model
+ readonly property int groupLabelWidth: tLabel.implicitWidth
+
+ Text {
+ id: tLabel
+ text: model.group
+ color: model.color
+ width: tagsRepeater.maxGroupLabelWidth;
+ elide: Text.ElideRight
+ anchors.top: parent.top
+ anchors.topMargin: 5
+
+ MouseArea {
+ anchors.fill: parent;
+ acceptedButtons: Qt.RightButton
+ onClicked: {
+ if (mouse.button === Qt.RightButton) {
+ const coords = mapToItem(root, mouse.x, mouse.y);
+ _parentView.showGroupContextMenu(coords.x, coords.y, model.group);
+ }
+ }
+ }
+ }
+
+ Flow {
+ width: root.width - 110
+ spacing: 5
+
+ Repeater {
+ model: tagsModel
+
+ Loader {
+ readonly property var tagsModel: model
+ readonly property var grpModel: groupModel
+ sourceComponent: tagComponent
+ }
+ }
+
+ ToolButton {
+ id: addTagButton
+ text: qsTr("+ Tag")
+ height: 25
+
+ onClicked: {
+ _variantsGroupModel.addNewTag(groupModel.group)
+ }
+
+ }
+ }
+ }
+ }
+
+ Item { width: 1; height: 5 } // vertical spacer
+
+ ToolButton {
+ id: addGroupButton
+ text: qsTr("+ Group")
+ width: 60
+ height: 25
+ onClicked: {
+ _variantsGroupModel.addNewGroup()
+ }
+ }
+
+ Item { width: 1; height: 5 } // vertical spacer
+ }
+ }
+
+ Component {
+ id: tagComponent
+
+ Rectangle {
+ property bool toggled: tagsModel.selected
+ property string grpColor: grpModel ? grpModel.color : ""
+
+ width: Math.max(tLabel.width + 10, 60)
+ height: 25
+ color: toggled ? grpColor : "#2e2f30"
+ border.color: "#959596"
+
+ Text {
+ id: tLabel
+ anchors.centerIn: parent
+ text: tagsModel.tag
+ color: toggled ? "#ffffff" : "#959596"
+ }
+
+ MouseArea {
+ anchors.fill: parent;
+ acceptedButtons: Qt.RightButton | Qt.LeftButton
+ onClicked: {
+ if (mouse.button === Qt.LeftButton) {
+ toggled = !toggled;
+ _variantsGroupModel.setTagState(grpModel.group, tagsModel.tag, toggled);
+ } else if (mouse.button === Qt.RightButton) {
+ const coords = mapToItem(root, mouse.x, mouse.y);
+ _parentView.showTagContextMenu(coords.x, coords.y, grpModel.group,
+ tagsModel.tag);
+ }
+ }
+ }
+ }
+ }
}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp
index 0b6db847..41be5767 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp
@@ -30,6 +30,10 @@
#include "ObjectListModel.h"
#include "StudioPreferences.h"
#include "StudioUtils.h"
+#include "StudioApp.h"
+#include "Core.h"
+#include "Qt3DSDMStudioSystem.h"
+#include "ClientDataModelBridge.h"
#include <QtCore/qtimer.h>
#include <QtQml/qqmlcontext.h>
@@ -50,10 +54,29 @@ QAbstractItemModel *ObjectBrowserView::model() const
void ObjectBrowserView::setModel(ObjectListModel *model)
{
- if (!m_model) {
+ if (!m_model)
m_model = new FlatObjectListModel(model, this);
- }
m_model->setSourceModel(model);
+
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+
+ // Remove "Scene.__Container" and "materials//Default" entries
+ QModelIndexList list = m_model->match(m_model->index(0, 0),
+ ObjectListModel::AbsolutePathRole,
+ QStringLiteral("Scene.")
+ + bridge->getMaterialContainerName(), 1,
+ Qt::MatchFlags(Qt::MatchWrap | Qt::MatchExactly
+ | Qt::MatchRecursive));
+ list.append(m_model->match(m_model->index(0, 0),
+ ObjectListModel::NameRole,
+ QStringLiteral("materials/") + bridge->getDefaultMaterialName(), 1,
+ Qt::MatchFlags(Qt::MatchWrap | Qt::MatchExactly
+ | Qt::MatchRecursive)));
+
+ for (int i = list.size(); i > 0; i--)
+ m_model->removeRow(list.at(i - 1).row(), m_model->index(0, 0));
+
m_ownerInstance = 0;
m_selection = -1;
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp
index c1a5fd95..b91727f5 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp
@@ -407,6 +407,14 @@ int FlatObjectListModel::rowCount(const QModelIndex &parent) const
return m_sourceInfo.count();
}
+bool FlatObjectListModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ beginRemoveRows(parent, row, row + count - 1);
+ m_sourceInfo.remove(row, count);
+ endRemoveRows();
+ return true;
+}
+
void FlatObjectListModel::setSourceModel(ObjectListModel *sourceModel)
{
beginResetModel();
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h
index 89b5a93c..4013f15c 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h
@@ -118,6 +118,7 @@ public:
int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &data, int role = Qt::EditRole) override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
void setSourceModel(ObjectListModel *sourceModel);
ObjectListModel *sourceModel() const { return m_sourceModel; }
diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.cpp b/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.cpp
new file mode 100644
index 00000000..83e72e7b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "VariantTagDialog.h"
+#include "ui_VariantTagDialog.h"
+#include "Dialogs.h"
+#include "StudioApp.h"
+#include "Core.h"
+#include "ProjectFile.h"
+
+VariantTagDialog::VariantTagDialog(DialogType type, const QString &group, const QString &name,
+ QWidget *parent)
+ : QDialog(parent)
+ , m_type(type)
+ , m_group(group)
+ , m_ui(new Ui::VariantTagDialog)
+{
+ m_ui->setupUi(this);
+
+ m_names.first = name;
+
+ if (type == AddGroup) {
+ setWindowTitle(tr("Add new Group"));
+ m_ui->label->setText(tr("Group name"));
+ } else if (type == RenameGroup) {
+ setWindowTitle(tr("Rename Group"));
+ m_ui->label->setText(tr("Group name"));
+ m_ui->lineEditTagName->setText(name);
+ m_ui->lineEditTagName->selectAll();
+ } else if (type == RenameTag) {
+ m_ui->lineEditTagName->setText(name);
+ m_ui->lineEditTagName->selectAll();
+ }
+}
+
+void VariantTagDialog::accept()
+{
+ QString name = m_ui->lineEditTagName->text();
+
+ if (name.isEmpty()) {
+ displayWarning(EmptyWarning);
+ } else if (name == m_names.first) { // no change
+ QDialog::reject();
+ } else if (((m_type == AddGroup || m_type == RenameGroup)
+ && !g_StudioApp.GetCore()->getProjectFile().isVariantGroupUnique(name))
+ || (!g_StudioApp.GetCore()->getProjectFile().isVariantTagUnique(m_group, name))) {
+ displayWarning(UniqueWarning);
+ } else {
+ m_names.second = name;
+ QDialog::accept();
+ }
+}
+
+std::pair<QString, QString> VariantTagDialog::getNames() const
+{
+ return m_names;
+}
+
+void VariantTagDialog::displayWarning(WarningType warningType)
+{
+ QString warning;
+ if (warningType == EmptyWarning) {
+ if (m_type == AddGroup || m_type == RenameGroup)
+ warning = tr("The group name must not be empty.");
+ else
+ warning = tr("The tag name must not be empty.");
+ } else if (warningType == UniqueWarning) {
+ if (m_type == AddGroup || m_type == RenameGroup)
+ warning = tr("The group name must be unique.");
+ else
+ warning = tr("The tag name must be unique within the tag group.");
+ }
+
+ g_StudioApp.GetDialogs()->DisplayMessageBox(tr("Warning"), warning,
+ Qt3DSMessageBox::ICON_WARNING, false);
+}
+
+VariantTagDialog::~VariantTagDialog()
+{
+ delete m_ui;
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.h b/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.h
new file mode 100644
index 00000000..b5e3989f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VARIANTTAGDIALOG_H
+#define VARIANTTAGDIALOG_H
+
+#include <QtWidgets/qdialog.h>
+
+#ifdef QT_NAMESPACE
+using namespace QT_NAMESPACE;
+#endif
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class VariantTagDialog;
+}
+QT_END_NAMESPACE
+
+class VariantTagDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ enum DialogType { AddTag, RenameTag, AddGroup, RenameGroup };
+
+ explicit VariantTagDialog(DialogType type, const QString &group = {}, const QString &name = {},
+ QWidget *parent = nullptr);
+ ~VariantTagDialog() override;
+
+public Q_SLOTS:
+ void accept() override;
+ std::pair<QString, QString> getNames() const;
+
+private:
+ enum WarningType {
+ EmptyWarning,
+ UniqueWarning
+ };
+
+ void displayWarning(WarningType warningType);
+
+ DialogType m_type;
+ QString m_group;
+ Ui::VariantTagDialog *m_ui;
+ std::pair<QString, QString> m_names; // holds the tags values before and after rename
+};
+
+#endif // VARIANTTAGDIALOG_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.ui b/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.ui
new file mode 100644
index 00000000..aa5d24ef
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.ui
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VariantTagDialog</class>
+ <widget class="QDialog" name="VariantTagDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>241</width>
+ <height>89</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Add new Tag</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QWidget" name="labelEditLayout" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Tag name</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineEditTagName"/>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>VariantTagDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>VariantTagDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp
new file mode 100644
index 00000000..a122889b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "VariantsGroupModel.h"
+#include "VariantsTagModel.h"
+#include "StudioApp.h"
+#include "Core.h"
+#include "Qt3DSDMStudioSystem.h"
+#include "ClientDataModelBridge.h"
+#include "IDocumentEditor.h"
+#include "VariantTagDialog.h"
+#include "StudioUtils.h"
+#include "Dialogs.h"
+
+#include <QtCore/qsavefile.h>
+
+VariantsGroupModel::VariantsGroupModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+
+}
+
+void VariantsGroupModel::refresh()
+{
+ int instance = g_StudioApp.GetCore()->GetDoc()->GetSelectedInstance();
+ auto bridge = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetClientDataModelBridge();
+
+ if (instance == 0 || !bridge->IsLayerInstance(instance)) {
+ m_instance = 0;
+ m_property = 0;
+ return;
+ }
+
+ auto propertySystem = g_StudioApp.GetCore()->GetDoc()->GetPropertySystem();
+ m_instance = instance;
+ m_property = bridge->GetLayer().m_variants.m_Property;
+
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(m_instance, m_property, sValue)) {
+ beginResetModel();
+ m_data.clear();
+
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ QHash<QString, QStringList> propTags;
+ if (!propVal.isEmpty()) {
+ const QStringList propTagsList = propVal.split(QChar(','));
+ for (auto &propTag : propTagsList) {
+ const QStringList propTagPair = propTag.split(QChar(':'));
+ propTags[propTagPair[0]].append(propTagPair[1]);
+ }
+ }
+
+ // build the variants data model
+ const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef();
+ const auto keys = variantsDef.keys();
+ for (auto &group : keys) {
+ TagGroupData g;
+ g.m_title = group;
+ g.m_color = variantsDef[group].m_color;
+
+ VariantsTagModel *m = new VariantsTagModel(this);
+ QVector<std::pair<QString, bool> > tags;
+ for (int i = 0; i < variantsDef[group].m_tags.length(); ++i)
+ tags.append({variantsDef[group].m_tags[i],
+ propTags[group].contains(variantsDef[group].m_tags[i])});
+
+ m->init(tags);
+ g.m_tagsModel = m;
+
+ m_data.push_back(g);
+ }
+
+ endResetModel();
+
+ bool isVariantsEmpty = rowCount() == 0;
+ if (m_variantsEmpty != isVariantsEmpty) {
+ m_variantsEmpty = isVariantsEmpty;
+ Q_EMIT varaintsEmptyChanged();
+ }
+ }
+}
+
+int VariantsGroupModel::rowCount(const QModelIndex &parent) const
+{
+ // For list models only the root node (an invalid parent) should return the list's size. For all
+ // other (valid) parents, rowCount() should return 0 so that it does not become a tree model.
+ if (parent.isValid())
+ return 0;
+
+ return m_data.size();
+}
+
+QVariant VariantsGroupModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role == GroupTitleRole)
+ return m_data.at(index.row()).m_title;
+ else if (role == GroupColorRole)
+ return m_data.at(index.row()).m_color;
+ else if (role == TagRole)
+ return QVariant::fromValue(m_data.at(index.row()).m_tagsModel);
+
+ return QVariant();
+}
+
+void VariantsGroupModel::setTagState(const QString &group, const QString &tag, bool selected)
+{
+ QString val;
+ QString tagsStr;
+ bool skipFirst = false;
+ for (auto &g : qAsConst(m_data)) {
+ if (g.m_title == group)
+ g.m_tagsModel->updateTagState(tag, selected);
+
+ tagsStr = g.m_tagsModel->serialize(g.m_title);
+ if (!tagsStr.isEmpty()) {
+ if (skipFirst)
+ val.append(QChar(','));
+ val.append(tagsStr);
+ skipFirst = true;
+ }
+ }
+
+ auto sVal = std::make_shared<qt3dsdm::CDataStr>(Q3DStudio::CString::fromQString(val));
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*g_StudioApp.GetCore()->GetDoc(), QObject::tr("Set Property"))
+ ->SetInstancePropertyValue(m_instance, m_property, sVal);
+}
+
+void VariantsGroupModel::addNewTag(const QString &group)
+{
+ VariantTagDialog dlg(VariantTagDialog::AddTag, group);
+
+ if (dlg.exec() == QDialog::Accepted) {
+ g_StudioApp.GetCore()->getProjectFile().addVariantTag(group, dlg.getNames().second);
+ refresh();
+ }
+}
+
+void VariantsGroupModel::importVariants()
+{
+ QString importFilePath = g_StudioApp.GetDialogs()->getImportVariantsDlg();
+
+ if (!importFilePath.isEmpty()) {
+ g_StudioApp.GetCore()->getProjectFile().loadVariants(importFilePath);
+ refresh();
+ }
+}
+
+void VariantsGroupModel::exportVariants()
+{
+ QString exportFilePath = g_StudioApp.GetDialogs()->getExportVariantsDlg();
+
+ if (exportFilePath.isEmpty())
+ return;
+
+ QDomDocument domDoc;
+ domDoc.appendChild(domDoc.createProcessingInstruction(QStringLiteral("xml"),
+ QStringLiteral("version=\"1.0\""
+ " encoding=\"utf-8\"")));
+
+ const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef();
+ const auto keys = variantsDef.keys();
+ QDomElement vElem = domDoc.createElement(QStringLiteral("variants"));
+ domDoc.appendChild(vElem);
+ for (auto &g : keys) {
+ const auto group = variantsDef[g];
+ QDomElement gElem = domDoc.createElement(QStringLiteral("variantgroup"));
+ gElem.setAttribute(QStringLiteral("id"), g);
+ gElem.setAttribute(QStringLiteral("color"), group.m_color);
+ vElem.appendChild(gElem);
+
+ for (auto &t : qAsConst(group.m_tags)) {
+ QDomElement tElem = domDoc.createElement(QStringLiteral("variant"));;
+ tElem.setAttribute(QStringLiteral("id"), t);
+ gElem.appendChild(tElem);
+ }
+ }
+
+ QSaveFile file(exportFilePath);
+ if (StudioUtils::openTextSave(file))
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+}
+
+void VariantsGroupModel::addNewGroup()
+{
+ VariantTagDialog dlg(VariantTagDialog::AddGroup);
+
+ if (dlg.exec() == QDialog::Accepted) {
+ g_StudioApp.GetCore()->getProjectFile().addVariantGroup(dlg.getNames().second);
+ refresh();
+ }
+}
+
+QHash<int, QByteArray> VariantsGroupModel::roleNames() const
+{
+ auto names = QAbstractListModel::roleNames();
+ names.insert(GroupTitleRole, "group");
+ names.insert(GroupColorRole, "color");
+ names.insert(TagRole, "tags");
+ return names;
+}
+
+Qt::ItemFlags VariantsGroupModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+
+ return Qt::ItemIsEditable;
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.h b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.h
new file mode 100644
index 00000000..75a218f7
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VARIANTSGROUPMODEL_H
+#define VARIANTSGROUPMODEL_H
+
+#include <QtCore/qabstractitemmodel.h>
+
+class VariantsTagModel;
+
+class VariantsGroupModel : public QAbstractListModel
+{
+ Q_OBJECT
+ Q_PROPERTY(bool variantsEmpty MEMBER m_variantsEmpty NOTIFY varaintsEmptyChanged)
+
+public:
+Q_SIGNALS:
+ void varaintsEmptyChanged();
+
+public:
+ explicit VariantsGroupModel(QObject *parent = nullptr);
+
+ enum Roles {
+ GroupTitleRole = Qt::UserRole + 1,
+ GroupColorRole,
+ TagRole
+ };
+
+ struct TagGroupData
+ {
+ QString m_title;
+ QString m_color;
+ VariantsTagModel *m_tagsModel = nullptr;
+ };
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = GroupTitleRole) const override;
+
+ Qt::ItemFlags flags(const QModelIndex& index) const override;
+
+ void refresh();
+
+ Q_INVOKABLE void setTagState(const QString &group, const QString &tag, bool selected);
+ Q_INVOKABLE void addNewTag(const QString &group);
+ Q_INVOKABLE void addNewGroup();
+ Q_INVOKABLE void importVariants();
+ Q_INVOKABLE void exportVariants();
+
+
+protected:
+ QHash<int, QByteArray> roleNames() const override;
+
+private:
+ QVector<TagGroupData> m_data;
+ int m_instance = 0; // selected layer instance
+ int m_property = 0; // variant tags property handler
+ bool m_variantsEmpty = true; // no groups (nor tags)
+};
+
+#endif // VARIANTSGROUPMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.cpp b/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.cpp
new file mode 100644
index 00000000..910b4f09
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "VariantsTagModel.h"
+
+VariantsTagModel::VariantsTagModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+
+}
+
+void VariantsTagModel::init(const QVector<std::pair<QString, bool> > &data)
+{
+ m_data = data;
+}
+
+void VariantsTagModel::updateTagState(const QString &tag, bool selected)
+{
+ for (auto &t : m_data) {
+ if (t.first == tag) {
+ t.second = selected;
+ break;
+ }
+ }
+}
+
+// return the tags in a formatted string to be saved to the property
+QString VariantsTagModel::serialize(const QString &groupName) const
+{
+ QString ret;
+ bool skipFirst = false;
+ for (auto &t : qAsConst(m_data)) {
+ if (t.second) {
+ if (skipFirst)
+ ret.append(QLatin1Char(','));
+
+ ret.append(groupName + QLatin1Char(':') + t.first);
+
+ skipFirst = true;
+ }
+ }
+
+ return ret;
+}
+
+int VariantsTagModel::rowCount(const QModelIndex &parent) const
+{
+ // For list models only the root node (an invalid parent) should return the list's size. For all
+ // other (valid) parents, rowCount() should return 0 so that it does not become a tree model.
+ if (parent.isValid())
+ return 0;
+
+ return m_data.size();
+}
+
+QVariant VariantsTagModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role == TagRole)
+ return m_data.at(index.row()).first;
+ else if (role == SelectedRole)
+ return m_data.at(index.row()).second;
+
+ return QVariant();
+}
+
+QHash<int, QByteArray> VariantsTagModel::roleNames() const
+{
+ auto names = QAbstractListModel::roleNames();
+ names.insert(TagRole, "tag");
+ names.insert(SelectedRole, "selected");
+ return names;
+}
+
+Qt::ItemFlags VariantsTagModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+
+ return Qt::ItemIsEditable; // FIXME: Implement me!
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h b/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.h
index e1a6914f..01bb4e73 100644
--- a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.h
@@ -1,7 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2008 NVIDIA Corporation.
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt 3D Studio.
@@ -27,29 +26,37 @@
**
****************************************************************************/
-#ifndef INCLUDED_ITIMELINE_KEYFRAMES_MANAGER_H
-#define INCLUDED_ITIMELINE_KEYFRAMES_MANAGER_H 1
+#ifndef VARIANTSTAGMODEL_H
+#define VARIANTSTAGMODEL_H
-#pragma once
+#include <QtCore/qabstractitemmodel.h>
-#include "IKeyframesManager.h"
-
-//=============================================================================
-/**
- * Interface to manage keyframes related actions in the Timeline
- */
-//=============================================================================
-class ITimelineKeyframesManager : public IKeyframesManager
+class VariantsTagModel : public QAbstractListModel
{
+ Q_OBJECT
+
public:
- virtual ~ITimelineKeyframesManager() {}
-
- virtual void SetKeyframeTime(long inTime) = 0;
- virtual void SetKeyframesDynamic(bool inDynamic) = 0;
- virtual long OffsetSelectedKeyframes(long inOffset) = 0;
- virtual bool CanMakeSelectedKeyframesDynamic() = 0;
- virtual void CommitChangedKeyframes() = 0;
- virtual void RollbackChangedKeyframes() = 0;
+ explicit VariantsTagModel(QObject *parent = nullptr);
+
+ enum Roles {
+ TagRole = Qt::UserRole + 1,
+ SelectedRole,
+ };
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = TagRole) const override;
+
+ Qt::ItemFlags flags(const QModelIndex& index) const override;
+
+ void init(const QVector<std::pair<QString, bool> > &data);
+ void updateTagState(const QString &tag, bool selected);
+ QString serialize(const QString &groupName) const;
+
+protected:
+ QHash<int, QByteArray> roleNames() const override;
+
+private:
+ QVector<std::pair<QString, bool> > m_data; // [{tagName, selectedState}, ...]
};
-#endif // INCLUDED_IKEYFRAMES_MANAGER_H
+#endif // VARIANTSTAGMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp
index 0a098a5b..f6d498f2 100644
--- a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp
+++ b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp
@@ -454,6 +454,24 @@ void ProjectFileSystemModel::setRootPath(const QString &path)
m_projectReferencesUpdateMap.clear();
m_projectReferencesUpdateTimer.stop();
+ // Delete the old model. If the new project is in a totally different directory tree, not
+ // doing this will result in unexplicable crashes when trying to parse something that should
+ // not be parsed.
+ disconnect(m_model, &QAbstractItemModel::rowsInserted,
+ this, &ProjectFileSystemModel::modelRowsInserted);
+ disconnect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &ProjectFileSystemModel::modelRowsRemoved);
+ disconnect(m_model, &QAbstractItemModel::layoutChanged,
+ this, &ProjectFileSystemModel::modelLayoutChanged);
+ delete m_model;
+ m_model = new QFileSystemModel(this);
+ connect(m_model, &QAbstractItemModel::rowsInserted,
+ this, &ProjectFileSystemModel::modelRowsInserted);
+ connect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &ProjectFileSystemModel::modelRowsRemoved);
+ connect(m_model, &QAbstractItemModel::layoutChanged,
+ this, &ProjectFileSystemModel::modelLayoutChanged);
+
setRootIndex(m_model->setRootPath(path));
// Open the presentations folder by default
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp b/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp
index 710dd4b8..9229e519 100644
--- a/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp
+++ b/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp
@@ -56,6 +56,10 @@ QVariant SlideModel::data(const QModelIndex &index, int role) const
return slideName(m_slides[row]);
case SelectedRole:
return row == m_selectedRow;
+ case VariantsRole:
+ int slideIdx = GetDoc()->GetStudioSystem()->GetSlideSystem()->GetSlideIndex(m_slides[row]);
+ if (slideIdx < m_variants.size())
+ return m_variants.at(slideIdx);
}
return {};
@@ -91,7 +95,7 @@ bool SlideModel::setData(const QModelIndex &index, const QVariant &value, int ro
}
Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), {role});
- return true;
+ break;
}
default:
return false;
@@ -112,6 +116,7 @@ QHash<int, QByteArray> SlideModel::roleNames() const
{
auto names = QAbstractListModel::roleNames();
names.insert(NameRole, "name");
+ names.insert(VariantsRole, "variants");
names.insert(SelectedRole, "selected");
return names;
@@ -347,6 +352,61 @@ void SlideModel::setSlideName(const qt3dsdm::Qt3DSDMSlideHandle &handle, const Q
}
}
+void SlideModel::refreshVariants(const QStringList &variants)
+{
+ m_variants.clear();
+
+ if (variants.isEmpty()) {
+ const auto *slideSystem = GetDoc()->GetStudioSystem()->GetSlideSystem();
+ int slideCount = slideSystem->GetSlideCount(slideSystem->GetMasterSlide(
+ GetDoc()->GetActiveSlide()));
+
+ QString vTemplate = QStringLiteral(" <font color='%1'>%2</font>");
+ QVector<QHash<QString, int>> counts(slideCount); // <group, total count tags>
+
+ const auto propertySystem = GetDoc()->GetPropertySystem();
+ const auto layers = GetDoc()->getLayers();
+ for (auto layer : layers) {
+ int slideIdx = slideIndex(slideSystem->GetAssociatedSlide(layer));
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(layer, GetBridge()->GetLayer().m_variants,
+ sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ if (!propVal.isEmpty()) {
+ QStringList tagPairs = propVal.split(QLatin1Char(','));
+ for (int i = 0; i < tagPairs.size(); ++i) {
+ QString group = tagPairs[i].left(tagPairs[i].indexOf(QLatin1Char(':')));
+ ++counts[slideIdx][group];
+ }
+ }
+ }
+ }
+
+ // add master slide layers counts to other layers
+ const auto keys = counts[0].keys();
+ for (int i = 1; i < slideCount; ++i) {
+ for (auto g : keys)
+ counts[i][g] += counts[0][g];
+ }
+
+ // update the variants counts model (m_variants)
+ auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef();
+ for (int i = 0; i < counts.size(); ++i) { // slides indexes
+ QString slideVariants;
+ const auto keys = counts[i].keys();
+ for (auto g : keys) // variants groups
+ slideVariants.append(vTemplate.arg(variantsDef[g].m_color).arg(counts[i][g]));
+
+ m_variants << slideVariants;
+ }
+ } else {
+ m_variants = variants;
+ }
+
+ Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), {VariantsRole});
+}
+
CDoc *SlideModel::GetDoc() const
{
return g_StudioApp.GetCore()->GetDoc();
@@ -375,10 +435,10 @@ void SlideModel::refreshSlideLabel(qt3dsdm::Qt3DSDMInstanceHandle instanceHandle
if (m_slides[i] == slideHandle) {
setData(index(i, 0), GetBridge()->GetName(instanceHandle),
SlideModel::NameRole);
+ break;
}
}
}
-
}
// Set selected slide highlight on UI
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideModel.h b/src/Authoring/Studio/Palettes/Slide/SlideModel.h
index 1de717cd..6f2de22f 100644
--- a/src/Authoring/Studio/Palettes/Slide/SlideModel.h
+++ b/src/Authoring/Studio/Palettes/Slide/SlideModel.h
@@ -44,7 +44,8 @@ public:
enum Roles {
NameRole = Qt::DisplayRole,
HandleRole = Qt::UserRole + 1,
- SelectedRole
+ SelectedRole,
+ VariantsRole
};
SlideModel(int slideCount, QObject *parent = nullptr);
@@ -76,6 +77,8 @@ public:
void refreshSlideLabel(qt3dsdm::Qt3DSDMInstanceHandle instanceHandle,
qt3dsdm::Qt3DSDMPropertyHandle propertyHandle);
void setSelectedSlideIndex(const QModelIndex &index);
+ void refreshVariants(const QStringList &variants = {});
+ QStringList variants() const { return m_variants; }
private:
bool hasSlideWithName(const QString &name) const;
@@ -89,6 +92,7 @@ private:
int m_selectedRow = -1;
int m_rearrangeStartRow = -1;
int m_rearrangeEndRow = -1;
+ QStringList m_variants; // model for variants tags display
QHash<qt3dsdm::Qt3DSDMInstanceHandle, qt3dsdm::Qt3DSDMSlideHandle> m_slideLookupHash;
};
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.cpp b/src/Authoring/Studio/Palettes/Slide/SlideView.cpp
index 5bb5aa67..51f90372 100644
--- a/src/Authoring/Studio/Palettes/Slide/SlideView.cpp
+++ b/src/Authoring/Studio/Palettes/Slide/SlideView.cpp
@@ -27,11 +27,9 @@
****************************************************************************/
#include "SlideView.h"
-#include <QtGui/qcolor.h>
#include "Core.h"
#include "Dispatch.h"
#include "Doc.h"
-#include "Literals.h"
#include "StudioPreferences.h"
#include "SlideModel.h"
#include "StudioApp.h"
@@ -45,22 +43,19 @@
#include "Qt3DSDMSlides.h"
#include "Dialogs.h"
-#include <QtCore/qcoreapplication.h>
#include <QtCore/qtimer.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlengine.h>
-#include <QtWidgets/qdesktopwidget.h>
-#include <QtWidgets/qdockwidget.h>
SlideView::SlideView(QWidget *parent) : QQuickWidget(parent)
, m_MasterSlideModel(new SlideModel(1, this))
, m_SlidesModel(new SlideModel(0, this))
+ , m_CurrentModel(m_SlidesModel)
, m_ActiveRoot(0)
, m_toolTip(tr("No Controller"))
{
g_StudioApp.GetCore()->GetDispatch()->AddPresentationChangeListener(this);
setResizeMode(QQuickWidget::SizeRootObjectToView);
- m_CurrentModel = m_SlidesModel;
QTimer::singleShot(0, this, &SlideView::initialize);
}
@@ -82,10 +77,7 @@ void SlideView::setShowMasterSlide(bool show)
if (show == currentIsMaster)
return;
- if (show)
- m_CurrentModel = m_MasterSlideModel;
- else
- m_CurrentModel = m_SlidesModel;
+ m_CurrentModel = show ? m_MasterSlideModel : m_SlidesModel;
// We need to get the first slide in the correct master mode
CDoc *theDoc = GetDoc();
@@ -124,8 +116,6 @@ void SlideView::showControllerDialog(const QPoint &point)
m_dataInputSelector->setData(dataInputList, currCtr);
CDialogs::showWidgetBrowser(this, m_dataInputSelector, point,
CDialogs::WidgetBrowserAlign::ToolButton);
-
- return;
}
bool SlideView::toolTipsEnabled()
@@ -142,7 +132,7 @@ QSize SlideView::minimumSizeHint() const
{
// prevent datainput control indicator from overlapping
// with slide name too much when panel is minimised
- return {80, 0};
+ return {100, 0};
}
void SlideView::deselectAll()
@@ -209,8 +199,9 @@ void SlideView::OnNewPresentation()
// Set up listener for the name changes to slide
m_Connections.push_back(theSignalProvider->ConnectInstancePropertyValue(
- std::bind(&SlideModel::refreshSlideLabel, m_SlidesModel,
+ std::bind(&SlideView::onPropertyChanged, this,
std::placeholders::_1, std::placeholders::_2)));
+
// Set up listener for undo/redo changes in order to update
// slide datainput control
CDispatch *theDispatch = g_StudioApp.GetCore()->GetDispatch();
@@ -290,18 +281,16 @@ void SlideView::onDataInputChange(int handle, int instance, const QString &dataI
m_toolTip = tr("No Controller");
}
qt3dsdm::Qt3DSDMPropertyHandle ctrldProp;
- if (bridge->GetObjectType(slideRoot) == EStudioObjectType::OBJTYPE_SCENE) {
+ if (bridge->GetObjectType(slideRoot) == EStudioObjectType::OBJTYPE_SCENE)
ctrldProp = bridge->GetObjectDefinitions().m_Scene.m_ControlledProperty;
- } else if (bridge->GetObjectType(slideRoot) ==
- EStudioObjectType::OBJTYPE_COMPONENT) {
+ else if (bridge->GetObjectType(slideRoot) == EStudioObjectType::OBJTYPE_COMPONENT)
ctrldProp = bridge->GetObjectDefinitions().m_Component.m_ControlledProperty;
- } else {
+ else
Q_ASSERT(false);
- }
qt3dsdm::SValue controlledPropertyVal;
- doc->GetStudioSystem()->GetPropertySystem()->GetInstancePropertyValue(
- slideRoot, ctrldProp, controlledPropertyVal);
+ doc->GetStudioSystem()->GetPropertySystem()->GetInstancePropertyValue(slideRoot, ctrldProp,
+ controlledPropertyVal);
// To indicate that slide transitions are controlled by data input,
// we set "controlled property" of this scene to contain the name of
@@ -309,27 +298,27 @@ void SlideView::onDataInputChange(int handle, int instance, const QString &dataI
// If we have existing slide control in this root element, replace it.
// Otherwise just append slide control string to controlledproperty
// (it might already contain timeline control information)
- auto existingCtrl = qt3dsdm::get<QString>(controlledPropertyVal);
- if (existingCtrl.contains("@slide")) {
- int slideStrPos = existingCtrl.indexOf("@slide");
+ QString existingCtrl = qt3dsdm::get<QString>(controlledPropertyVal);
+ if (existingCtrl.contains(QLatin1String("@slide"))) {
+ int slideStrPos = existingCtrl.indexOf(QLatin1String("@slide"));
// find the controlling datainput name and build the string to replace
- int ctrStrPos = existingCtrl.lastIndexOf("$", slideStrPos - 2);
+ int ctrStrPos = existingCtrl.lastIndexOf(QLatin1Char('$'), slideStrPos - 2);
QString prevCtrler = existingCtrl.mid(ctrStrPos, slideStrPos - ctrStrPos - 1);
- existingCtrl.replace(prevCtrler + " @slide", fullSlideControlStr);
+ existingCtrl.replace(prevCtrler + QLatin1String(" @slide"), fullSlideControlStr);
} else {
- (!existingCtrl.isEmpty() && m_controlled) ? existingCtrl.append(" ") : 0;
+ if (!existingCtrl.isEmpty() && m_controlled)
+ existingCtrl.append(QLatin1Char(' '));
existingCtrl.append(fullSlideControlStr);
}
- if (existingCtrl.endsWith(" "))
+ if (existingCtrl.endsWith(QLatin1Char(' ')))
existingCtrl.chop(1);
- if (existingCtrl.startsWith(" "))
+ if (existingCtrl.startsWith(QLatin1Char(' ')))
existingCtrl.remove(0, 1);
qt3dsdm::SValue fullCtrlPropVal
- = std::make_shared<qt3dsdm::CDataStr>(
- Q3DStudio::CString::fromQString(existingCtrl));
+ = std::make_shared<qt3dsdm::CDataStr>(Q3DStudio::CString::fromQString(existingCtrl));
Q3DStudio::SCOPED_DOCUMENT_EDITOR(*doc, QObject::tr("Set Slide control"))
->SetInstancePropertyValue(slideRoot, ctrldProp, fullCtrlPropVal);
@@ -338,6 +327,17 @@ void SlideView::onDataInputChange(int handle, int instance, const QString &dataI
Q_EMIT controlledChanged();
}
+void SlideView::onPropertyChanged(qt3dsdm::Qt3DSDMInstanceHandle inInstance,
+ qt3dsdm::Qt3DSDMPropertyHandle inProperty)
+{
+ // refresh slide name
+ m_SlidesModel->refreshSlideLabel(inInstance, inProperty);
+
+ // refresh variants
+ if (inProperty == GetBridge()->GetLayer().m_variants)
+ refreshVariants();
+}
+
void SlideView::onDockLocationChange(Qt::DockWidgetArea area)
{
m_dockArea = area;
@@ -353,24 +353,22 @@ void SlideView::updateDataInputStatus()
qt3dsdm::Qt3DSDMInstanceHandle slideRoot = doc->GetActiveRootInstance();
qt3dsdm::Qt3DSDMPropertyHandle ctrldProp;
- if (bridge->GetObjectType(slideRoot) == EStudioObjectType::OBJTYPE_SCENE) {
+ if (bridge->GetObjectType(slideRoot) == EStudioObjectType::OBJTYPE_SCENE)
ctrldProp = bridge->GetObjectDefinitions().m_Scene.m_ControlledProperty;
- } else if (bridge->GetObjectType(slideRoot) ==
- EStudioObjectType::OBJTYPE_COMPONENT) {
+ else if (bridge->GetObjectType(slideRoot) == EStudioObjectType::OBJTYPE_COMPONENT)
ctrldProp = bridge->GetObjectDefinitions().m_Component.m_ControlledProperty;
- } else {
+ else
Q_ASSERT(false);
- }
qt3dsdm::SValue controlledPropertyVal;
- doc->GetStudioSystem()->GetPropertySystem()->GetInstancePropertyValue(
- slideRoot, ctrldProp, controlledPropertyVal);
- auto existingCtrl = qt3dsdm::get<QString>(controlledPropertyVal);
+ doc->GetStudioSystem()->GetPropertySystem()->GetInstancePropertyValue(slideRoot, ctrldProp,
+ controlledPropertyVal);
+ QString existingCtrl = qt3dsdm::get<QString>(controlledPropertyVal);
QString newController;
- int slideStrPos = existingCtrl.indexOf("@slide");
+ int slideStrPos = existingCtrl.indexOf(QLatin1String("@slide"));
if (slideStrPos != -1) {
- int ctrStrPos = existingCtrl.lastIndexOf("$", slideStrPos - 2);
+ int ctrStrPos = existingCtrl.lastIndexOf(QLatin1Char('$'), slideStrPos - 2);
newController = existingCtrl.mid(ctrStrPos + 1, slideStrPos - ctrStrPos - 2);
}
if (newController != m_currentController) {
@@ -505,6 +503,12 @@ bool SlideView::isMaster(const qt3dsdm::Qt3DSDMSlideHandle &inSlideHandle)
return (0 == GetSlideIndex(inSlideHandle));
}
+void SlideView::refreshVariants()
+{
+ m_SlidesModel->refreshVariants();
+ m_MasterSlideModel->refreshVariants(m_SlidesModel->variants());
+}
+
void SlideView::OnBeginDataModelNotifications()
{
}
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.h b/src/Authoring/Studio/Palettes/Slide/SlideView.h
index e95ac314..18c4d1d7 100644
--- a/src/Authoring/Studio/Palettes/Slide/SlideView.h
+++ b/src/Authoring/Studio/Palettes/Slide/SlideView.h
@@ -67,6 +67,7 @@ public:
QSize minimumSizeHint() const override;
void onDataInputChange(int handle, int instance, const QString &dataInputName);
void onDockLocationChange(Qt::DockWidgetArea area);
+ void refreshVariants();
Q_INVOKABLE void deselectAll();
Q_INVOKABLE void addNewSlide(int row);
@@ -120,10 +121,12 @@ private:
long GetSlideIndex(const qt3dsdm::Qt3DSDMSlideHandle &inSlideHandle);
bool isMaster(const qt3dsdm::Qt3DSDMSlideHandle &inSlideHandle);
void rebuildSlideList(const qt3dsdm::Qt3DSDMSlideHandle &inActiveSlideHandle);
+ void onPropertyChanged(qt3dsdm::Qt3DSDMInstanceHandle inInstance,
+ qt3dsdm::Qt3DSDMPropertyHandle inProperty);
- SlideModel *m_CurrentModel = nullptr;
SlideModel *m_MasterSlideModel = nullptr;
SlideModel *m_SlidesModel = nullptr;
+ SlideModel *m_CurrentModel = nullptr;
DataInputSelectView *m_dataInputSelector = nullptr;
QColor m_BaseColor = QColor::fromRgb(75, 75, 75);
std::vector<std::shared_ptr<qt3dsdm::ISignalConnection>>
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.qml b/src/Authoring/Studio/Palettes/Slide/SlideView.qml
index c8f409d0..4113c947 100644
--- a/src/Authoring/Studio/Palettes/Slide/SlideView.qml
+++ b/src/Authoring/Studio/Palettes/Slide/SlideView.qml
@@ -263,6 +263,17 @@ Rectangle {
}
}
+ Label { // variants
+ width: slideImage.width
+ font.pixelSize: _fontSize
+ padding: 3
+ verticalAlignment: Text.AlignVCenter
+ background: Rectangle { color:"#111111" }
+ wrapMode: Text.WordWrap
+ visible: model.variants !== ""
+ text: model.variants
+ }
+
Item {
anchors.horizontalCenter: slideImage.horizontalCenter
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h
index e8cdd767..a01e5e48 100644
--- a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h
@@ -37,7 +37,6 @@
class RowTree;
class CControlWindowListener;
-class ITimelineKeyframesManager;
// Data model specific ??
class CDropTarget;
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineTimebar.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineTimebar.cpp
index ba6dd622..fdeb7338 100644
--- a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineTimebar.cpp
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineTimebar.cpp
@@ -37,7 +37,6 @@
#include "Doc.h"
#include "Dispatch.h"
#include "Core.h"
-#include "DurationEditDlg.h"
#include "IDocumentEditor.h"
#include "StudioFullSystem.h"
#include "StudioPreferences.h"
@@ -218,6 +217,5 @@ void Qt3DSDMTimelineTimebar::SetTimebarComment(const Q3DStudio::CString &inComme
void Qt3DSDMTimelineTimebar::SetTimebarTime(ITimeChangeCallback *inCallback /*= nullptr*/)
{
g_StudioApp.GetDialogs()->asyncDisplayDurationEditDialog(GetStartTime(), GetEndTime(),
- m_TimelineTranslationManager->GetDoc(),
inCallback);
}
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h
index c803ef2c..7e4ea614 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h
@@ -35,7 +35,7 @@
struct Keyframe
{
- Keyframe(double time, RowTimeline *propRow)
+ Keyframe(long time, RowTimeline *propRow)
: time(time)
, rowProperty(propRow)
, rowMaster(propRow->parentRow())
@@ -47,7 +47,7 @@ struct Keyframe
return binding && binding->IsSelected();
}
- double time;
+ long time;
QString propertyType;
RowTimeline *rowProperty = nullptr;
RowTimeline *rowMaster = nullptr;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp
index 936d60ae..9a12aab3 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp
@@ -30,13 +30,8 @@
#include "RowTree.h"
#include "RowTimeline.h"
#include "Keyframe.h"
-#include "RowTypes.h"
-#include "TimelineConstants.h"
-#include "Ruler.h"
-#include "PlayHead.h"
#include "RowManager.h"
#include "TimelineGraphicsScene.h"
-#include "StudioObjectTypes.h"
#include "StudioApp.h"
#include "Core.h"
#include "Doc.h"
@@ -44,26 +39,16 @@
#include "CmdDataModelRemoveKeyframe.h"
#include "CmdDataModelInsertKeyframe.h"
#include "CmdDataModelChangeKeyframe.h"
-#include "Qt3DSDMAnimation.h"
#include "ClientDataModelBridge.h"
-#include "Bindings/ITimelineItemBinding.h"
#include "Bindings/OffsetKeyframesCommandHelper.h"
-#include "Bindings/Qt3DSDMTimelineKeyframe.h"
+#include "Bindings/PasteKeyframesCommandHelper.h"
#include "StudioPreferences.h"
-#include "Qt3DSDMAnimation.h"
#include "Dialogs.h"
-#include "TimeEditDlg.h"
-#include "Bindings/PasteKeyframesCommandHelper.h"
-
-#include <qglobal.h>
-#include <QtCore/qhash.h>
-#include <QtCore/qdebug.h>
+#include "TimeEnums.h"
using namespace qt3dsdm;
-KeyframeManager::KeyframeManager(TimelineGraphicsScene *scene)
- : m_scene(scene)
- , m_pasteKeyframeCommandHelper(nullptr)
+KeyframeManager::KeyframeManager(TimelineGraphicsScene *scene) : m_scene(scene)
{
}
@@ -72,7 +57,7 @@ KeyframeManager::~KeyframeManager()
delete m_pasteKeyframeCommandHelper;
}
-QList<Keyframe *> KeyframeManager::insertKeyframe(RowTimeline *row, double time,
+QList<Keyframe *> KeyframeManager::insertKeyframe(RowTimeline *row, long time,
bool selectInsertedKeyframes)
{
QList<Keyframe *> addedKeyframes;
@@ -88,9 +73,8 @@ QList<Keyframe *> KeyframeManager::insertKeyframe(RowTimeline *row, double time,
}
if (!propRows.empty()) {
- Keyframe *keyframe = nullptr;
for (const auto &r : qAsConst(propRows)) {
- keyframe = new Keyframe(time, r);
+ Keyframe *keyframe = new Keyframe(time, r);
r->insertKeyframe(keyframe);
r->parentRow()->insertKeyframe(keyframe);
addedKeyframes.append(keyframe);
@@ -159,10 +143,9 @@ void KeyframeManager::commitMoveSelectedKeyframes()
{
CDoc *theDoc = g_StudioApp.GetCore()->GetDoc();
COffsetKeyframesCommandHelper h(*theDoc);
- for (Keyframe *keyframe : qAsConst(m_selectedKeyframes)) {
- const long msTime = round(keyframe->time * 1000);
- keyframe->binding->UpdateKeyframesTime(&h, msTime);
- }
+
+ for (Keyframe *keyframe : qAsConst(m_selectedKeyframes))
+ keyframe->binding->UpdateKeyframesTime(&h, keyframe->time);
}
void KeyframeManager::selectKeyframesInRect(const QRectF &rect)
@@ -300,7 +283,7 @@ void KeyframeManager::copySelectedKeyframes()
m_pasteKeyframeCommandHelper = new CPasteKeyframeCommandHelper();
// calc min copied frames time
- double minTime = 999999.0; // in seconds (~277.78 hrs)
+ long minTime = LONG_MAX;
for (auto keyframe : qAsConst(m_selectedKeyframes)) {
if (keyframe->time < minTime)
minTime = keyframe->time;
@@ -331,9 +314,9 @@ void KeyframeManager::copySelectedKeyframes()
break;
}
- double dt = Qt3DSDMTimelineKeyframe::GetTimeInSecs(kf->GetTime()) - minTime;
- qt3dsdm::Qt3DSDMAnimationHandle animation =
- animationCore->GetAnimationForKeyframe(theKeyframeHandles[0]);
+ float dt = Qt3DSDMTimelineKeyframe::GetTimeInSecs(kf->GetTime() - minTime);
+ qt3dsdm::Qt3DSDMAnimationHandle animation
+ = animationCore->GetAnimationForKeyframe(theKeyframeHandles[0]);
m_pasteKeyframeCommandHelper->AddKeyframeData(
animationCore->GetAnimationInfo(animation).m_Property, dt, info, infoCount);
}
@@ -373,28 +356,47 @@ void KeyframeManager::pasteKeyframes()
}
}
-void KeyframeManager::moveSelectedKeyframes(double dx)
+void KeyframeManager::moveSelectedKeyframes(long newTime)
{
- double dt = m_scene->ruler()->distanceToTime(dx);
+ Keyframe *pressedKeyframe = m_scene->pressedKeyframe();
- if (dt < 0) { // check min limit
- double minTime = 999999; // seconds (~277.78 hrs)
- for (auto keyframe : qAsConst(m_selectedKeyframes)) {
- if (keyframe->time < minTime)
- minTime = keyframe->time;
- }
+ Q_ASSERT(pressedKeyframe);
- if (minTime + dt < 0)
- dt = -minTime;
- }
+ // make sure the min-time keyframe doesn't go below zero
+ long minTime = getMinSelectedKeyframesTime();
+ if (pressedKeyframe->time - minTime > newTime)
+ newTime = pressedKeyframe->time - minTime;
- for (auto keyframe : qAsConst(m_selectedKeyframes))
- keyframe->time += dt;
+ for (auto keyframe : qAsConst(m_selectedKeyframes)) {
+ if (keyframe != pressedKeyframe)
+ keyframe->time = newTime - (pressedKeyframe->time - keyframe->time);
+ }
+ pressedKeyframe->time = newTime;
for (auto row : qAsConst(m_selectedKeyframesMasterRows))
row->updateKeyframes();
}
+long KeyframeManager::getMinSelectedKeyframesTime() const
+{
+ long minTime = LONG_MAX;
+ for (auto keyframe : qAsConst(m_selectedKeyframes)) {
+ if (keyframe->time < minTime)
+ minTime = keyframe->time;
+ }
+
+ return minTime;
+}
+
+// returns the distance between the pressed keyframe and the min-time keyframe in a multiselection
+long KeyframeManager::getPressedKeyframeOffset() const
+{
+ if (m_scene->pressedKeyframe())
+ return m_scene->pressedKeyframe()->time - getMinSelectedKeyframesTime();
+
+ return 0;
+}
+
// selected keyframes belong to only one master row
bool KeyframeManager::oneMasterRowSelected() const
{
@@ -422,9 +424,7 @@ bool KeyframeManager::hasDynamicKeyframes(RowTree *row) const
return false;
}
-// IKeyframesManager interface to connect Doc and KeyframeManager
-// Mahmoud_TODO: rewrite a better interface for the new timeline
-// ITimelineKeyframesManager interface
+// IKeyframesManager interface
void KeyframeManager::SetKeyframeTime(long inTime)
{
g_StudioApp.GetDialogs()->asyncDisplayTimeEditDialog(inTime, g_StudioApp.GetCore()->GetDoc(),
@@ -459,35 +459,25 @@ void KeyframeManager::SetKeyframesDynamic(bool inDynamic)
g_StudioApp.GetCore()->ExecuteCommand(cmd);
}
-long KeyframeManager::OffsetSelectedKeyframes(long inOffset)
-{
- double dx = m_scene->ruler()->timeToDistance(inOffset / 1000.0);
- moveSelectedKeyframes(dx);
- return 0;
-}
-
-bool KeyframeManager::CanMakeSelectedKeyframesDynamic()
-{
- // Mahmoud_TODO: implement if needed
- return false;
-}
-
void KeyframeManager::CommitChangedKeyframes()
{
+ m_scene->resetPressedKeyframe();
commitMoveSelectedKeyframes();
}
void KeyframeManager::RollbackChangedKeyframes()
{
+ m_scene->resetPressedKeyframe();
+
for (Keyframe *keyframe : qAsConst(m_selectedKeyframes))
- keyframe->time = keyframe->binding->GetTime() / 1000.0;
+ keyframe->time = keyframe->binding->GetTime();
for (auto row : qAsConst(m_selectedKeyframesMasterRows))
row->updateKeyframes();
}
// IKeyframesManager interface
-bool KeyframeManager::HasSelectedKeyframes(bool inOnlyDynamic)
+bool KeyframeManager::HasSelectedKeyframes()
{
return hasSelectedKeyframes();
}
@@ -571,11 +561,6 @@ void KeyframeManager::SetKeyframeInterpolation()
}
}
-void KeyframeManager::SelectAllKeyframes()
-{
- // Mahmoud_TODO: implement if needed
-}
-
void KeyframeManager::DeselectAllKeyframes()
{
deselectAllKeyframes();
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h
index 6af9896f..9c160687 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h
@@ -29,10 +29,10 @@
#ifndef KEYFRAMEMANAGER_H
#define KEYFRAMEMANAGER_H
-#include "Bindings/ITimelineKeyframesManager.h"
+#include "IKeyframesManager.h"
+#include "Qt3DSDMAnimation.h"
#include <QtCore/qlist.h>
#include <StudioObjectTypes.h>
-#include "Qt3DSDMAnimation.h"
class RowTimeline;
class RowTree;
@@ -43,13 +43,13 @@ struct Keyframe;
QT_FORWARD_DECLARE_CLASS(QGraphicsSceneContextMenuEvent)
QT_FORWARD_DECLARE_CLASS(QRectF)
-class KeyframeManager : public ITimelineKeyframesManager
+class KeyframeManager : public IKeyframesManager
{
public:
KeyframeManager(TimelineGraphicsScene *m_scene);
- virtual ~KeyframeManager();
+ virtual ~KeyframeManager() override;
- QList<Keyframe *> insertKeyframe(RowTimeline *row, double time,
+ QList<Keyframe *> insertKeyframe(RowTimeline *row, long time,
bool selectInsertedKeyframes = true);
void selectKeyframe(Keyframe *keyframe);
void selectConnectedKeyframes(Keyframe *keyframe);
@@ -63,7 +63,7 @@ public:
void deleteKeyframes(RowTimeline *row, bool repaint = true);
void copySelectedKeyframes();
void pasteKeyframes();
- void moveSelectedKeyframes(double dx);
+ void moveSelectedKeyframes(long newTime);
void commitMoveSelectedKeyframes();
bool deleteSelectedKeyframes();
bool oneMasterRowSelected() const;
@@ -72,16 +72,11 @@ public:
bool hasDynamicKeyframes(RowTree *row) const;
// IKeyframesManager interface
- // Mahmoud_TODO: rewrite a better interface for the new timeline
- // ITimelineKeyframesManager interface
void SetKeyframeTime(long inTime) override;
void SetKeyframesDynamic(bool inDynamic) override;
- long OffsetSelectedKeyframes(long inOffset) override;
- bool CanMakeSelectedKeyframesDynamic() override;
void CommitChangedKeyframes() override;
void RollbackChangedKeyframes() override;
- // IKeyframesManager interface
- bool HasSelectedKeyframes(bool inOnlyDynamic) override;
+ bool HasSelectedKeyframes() override;
bool HasDynamicKeyframes() override;
bool CanPerformKeyframeCopy() override;
bool CanPerformKeyframePaste() override;
@@ -89,14 +84,16 @@ public:
bool RemoveKeyframes(bool inPerformCopy) override;
void PasteKeyframes() override;
void SetKeyframeInterpolation() override;
- void SelectAllKeyframes() override;
void DeselectAllKeyframes() override;
void SetChangedKeyframes() override;
+ long getPressedKeyframeOffset() const;
private:
qt3dsdm::SGetOrSetKeyframeInfo setKeyframeInfo(qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe,
qt3dsdm::IAnimationCore &inCore);
- CPasteKeyframeCommandHelper *m_pasteKeyframeCommandHelper;
+ long getMinSelectedKeyframesTime() const;
+
+ CPasteKeyframeCommandHelper *m_pasteKeyframeCommandHelper = nullptr;
TimelineGraphicsScene *m_scene;
QList<Keyframe *> m_selectedKeyframes;
QList<RowTimeline *> m_selectedKeyframesMasterRows;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp
index dae3d80a..6854b49b 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp
@@ -98,8 +98,8 @@ RowTree *RowManager::createRowFromBinding(ITimelineItemBinding *binding, RowTree
ITimelineTimebar *timebar = binding->GetTimelineItem()->GetTimebar();
RowTimeline *rowTimeline = newRow->rowTimeline();
rowTimeline->clearBoundChildren();
- rowTimeline->setStartTime(timebar->GetStartTime() * .001);
- rowTimeline->setEndTime(timebar->GetEndTime() * .001);
+ rowTimeline->setStartTime(timebar->GetStartTime());
+ rowTimeline->setEndTime(timebar->GetEndTime());
rowTimeline->setBarColor(timebar->GetTimebarColor());
// create property rows
@@ -113,12 +113,12 @@ RowTree *RowManager::createRowFromBinding(ITimelineItemBinding *binding, RowTree
// add keyframes
for (int j = 0; j < prop_i->GetKeyframeCount(); j++) {
- Qt3DSDMTimelineKeyframe *kf =
- static_cast<Qt3DSDMTimelineKeyframe *>(prop_i->GetKeyframeByIndex(j));
+ Qt3DSDMTimelineKeyframe *kf
+ = static_cast<Qt3DSDMTimelineKeyframe *>(prop_i->GetKeyframeByIndex(j));
- QList<Keyframe *> addedKeyframes =
- m_scene->keyframeManager()->insertKeyframe(propRow->rowTimeline(),
- static_cast<double>(kf->GetTime()) * .001, false);
+ QList<Keyframe *> addedKeyframes
+ = m_scene->keyframeManager()->insertKeyframe(propRow->rowTimeline(),
+ kf->GetTime(), false);
Keyframe *kfUI = addedKeyframes.at(0);
kf->setUI(kfUI);
@@ -151,7 +151,7 @@ RowTree *RowManager::getOrCreatePropertyRow(RowTree *masterRow, const QString &p
{
RowTree *propertyRow = masterRow->getPropertyRow(propType);
if (!propertyRow)
- propertyRow = createRow(OBJTYPE_UNKNOWN, masterRow, 0, propType, index);
+ propertyRow = createRow(OBJTYPE_UNKNOWN, masterRow, {}, propType, index);
propertyRow->updateLock(masterRow->locked());
@@ -270,14 +270,14 @@ void RowManager::clearSelection()
// set updateMaxDuration to false.
void RowManager::updateRulerDuration(bool updateMaxDuration)
{
- double duration = 0;
- double maxDuration = 0; // for setting correct size for the view so scrollbars appear correctly
+ long duration = 0;
+ long maxDuration = 0; // for setting correct size for the view so scrollbars appear correctly
if (m_layoutTree->count() > 1) {
auto rootRow = static_cast<RowTree *>(m_layoutTree->itemAt(1)->graphicsItem());
bool isComponent = rootRow->rowType() == OBJTYPE_COMPONENT;
for (int i = 1; i < m_layoutTree->count(); ++i) {
RowTree *row_i = static_cast<RowTree *>(m_layoutTree->itemAt(i)->graphicsItem());
- double dur_i = row_i->rowTimeline()->getEndTime();
+ long dur_i = row_i->rowTimeline()->getEndTime();
if (((isComponent && i != 1) || row_i->rowType() == OBJTYPE_LAYER) && dur_i > duration)
duration = dur_i;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h
index ae5aa2cb..61525718 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h
@@ -36,7 +36,8 @@ namespace TimelineConstants
const int ROW_H_EXPANDED = 120; // property rows height when graph is shown
const int ROW_SPACING = 2;
const int ROW_DEPTH_STEP = 15; // x-distance between 2 consecutive depths
- const int RULER_SEC_W = 30; // width of 1 second section (at scale 1)
+ const double RULER_SEC_W = 30; // width of 1 second section (at scale 1)
+ const double RULER_MILLI_W = RULER_SEC_W / 1000.0; // width of 1 millisecond section at scale 1
const int RULER_SEC_DIV = 10; // second divisions
const int RULER_DIV_H1 = 5; // height of main divisions
const int RULER_DIV_H2 = 3; // height of secondary divisions
@@ -69,7 +70,7 @@ namespace TimelineConstants
const int AUTO_SCROLL_DELTA = 8; // increment in scroll at each time step
const int AUTO_SCROLL_TRIGGER = 500; // time after which auto scroll starts (millis)
const int AUTO_EXPAND_TIME = 500; // auto expand a hovered row (while DnD-ing)
- const double MAX_SLIDE_TIME = 3599.0; // seconds
+ const long MAX_SLIDE_TIME = 3599000; // milliseconds
const int TIMELINE_SCROLL_MAX_DELTA = 25; // Maximum amount of pixels to scroll per frame
const int TIMELINE_SCROLL_DIVISOR = 6; // Divisor for timeline autoscroll distance
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.cpp
index 03764b13..378b20da 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.cpp
@@ -31,11 +31,8 @@
#include "RowManager.h"
#include "RowTree.h"
#include "Bindings/ITimelineItemBinding.h"
-#include "DurationEditDlg.h"
#include "StudioApp.h"
#include "Dialogs.h"
-#include "Core.h"
-#include "Doc.h"
TimelineControl::TimelineControl(TimelineGraphicsScene *scene)
: m_scene(scene)
@@ -54,29 +51,24 @@ void TimelineControl::setRowTimeline(RowTimeline *rowTimeline)
void TimelineControl::showDurationEditDialog()
{
- g_StudioApp.GetDialogs()->asyncDisplayDurationEditDialog(m_startTime * 1000, m_endTime * 1000,
- g_StudioApp.GetCore()->GetDoc(), this);
+ g_StudioApp.GetDialogs()->asyncDisplayDurationEditDialog(m_startTime, m_endTime, this);
}
void TimelineControl::ChangeStartTime(long inTime)
{
- double time = (double)inTime / 1000;
- m_rowTimeline->setStartTime(time);
+ m_rowTimeline->setStartTime(inTime);
}
void TimelineControl::ChangeEndTime(long inTime)
{
- double time = (double)inTime / 1000;
- m_rowTimeline->setEndTime(time);
+ m_rowTimeline->setEndTime(inTime);
m_scene->rowManager()->updateRulerDuration();
}
void TimelineControl::Commit()
{
- long startTime = m_rowTimeline->getStartTime() * 1000;
- m_timebar->ChangeTime(startTime, true);
- long endTime = m_rowTimeline->getEndTime() * 1000;
- m_timebar->ChangeTime(endTime, false);
+ m_timebar->ChangeTime(m_rowTimeline->getStartTime(), true);
+ m_timebar->ChangeTime(m_rowTimeline->getEndTime(), false);
m_timebar->CommitTimeChange();
}
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.h
index 981b6db7..3c348016 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.h
@@ -53,8 +53,8 @@ private:
TimelineGraphicsScene *m_scene = nullptr;
RowTimeline *m_rowTimeline = nullptr;
ITimelineTimebar *m_timebar = nullptr;
- double m_startTime = 0;
- double m_endTime = 0;
+ long m_startTime = 0;
+ long m_endTime = 0;
};
#endif // TIMELINECONTROL_H
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp
index e8c6730a..67e1c897 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp
@@ -50,7 +50,7 @@
#include "RowTreeContextMenu.h"
#include "RowTimelineContextMenu.h"
#include "StudioPreferences.h"
-#include "TimeEditDlg.h"
+#include "TimeEnums.h"
#include "StudioClipboard.h"
#include "Dialogs.h"
#include "Qt3DSDMStudioSystem.h"
@@ -80,16 +80,15 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget)
, m_layoutTimeline(new QGraphicsLinearLayout(Qt::Vertical))
, m_ruler(new Ruler)
, m_playHead(new PlayHead(m_ruler))
- , m_selectionRect(new SelectionRect())
- , m_rowMover(new RowMover(this))
, m_widgetTimeline(timelineWidget)
, m_widgetRoot(new QGraphicsWidget)
+ , m_rowMover(new RowMover(this))
+ , m_selectionRect(new SelectionRect())
, m_rowManager(new RowManager(this, m_layoutTree, m_layoutTimeline))
, m_keyframeManager(new KeyframeManager(this))
, m_pressPos(invalidPoint)
, m_pressScreenPos(invalidPoint)
, m_timelineControl(new TimelineControl(this))
- , m_currentCursor(-1)
{
addItem(m_playHead);
addItem(m_selectionRect);
@@ -164,8 +163,7 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget)
}
if (m_selectionRect->isActive()) {
- p -= QPoint(0, m_widgetTimeline->navigationBar()->height()
- + TimelineConstants::ROW_H);
+ p -= QPoint(0, m_widgetTimeline->navigationBar()->height() + TimelineConstants::ROW_H);
const double bottom = timelineContent->contentsRect().height() - scrollBarOffsets.y();
if (m_lastAutoScrollX != p.x() || p.x() <= 0 || p.x() >= right
|| m_lastAutoScrollY != p.y() || p.y() <= 0 || p.y() >= bottom) {
@@ -200,7 +198,7 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget)
if (scroll != 0)
scroll -= TimelineConstants::TREE_BOUND_W;
- double distance = p.x() + scroll;
+ double distance = p.x() + scroll - TimelineConstants::RULER_EDGE_OFFSET;
if (m_clickedTimelineControlType == TimelineControlType::Duration
&& !m_editedTimelineRow.isNull()) {
distance -= m_editedTimelineRow->getDurationMoveOffsetX();
@@ -210,8 +208,7 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget)
snap(distance, !m_rulerPressed);
if (m_rulerPressed) {
- long time = m_ruler->distanceToTime(
- distance - TimelineConstants::RULER_EDGE_OFFSET) * 1000;
+ long time = m_ruler->distanceToTime(distance);
if (time < 0)
time = 0;
g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(time);
@@ -223,22 +220,21 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget)
if (m_dragging) {
if (m_clickedTimelineControlType == TimelineControlType::StartHandle) {
- double visiblePtX = distance > TimelineConstants::RULER_EDGE_OFFSET
- ? m_editedTimelineRow->getStartX() : 0;
+ double visiblePtX = distance > 0 ? m_editedTimelineRow->getStartX() : 0;
if (distance > m_editedTimelineRow->getEndX())
visiblePtX += TimelineConstants::RULER_EDGE_OFFSET;
m_editedTimelineRow->setStartX(distance);
m_editedTimelineRow->showToolTip(QCursor::pos());
- timelineContent->ensureVisible(TimelineConstants::TREE_BOUND_W + visiblePtX,
+ timelineContent->ensureVisible(TimelineConstants::TREE_BOUND_W
+ + TimelineConstants::RULER_EDGE_OFFSET
+ + visiblePtX,
m_editedTimelineRow->y(), 0, 0, 0, 0);
} else if (m_clickedTimelineControlType == TimelineControlType::EndHandle) {
- double time = m_ruler->distanceToTime(
- distance - TimelineConstants::RULER_EDGE_OFFSET);
+ long time = m_ruler->distanceToTime(distance);
double edgeMargin = 0;
if (time > TimelineConstants::MAX_SLIDE_TIME) {
- distance = m_ruler->timeToDistance(TimelineConstants::MAX_SLIDE_TIME)
- + TimelineConstants::RULER_EDGE_OFFSET;
+ distance = m_ruler->timeToDistance(TimelineConstants::MAX_SLIDE_TIME);
edgeMargin = TimelineConstants::RULER_EDGE_OFFSET;
} else if (time < m_editedTimelineRow->getStartTime()) {
edgeMargin = -TimelineConstants::RULER_EDGE_OFFSET;
@@ -248,27 +244,27 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget)
rowManager()->updateRulerDuration(p.x() > right);
timelineContent->ensureVisible(
TimelineConstants::TREE_BOUND_W
+ + TimelineConstants::RULER_EDGE_OFFSET
+ m_editedTimelineRow->getEndX() + edgeMargin,
m_editedTimelineRow->y(), 0, 0, 0, 0);
} else if (m_clickedTimelineControlType == TimelineControlType::Duration) {
- double time = m_ruler->distanceToTime(
- distance - TimelineConstants::RULER_EDGE_OFFSET)
- + m_editedTimelineRow->getDuration(); // seconds
+ long time = m_ruler->distanceToTime(distance)
+ + m_editedTimelineRow->getDuration(); // milliseconds
double visiblePtX = distance
- + m_editedTimelineRow->getDurationMoveOffsetX();
+ + m_editedTimelineRow->getDurationMoveOffsetX();
if (time > TimelineConstants::MAX_SLIDE_TIME) {
distance = m_ruler->timeToDistance(TimelineConstants::MAX_SLIDE_TIME
- - m_editedTimelineRow->getDuration())
- + TimelineConstants::RULER_EDGE_OFFSET;
+ - m_editedTimelineRow->getDuration());
visiblePtX = m_editedTimelineRow->getEndX()
- + TimelineConstants::RULER_EDGE_OFFSET;
+ + TimelineConstants::RULER_EDGE_OFFSET;
}
m_editedTimelineRow->moveDurationTo(distance);
m_editedTimelineRow->showToolTip(QCursor::pos());
rowManager()->updateRulerDuration(p.x() > right);
timelineContent->ensureVisible(
- TimelineConstants::TREE_BOUND_W + visiblePtX,
+ TimelineConstants::TREE_BOUND_W
+ + TimelineConstants::RULER_EDGE_OFFSET + visiblePtX,
m_editedTimelineRow->y(), 0, 0, 0, 0);
}
}
@@ -365,8 +361,8 @@ void TimelineGraphicsScene::setControllerText(const QString &controller)
void TimelineGraphicsScene::updateTimelineLayoutWidth()
{
double timelineWidth = TimelineConstants::RULER_EDGE_OFFSET * 2
- + m_ruler->maxDuration() * TimelineConstants::RULER_SEC_W
- * m_ruler->timelineScale();
+ + m_ruler->maxDuration() * TimelineConstants::RULER_MILLI_W
+ * m_ruler->timelineScale();
m_layoutTimeline->setMinimumWidth(timelineWidth);
m_layoutTimeline->setMaximumWidth(timelineWidth);
@@ -547,12 +543,12 @@ void TimelineGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
m_pressPosInKeyframe = (m_pressPos.x() - m_ruler->x())
- (TimelineConstants::RULER_EDGE_OFFSET
+ m_ruler->timeToDistance(keyframe->time));
- m_keyframePressed = true;
+ m_pressedKeyframe = keyframe;
}
} else {
m_keyframeManager->deselectAllKeyframes();
- m_clickedTimelineControlType =
- m_editedTimelineRow->getClickedControl(m_pressPos);
+ m_clickedTimelineControlType
+ = m_editedTimelineRow->getClickedControl(m_pressPos);
// clicked an empty spot on a timeline row, start selection rect.
if (m_clickedTimelineControlType == TimelineControlType::None) {
@@ -560,7 +556,7 @@ void TimelineGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
} else if (m_clickedTimelineControlType == TimelineControlType::Duration) {
if (!ctrlKeyDown
&& m_rowManager->isRowSelected(m_editedTimelineRow->rowTree())
- && !m_rowManager->isSingleSelected() ) {
+ && !m_rowManager->isSingleSelected()) {
m_releaseSelectRow = m_editedTimelineRow->rowTree();
}
@@ -631,16 +627,16 @@ void TimelineGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
m_rowMover->updateTargetRow(event->scenePos());
updateAutoScrolling(event->scenePos().y());
}
- } else if (m_keyframePressed) { // moving selected keyframes
- double newX = event->scenePos().x() - m_ruler->x() - m_pressPosInKeyframe;
+ } else if (m_pressedKeyframe) { // moving selected keyframes
+ double newX = event->scenePos().x() - m_ruler->x()
+ - TimelineConstants::RULER_EDGE_OFFSET - m_pressPosInKeyframe;
- if (newX < TimelineConstants::RULER_EDGE_OFFSET)
- newX = TimelineConstants::RULER_EDGE_OFFSET;
+ if (newX < 0)
+ newX = 0;
if (shift)
snap(newX);
- newX += m_ruler->x() + m_pressPosInKeyframe;
- double dx = newX - m_pressPos.x();
- m_keyframeManager->moveSelectedKeyframes(dx);
+
+ m_keyframeManager->moveSelectedKeyframes(ruler()->distanceToTime(newX));
m_pressPos.setX(newX);
}
@@ -690,23 +686,23 @@ void TimelineGraphicsScene::stopAutoScroll() {
void TimelineGraphicsScene::updateSnapSteps()
{
m_snapSteps.clear();
- // i = 1 is always the scene row
+ // i = 1 is always the scene row (or component root)
for (int i = 2; i < m_layoutTimeline->count(); i++) {
- RowTree *rowTree = static_cast<RowTree *>
- (m_layoutTree->itemAt(i)->graphicsItem());
+ RowTree *rowTree = static_cast<RowTree *>(m_layoutTree->itemAt(i)->graphicsItem());
if (rowTree->hasDurationBar() && rowTree->isVisible()) {
- if (!m_snapSteps.contains(rowTree->rowTimeline()->getStartX()))
- m_snapSteps.push_back(rowTree->rowTimeline()->getStartX());
+ double startX = rowTree->rowTimeline()->getStartX();
+ if (!m_snapSteps.contains(startX))
+ m_snapSteps.push_back(startX);
- if (!m_snapSteps.contains(rowTree->rowTimeline()->getEndX()))
- m_snapSteps.push_back(rowTree->rowTimeline()->getEndX());
+ double endX = rowTree->rowTimeline()->getEndX();
+ if (!m_snapSteps.contains(endX))
+ m_snapSteps.push_back(endX);
// add keyframes times
if (rowTree->hasPropertyChildren()) {
const QList<Keyframe *> keyframes = rowTree->rowTimeline()->keyframes();
for (Keyframe *k : keyframes) {
- double kX = m_ruler->timeToDistance(k->time)
- + TimelineConstants::RULER_EDGE_OFFSET;
+ double kX = m_ruler->timeToDistance(k->time);
if (!m_snapSteps.contains(kX))
m_snapSteps.push_back(kX);
}
@@ -730,7 +726,7 @@ void TimelineGraphicsScene::resetMousePressParams()
m_timelinePanning = false;
m_startRowMoverOnNextDrag = false;
m_rulerPressed = false;
- m_keyframePressed = false;
+ m_pressedKeyframe = nullptr;
m_clickedTimelineControlType = TimelineControlType::None;
m_editedTimelineRow.clear();
m_releaseSelectRow.clear();
@@ -743,6 +739,11 @@ void TimelineGraphicsScene::resetMousePressParams()
m_lastAutoScrollY = -1.0;
}
+void TimelineGraphicsScene::resetPressedKeyframe()
+{
+ m_pressedKeyframe = nullptr;
+}
+
QLabel *TimelineGraphicsScene::timebarTooltip()
{
return m_timebarToolTip;
@@ -752,7 +753,8 @@ void TimelineGraphicsScene::snap(double &value, bool snapToPlayHead)
{
// snap to play head
if (snapToPlayHead) {
- double playHeadX = m_playHead->x() - m_ruler->x();
+ double playHeadX = m_playHead->x() - TimelineConstants::TREE_BOUND_W
+ - TimelineConstants::RULER_EDGE_OFFSET;
if (abs(value - playHeadX) < CStudioPreferences::GetSnapRange()) {
value = playHeadX;
return;
@@ -775,8 +777,7 @@ void TimelineGraphicsScene::snap(double &value, bool snapToPlayHead)
else if (CStudioPreferences::GetTimelineSnappingGridResolution() == SNAPGRID_TICKMARKS)
snapStep *= .1;
- double snapValue = TimelineConstants::RULER_EDGE_OFFSET
- + round((value - TimelineConstants::RULER_EDGE_OFFSET) / snapStep) * snapStep;
+ double snapValue = round(value / snapStep) * snapStep;
if (abs(value - snapValue) < CStudioPreferences::GetSnapRange())
value = snapValue;
}
@@ -788,37 +789,33 @@ void TimelineGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
if (m_dragging) {
if (m_rowMover->isActive()) { // moving rows (reorder/reparent)
commitMoveRows();
- } else if (m_keyframePressed) {
+ } else if (m_pressedKeyframe) {
// update keyframe movement (time) to binding
m_keyframeManager->commitMoveSelectedKeyframes();
} else if (m_clickedTimelineControlType == TimelineControlType::StartHandle) {
if (!m_editedTimelineRow.isNull()) {
ITimelineTimebar *timebar = m_editedTimelineRow->rowTree()->getBinding()
->GetTimelineItem()->GetTimebar();
- timebar->ChangeTime(m_editedTimelineRow->getStartTime() * 1000, true);
+ timebar->ChangeTime(m_editedTimelineRow->getStartTime(), true);
timebar->CommitTimeChange();
}
} else if (m_clickedTimelineControlType == TimelineControlType::EndHandle) {
if (!m_editedTimelineRow.isNull()) {
ITimelineTimebar *timebar = m_editedTimelineRow->rowTree()->getBinding()
- ->GetTimelineItem()->GetTimebar();
- timebar->ChangeTime(m_editedTimelineRow->getEndTime() * 1000, false);
+ ->GetTimelineItem()->GetTimebar();
+ timebar->ChangeTime(m_editedTimelineRow->getEndTime(), false);
timebar->CommitTimeChange();
- if (m_playHead->time() > ruler()->duration()) {
- g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(ruler()->duration()
- * 1000);
- }
+ if (m_playHead->time() > ruler()->duration())
+ g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(ruler()->duration());
}
} else if (m_clickedTimelineControlType == TimelineControlType::Duration) {
if (!m_editedTimelineRow.isNull()) {
ITimelineTimebar *timebar = m_editedTimelineRow->rowTree()->getBinding()
->GetTimelineItem()->GetTimebar();
- timebar->OffsetTime(m_editedTimelineRow->getDurationMoveTime() * 1000);
+ timebar->OffsetTime(m_editedTimelineRow->getDurationMoveTime());
timebar->CommitTimeChange();
- if (m_playHead->time() > ruler()->duration()) {
- g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(ruler()->duration()
- * 1000);
- }
+ if (m_playHead->time() > ruler()->duration())
+ g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(ruler()->duration());
}
}
} else if (!m_rulerPressed && (!m_releaseSelectRow.isNull() || !itemAt(event->scenePos(),
@@ -849,7 +846,8 @@ void TimelineGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *even
|| itemBelowPlayhead->type() == TimelineItem::TypeRuler) {
CDoc *doc = g_StudioApp.GetCore()->GetDoc();
g_StudioApp.GetDialogs()->asyncDisplayTimeEditDialog(doc->GetCurrentViewTime(),
- doc, PLAYHEAD);
+ doc, PLAYHEAD,
+ m_keyframeManager);
} else {
item = itemBelowPlayhead;
if (item->type() == TimelineItem::TypeRowTree) {
@@ -880,8 +878,9 @@ void TimelineGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *even
RowTimeline *rowTimeline = static_cast<RowTimeline *>(item);
Keyframe *clickedKeyframe = rowTimeline->getClickedKeyframe(scenePos);
if (clickedKeyframe) {
+ m_pressedKeyframe = clickedKeyframe;
g_StudioApp.GetDialogs()->asyncDisplayTimeEditDialog(
- clickedKeyframe->time * 1000, g_StudioApp.GetCore()->GetDoc(),
+ clickedKeyframe->time, g_StudioApp.GetCore()->GetDoc(),
ASSETKEYFRAME, m_keyframeManager);
} else {
if (!rowTimeline->rowTree()->locked())
@@ -980,8 +979,7 @@ void TimelineGraphicsScene::updateHoverStatus(const QPointF &scenePos)
item = getItemBelowType(TimelineItem::TypePlayHead, item, scenePos);
if (item->type() == TimelineItem::TypeRowTimeline) {
RowTimeline *timelineItem = static_cast<RowTimeline *>(item);
- TimelineControlType controlType =
- timelineItem->getClickedControl(scenePos);
+ TimelineControlType controlType = timelineItem->getClickedControl(scenePos);
if (controlType == TimelineControlType::StartHandle
|| controlType == TimelineControlType::EndHandle) {
setMouseCursor(CMouseCursor::CURSOR_RESIZE_LEFTRIGHT);
@@ -1120,3 +1118,4 @@ KeyframeManager *TimelineGraphicsScene::keyframeManager() const { return m
QGraphicsLinearLayout *TimelineGraphicsScene::layoutTree() const { return m_layoutTree; }
QGraphicsLinearLayout *TimelineGraphicsScene::layoutTimeline() const { return m_layoutTimeline; }
TimelineWidget *TimelineGraphicsScene::widgetTimeline() const { return m_widgetTimeline; }
+Keyframe *TimelineGraphicsScene::pressedKeyframe() const { return m_pressedKeyframe; }
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h
index e8eda8f3..8a41ea49 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h
@@ -95,6 +95,8 @@ public:
QPoint getScrollbarOffsets() const;
void handleShowDISelector(const QString &propertyname, qt3dsdm::Qt3DSDMInstanceHandle inInst,
const QPoint &pos);
+ void resetPressedKeyframe();
+ Keyframe *pressedKeyframe() const;
protected:
bool event(QEvent *event) override;
@@ -140,13 +142,13 @@ private:
QPointF m_pressPos;
QPointF m_pressScreenPos;
QList<double> m_snapSteps;
- CMouseCursor::Qt3DSMouseCursor m_currentCursor;
+ CMouseCursor::Qt3DSMouseCursor m_currentCursor = -1;
TimelineControl *m_timelineControl = nullptr;
DataInputSelectView *m_dataInputSelector = nullptr; // triggered by context menu but owned by
// rowtree
bool m_rulerPressed = false;
- bool m_keyframePressed = false;
+ Keyframe *m_pressedKeyframe = nullptr;
bool m_dragging = false;
bool m_startRowMoverOnNextDrag = false;
bool m_timelineZooming = false;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp
index 6240fc34..73f5e155 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp
@@ -52,12 +52,12 @@
#include "Bindings/Qt3DSDMTimelineItemBinding.h"
#include "Bindings/Qt3DSDMTimelineItemProperty.h"
#include "Bindings/TimelineBreadCrumbProvider.h"
-#include "TimeEditDlg.h"
#include "IDocumentEditor.h"
#include "Control.h"
#include "TimelineDropTarget.h"
#include "StudioPreferences.h"
#include "Dialogs.h"
+#include "TimeEnums.h"
#include <QtGui/qevent.h>
#include <QtWidgets/qgraphicslinearlayout.h>
@@ -84,7 +84,7 @@ public:
};
TimelineWidget::TimelineWidget(const QSize &preferredSize, QWidget *parent)
- : QWidget()
+ : QWidget(parent)
, m_toolbar(new TimelineToolbar())
, m_viewTreeHeader(new TreeHeaderView(this))
, m_viewTreeContent(new QGraphicsView(this))
@@ -247,17 +247,18 @@ TimelineWidget::TimelineWidget(const QSize &preferredSize, QWidget *parent)
connect(m_toolbar, &TimelineToolbar::deleteLayerTriggered,
[=](){ doc->DeleteSelectedObject(); });
- connect(m_toolbar, &TimelineToolbar::gotoTimeTriggered, this, [this]() {
+ connect(m_toolbar, &TimelineToolbar::gotoTimeTriggered, this, [=]() {
CDoc *doc = g_StudioApp.GetCore()->GetDoc();
g_StudioApp.GetDialogs()->asyncDisplayTimeEditDialog(doc->GetCurrentViewTime(),
- doc, PLAYHEAD);
+ doc, PLAYHEAD,
+ m_graphicsScene->keyframeManager());
});
- connect(m_toolbar, &TimelineToolbar::firstFrameTriggered, this, [this]() {
+ connect(m_toolbar, &TimelineToolbar::firstFrameTriggered, this, []() {
g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(0);
});
- connect(m_toolbar, &TimelineToolbar::stopTriggered, this, [this]() {
+ connect(m_toolbar, &TimelineToolbar::stopTriggered, this, []() {
g_StudioApp.PlaybackStopNoRestore();
});
@@ -270,7 +271,7 @@ TimelineWidget::TimelineWidget(const QSize &preferredSize, QWidget *parent)
});
connect(m_toolbar, &TimelineToolbar::lastFrameTriggered, this, [this]() {
- double dur = m_graphicsScene->ruler()->duration() * 1000;
+ long dur = m_graphicsScene->ruler()->duration();
g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(dur);
});
@@ -305,15 +306,13 @@ Q3DStudio::CString TimelineWidget::getPlaybackMode()
CDoc *doc = g_StudioApp.GetCore()->GetDoc();
qt3dsdm::Qt3DSDMSlideHandle theActiveSlide(doc->GetActiveSlide());
// clock has passed the end, check whether needs to switch slide
- qt3dsdm::Qt3DSDMInstanceHandle theInstanceHandle = doc->GetStudioSystem()->GetSlideSystem()
- ->GetSlideInstance(theActiveSlide);
+ qt3dsdm::Qt3DSDMInstanceHandle instance = doc->GetStudioSystem()->GetSlideSystem()
+ ->GetSlideInstance(theActiveSlide);
- CClientDataModelBridge *clientDataModelBridge = doc->GetStudioSystem()
- ->GetClientDataModelBridge();
+ CClientDataModelBridge *bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
qt3dsdm::IPropertySystem *propertySystem = doc->GetStudioSystem()->GetPropertySystem();
qt3dsdm::SValue theValue;
- propertySystem->GetInstancePropertyValue(theInstanceHandle, clientDataModelBridge->GetSlide()
- .m_PlayMode, theValue);
+ propertySystem->GetInstancePropertyValue(instance, bridge->GetSlide().m_PlayMode, theValue);
return qt3dsdm::get<qt3dsdm::TDataStrPtr>(theValue)->GetData();
}
@@ -377,7 +376,7 @@ void TimelineWidget::OnNewPresentation()
std::placeholders::_1, std::placeholders::_2)));
m_connections.push_back(theSignalProvider->ConnectFirstKeyframeDynamicSet(
std::bind(&TimelineWidget::onFirstKeyframeDynamicSet, this,
- std::placeholders::_1, std::placeholders::_2)));
+ std::placeholders::_1)));
// action created/deleted
m_connections.push_back(theSignalProvider->ConnectActionCreated(
@@ -426,7 +425,7 @@ void TimelineWidget::OnClosingPresentation()
void TimelineWidget::OnTimeChanged(long inTime)
{
- m_graphicsScene->playHead()->setTime(inTime * .001);
+ m_graphicsScene->playHead()->setTime(inTime);
m_toolbar->setTime(inTime);
double left = m_viewTimelineHeader->horizontalScrollBar()->value()
@@ -474,6 +473,7 @@ void TimelineWidget::insertToHandlesMapRecursive(Qt3DSDMTimelineItemBinding *bin
return;
insertToHandlesMap(binding);
+
const QList<ITimelineItemBinding *> children = binding->GetChildren();
for (auto child : children)
insertToHandlesMapRecursive(static_cast<Qt3DSDMTimelineItemBinding *>(child));
@@ -596,8 +596,7 @@ void TimelineWidget::onAnimationCreated(qt3dsdm::Qt3DSDMInstanceHandle parentIns
for (int i = 0; i < propBinding->GetKeyframeCount(); i++) {
IKeyframe *kf = propBinding->GetKeyframeByIndex(i);
Keyframe *kfUI = m_graphicsScene->keyframeManager()->insertKeyframe(
- propRow->rowTimeline(), static_cast<double>(kf->GetTime()) * .001, false)
- .at(0);
+ propRow->rowTimeline(), kf->GetTime(), false).at(0);
kf->setUI(kfUI);
kfUI->binding = static_cast<Qt3DSDMTimelineKeyframe *>(kf);
@@ -685,10 +684,8 @@ void TimelineWidget::refreshKeyframe(qt3dsdm::Qt3DSDMAnimationHandle inAnimation
}
}
-void TimelineWidget::onFirstKeyframeDynamicSet(qt3dsdm::Qt3DSDMAnimationHandle inAnimation,
- bool inDynamic)
+void TimelineWidget::onFirstKeyframeDynamicSet(qt3dsdm::Qt3DSDMAnimationHandle inAnimation)
{
- Q_UNUSED(inDynamic)
refreshKeyframe(inAnimation, 0, ETimelineKeyframeTransaction_DynamicChanged);
}
@@ -755,6 +752,28 @@ void TimelineWidget::onPropertyChanged(qt3dsdm::Qt3DSDMInstanceHandle inInstance
m_subpresentationChanges.insert(inInstance);
if (!m_asyncUpdateTimer.isActive())
m_asyncUpdateTimer.start();
+ } else if (inProperty == m_bridge->GetLayer().m_variants) {
+ qt3dsdm::SValue sValue;
+ if (doc->GetPropertySystem()->GetInstancePropertyValue(inInstance, inProperty, sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ if (!propVal.isEmpty()) {
+ QStringList tagPairs = propVal.split(QLatin1Char(','));
+ QStringList groups;
+ for (int i = 0; i < tagPairs.size(); ++i) {
+ QString group = tagPairs[i].left(tagPairs[i].indexOf(QLatin1Char(':')));
+ if (!groups.contains(group))
+ groups.append(group);
+ }
+
+ m_variantsMap[inInstance] = groups;
+ } else {
+ m_variantsMap[inInstance].clear();
+ }
+
+ if (!m_asyncUpdateTimer.isActive())
+ m_asyncUpdateTimer.start();
+ }
}
}
@@ -778,11 +797,11 @@ void TimelineWidget::onAsyncUpdate()
m_graphicsScene->updateController();
onSelectionChange(doc->GetSelectedValue());
m_toolbar->setNewLayerEnabled(!m_graphicsScene->rowManager()->isComponentRoot());
+ refreshVariants();
- // update suppresentation indicators
- for (auto *row : m_handlesMap)
+ // update sub-presentation indicators
+ for (auto *row : qAsConst(m_handlesMap))
row->updateSubpresentations();
-
} else {
if (!m_moveMap.isEmpty()) {
// Flip the hash around so that we collect moves by parent.
@@ -926,10 +945,22 @@ void TimelineWidget::onAsyncUpdate()
}
m_graphicsScene->updateSnapSteps();
}
+
+ if (!m_variantsMap.isEmpty()) {
+ const auto instances = m_variantsMap.keys();
+ for (int instance : instances) {
+ if (m_handlesMap.contains(instance)) {
+ RowTree *row = m_handlesMap[instance];
+ if (row)
+ row->updateVariants(m_variantsMap[instance]); // variants groups names
+ }
+ }
+ }
}
m_dirtyProperties.clear();
m_moveMap.clear();
m_actionChanges.clear();
+ m_variantsMap.clear();
m_subpresentationChanges.clear();
m_keyframeChangesMap.clear();
m_graphicsScene->rowManager()->finalizeRowDeletions();
@@ -977,8 +1008,7 @@ void TimelineWidget::onPropertyLinked(qt3dsdm::Qt3DSDMInstanceHandle inInstance,
for (int i = 0; i < propBinding->GetKeyframeCount(); i++) {
IKeyframe *kf = propBinding->GetKeyframeByIndex(i);
Keyframe *kfUI = m_graphicsScene->keyframeManager()->insertKeyframe(
- propRow->rowTimeline(), static_cast<double>(kf->GetTime()) * .001,
- false).at(0);
+ propRow->rowTimeline(), kf->GetTime(), false).at(0);
kf->setUI(kfUI);
kfUI->binding = static_cast<Qt3DSDMTimelineKeyframe *>(kf);
@@ -1030,21 +1060,6 @@ void TimelineWidget::onChildMoved(int inParent, int inChild, long inOldIndex,
onChildAdded(inParent, inChild, inNewIndex);
}
-void TimelineWidget::OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation)
-{
-
-}
-
-void TimelineWidget::Draw(CRenderer *inRenderer)
-{
-
-}
-
-void TimelineWidget::OnGainFocus()
-{
-
-}
-
CDropTarget *TimelineWidget::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags,
EStudioObjectType objectType,
Q3DStudio::DocumentEditorFileType::Enum fileType)
@@ -1079,12 +1094,6 @@ CDropTarget *TimelineWidget::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardMo
return theTarget;
}
-bool TimelineWidget::OnMouseHover(CPt inPoint, Qt::KeyboardModifiers inFlags)
-{
- return true;
-}
-
-
void TimelineWidget::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
{
Q_UNUSED(inFlags)
@@ -1103,14 +1112,6 @@ bool TimelineWidget::blockMousePress() const
return m_blockMousePress;
}
-void TimelineWidget::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags)
-{
-}
-
-void TimelineWidget::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
-{
-}
-
CPt TimelineWidget::GetPreferredSize()
{
return CPt(m_preferredSize.width(), m_preferredSize.height());
@@ -1150,7 +1151,7 @@ Qt3DSDMTimelineItemBinding *TimelineWidget::getBindingForHandle(int handle,
const QList<ITimelineItemBinding *> children = binding->GetChildren();
for (auto child : children) {
Qt3DSDMTimelineItemBinding *b = getBindingForHandle(handle,
- static_cast<Qt3DSDMTimelineItemBinding *>(child));
+ static_cast<Qt3DSDMTimelineItemBinding *>(child));
if (b)
return b;
@@ -1174,6 +1175,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event)
void TimelineWidget::mouseReleaseEvent(QMouseEvent *event)
{
+ Q_UNUSED(event)
m_splitterPressed = false;
}
@@ -1232,8 +1234,8 @@ void TimelineWidget::onTimeBarColorChanged(const QColor &color)
void TimelineWidget::setSelectedTimeBarsColor(const QColor &color, bool preview)
{
using namespace Q3DStudio; // Needed for SCOPED_DOCUMENT_EDITOR macro
- auto rows = selectedRows();
- for (RowTree *row : qAsConst(rows)) {
+ const auto rows = selectedRows();
+ for (RowTree *row : rows) {
row->rowTimeline()->setBarColor(color);
if (!preview) {
Qt3DSDMTimelineItemBinding *timelineItemBinding =
@@ -1244,3 +1246,33 @@ void TimelineWidget::setSelectedTimeBarsColor(const QColor &color, bool preview)
}
}
}
+
+void TimelineWidget::refreshVariants()
+{
+ const auto propertySystem = g_StudioApp.GetCore()->GetDoc()->GetPropertySystem();
+ const auto layers = g_StudioApp.GetCore()->GetDoc()->getLayers();
+ for (auto layer : layers) {
+ if (!m_handlesMap.contains(layer))
+ continue;
+
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(layer, m_bridge->GetLayer().m_variants,
+ sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ if (!propVal.isEmpty()) {
+ QStringList tagPairs = propVal.split(QLatin1Char(','));
+ QStringList groups;
+ for (int i = 0; i < tagPairs.size(); ++i) {
+ QString group = tagPairs[i].left(tagPairs[i].indexOf(QLatin1Char(':')));
+ if (!groups.contains(group))
+ groups.append(group);
+ }
+
+ m_handlesMap[layer]->updateVariants(groups);
+ } else {
+ m_handlesMap[layer]->updateVariants({});
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h
index 26c9a66b..ac01367a 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h
@@ -73,6 +73,7 @@ public:
void openBarColorDialog();
void onTimeBarColorChanged(const QColor &color);
void setSelectedTimeBarsColor(const QColor &color, bool preview);
+ void refreshVariants();
void enableDnD(bool b = true);
bool dndActive() const;
bool blockMousePress() const;
@@ -87,16 +88,10 @@ public:
bool hasSelectedKeyframes() const;
// CControl
- void OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation = false) override;
- void Draw(CRenderer *inRenderer) override;
- void OnGainFocus() override;
CDropTarget *FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags,
EStudioObjectType objectType,
Q3DStudio::DocumentEditorFileType::Enum fileType) override;
- bool OnMouseHover(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
- void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
- void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
CPt GetPreferredSize() override;
void SetSize(long inX, long inY) override;
bool isFullReconstructPending() const { return m_fullReconstruct; }
@@ -115,7 +110,7 @@ protected:
void onKeyframeDeleted(qt3dsdm::Qt3DSDMAnimationHandle inAnimation,
qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe);
void onKeyframeUpdated(qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe);
- void onFirstKeyframeDynamicSet(qt3dsdm::Qt3DSDMAnimationHandle inAnimation, bool inDynamic);
+ void onFirstKeyframeDynamicSet(qt3dsdm::Qt3DSDMAnimationHandle inAnimation);
void onAnimationDeleted(qt3dsdm::Qt3DSDMInstanceHandle parentInstance,
qt3dsdm::Qt3DSDMPropertyHandle property);
void onActionEvent(qt3dsdm::Qt3DSDMActionHandle inAction, qt3dsdm::Qt3DSDMSlideHandle inSlide,
@@ -164,6 +159,7 @@ private:
QSize m_preferredSize;
QMultiHash<qt3dsdm::Qt3DSDMInstanceHandle, qt3dsdm::Qt3DSDMPropertyHandle> m_dirtyProperties;
QHash<int, int> m_moveMap; // key: child handle, value: parent handle
+ QHash<int, QStringList> m_variantsMap; // key: obj handle, value: variant groups
QSet<int> m_actionChanges; // key: object handle
QSet<int> m_subpresentationChanges; // key: object handle
QMultiHash<int, int> m_keyframeChangesMap; // key: object handle, value: property handle
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp
index 35787462..3ddfdcad 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp
@@ -30,9 +30,11 @@
#include "Ruler.h"
#include "TimelineConstants.h"
#include "StudioPreferences.h"
+#include "StudioUtils.h"
#include <QtGui/qpainter.h>
#include <QtGui/qcursor.h>
+#include <QtWidgets/qwidget.h>
PlayHead::PlayHead(Ruler *ruler)
: QGraphicsRectItem()
@@ -47,24 +49,22 @@ void PlayHead::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
Q_UNUSED(option)
Q_UNUSED(widget)
+ bool hiResIcons = StudioUtils::devicePixelRatio(widget->window()->windowHandle()) > 1.0;
static const QPixmap pixHead = QPixmap(":/images/PlaybackHead.png");
+ static const QPixmap pixHead2x = QPixmap(":/images/PlaybackHead@2x.png");
static const int PLAY_HEAD_H = 999999; // theoretically big enough height
- painter->drawPixmap(-TimelineConstants::PLAYHEAD_W * .5, 0, pixHead);
+ painter->drawPixmap(-TimelineConstants::PLAYHEAD_W * .5, 0, hiResIcons ? pixHead2x : pixHead);
painter->setPen(CStudioPreferences::timelinePlayheadLineColor());
painter->drawLine(0, 0, 0, PLAY_HEAD_H);
}
void PlayHead::setHeight(int height)
{
- setRect(
- rect().x(),
- rect().y(),
- rect().width(),
- height);
+ setRect(rect().x(), rect().y(), rect().width(), height);
}
-void PlayHead::setTime(double time)
+void PlayHead::setTime(long time)
{
if (time < 0)
time = 0;
@@ -78,21 +78,21 @@ void PlayHead::setTime(double time)
void PlayHead::setPosition(double posX)
{
posX = qBound(TimelineConstants::RULER_EDGE_OFFSET, posX, m_ruler->duration()
- * TimelineConstants::RULER_SEC_W * m_ruler->timelineScale()
+ * TimelineConstants::RULER_MILLI_W * m_ruler->timelineScale()
+ TimelineConstants::RULER_EDGE_OFFSET);
setX(m_ruler->x() + posX);
m_time = (posX - TimelineConstants::RULER_EDGE_OFFSET)
- / (TimelineConstants::RULER_SEC_W * m_ruler->timelineScale());
+ / (TimelineConstants::RULER_MILLI_W * m_ruler->timelineScale());
}
void PlayHead::updatePosition()
{
setX(m_ruler->x() + TimelineConstants::RULER_EDGE_OFFSET
- + m_time * TimelineConstants::RULER_SEC_W * m_ruler->timelineScale());
+ + m_time * TimelineConstants::RULER_MILLI_W * m_ruler->timelineScale());
}
-double PlayHead::time() const
+long PlayHead::time() const
{
return m_time;
}
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.h
index ef628f51..395e6317 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.h
@@ -44,14 +44,14 @@ public:
void setHeight(int height);
void setPosition(double posX); // set x poisiotn
void updatePosition(); // sync x poisiotn based on time value
- void setTime(double time); // set time (sets x based on time input)
+ void setTime(long time); // set time (sets x based on time (ms) input)
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget = nullptr) override;
- double time() const;
- int type() const;
+ long time() const;
+ int type() const override;
private:
- double m_time = 0;
+ long m_time = 0;
Ruler *m_ruler;
};
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp
index 196cedde..a0b689f4 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp
@@ -41,6 +41,7 @@
#include "AppFonts.h"
#include "StudioPreferences.h"
#include "TimelineToolbar.h"
+#include "StudioUtils.h"
#include <QtGui/qpainter.h>
#include <QtGui/qbrush.h>
@@ -101,6 +102,8 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
{
Q_UNUSED(option)
+ bool hiResIcons = StudioUtils::devicePixelRatio(widget->window()->windowHandle()) > 1.0;
+
if (!y()) // prevents flickering when the row is just inserted to the layout
return;
@@ -122,6 +125,8 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
painter->fillRect(0, 0, size().width(), currentHeight, bgColor);
}
+ const double edgeOffset = TimelineConstants::RULER_EDGE_OFFSET;
+
// Duration. Draw duration bar (for scene/component root) also if it has
// datainput controller
if (m_rowTree->hasDurationBar() || m_controllerDataInput.size()) {
@@ -132,17 +137,17 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
painter->setBrush(QBrush(CStudioPreferences::timelineRowColorDurationOff1(),
Qt::BDiagPattern));
painter->setPen(Qt::NoPen);
- painter->fillRect(QRect(m_startX, 0, m_endX - m_startX, currentHeight),
+ painter->fillRect(QRect(edgeOffset + m_startX, 0, m_endX - m_startX, currentHeight),
CStudioPreferences::timelineRowColorDurationOff2());
- painter->drawRect(QRect(m_startX, 0, m_endX - m_startX, currentHeight));
+ painter->drawRect(QRect(edgeOffset + m_startX, 0, m_endX - m_startX, currentHeight));
painter->setPen(QPen(CStudioPreferences::timelineRowColorDurationEdge(), 2));
- painter->drawLine(m_startX, 0, m_startX, currentHeight);
- painter->drawLine(m_endX, 0, m_endX, currentHeight);
+ painter->drawLine(edgeOffset + m_startX, 0, edgeOffset + m_startX, currentHeight);
+ painter->drawLine(edgeOffset + m_endX, 0, edgeOffset + m_endX, currentHeight);
} else {
// draw main duration part
- double x = qMax(m_startX, m_minStartX);
- double w = qMin(m_endX, m_maxEndX) - x;
+ double x = edgeOffset + qMax(m_startX, m_minStartX);
+ double w = edgeOffset + qMin(m_endX, m_maxEndX) - x;
static const int marginY = 3;
painter->setPen(Qt::NoPen);
@@ -161,8 +166,9 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
}
if (m_controllerDataInput.size()) {
- static const QPixmap pixDataInput
- = QPixmap(":/images/Objects-DataInput-White.png");
+ static const QPixmap pixDataInput = QPixmap(":/images/Objects-DataInput-White.png");
+ static const QPixmap pixDataInput2x
+ = QPixmap(":/images/Objects-DataInput-White@2x.png");
static const QFontMetrics fm(painter->font());
// need clip region to limit datainput icon visibility to the same rect as we use
@@ -178,8 +184,7 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
int iconx = x + (w - textwidth) / 2;
if (iconx < x)
iconx = x;
- painter->drawPixmap(iconx, marginY, pixDataInput.width(), pixDataInput.height(),
- pixDataInput);
+ painter->drawPixmap(iconx, marginY, hiResIcons ? pixDataInput2x : pixDataInput);
painter->setPen(Qt::NoPen);
painter->setClipping(false);
}
@@ -189,37 +194,40 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
Qt::BDiagPattern));
if (m_startX < m_minStartX) {
painter->setPen(Qt::NoPen);
- painter->fillRect(QRect(m_startX, 0, m_minStartX - m_startX, currentHeight),
+ painter->fillRect(QRect(edgeOffset + m_startX, 0, m_minStartX - m_startX,
+ currentHeight),
CStudioPreferences::timelineRowColorDurationOff2());
- painter->drawRect(QRect(m_startX, 0, m_minStartX - m_startX, currentHeight));
+ painter->drawRect(QRect(edgeOffset + m_startX, 0, m_minStartX - m_startX,
+ currentHeight));
painter->setPen(CStudioPreferences::timelineRowColorDurationEdge());
- painter->drawLine(m_minStartX, 0, m_minStartX, currentHeight);
+ painter->drawLine(edgeOffset + m_minStartX, 0, edgeOffset + m_minStartX,
+ currentHeight);
}
// draw hashed part after
if (m_endX > m_maxEndX) {
painter->setPen(Qt::NoPen);
- painter->fillRect(QRect(m_maxEndX, 0, m_endX - m_maxEndX, currentHeight),
+ painter->fillRect(QRect(edgeOffset + m_maxEndX, 0, m_endX - m_maxEndX,
+ currentHeight),
CStudioPreferences::timelineRowColorDurationOff2());
- painter->drawRect(QRect(m_maxEndX, 0, m_endX - m_maxEndX, currentHeight));
+ painter->drawRect(QRect(edgeOffset + m_maxEndX, 0, m_endX - m_maxEndX,
+ currentHeight));
painter->setPen(CStudioPreferences::timelineRowColorDurationEdge());
- painter->drawLine(m_maxEndX, 0, m_maxEndX, currentHeight);
+ painter->drawLine(edgeOffset + m_maxEndX, 0, edgeOffset + m_maxEndX, currentHeight);
}
if (m_rowTree->indexInLayout() != 1) {
painter->setPen(QPen(CStudioPreferences::timelineRowColorDurationEdge(), 2));
- painter->drawLine(m_startX, 0, m_startX, currentHeight);
- painter->drawLine(m_endX, 0, m_endX, currentHeight);
+ painter->drawLine(edgeOffset + m_startX, 0, edgeOffset + m_startX, currentHeight);
+ painter->drawLine(edgeOffset + m_endX, 0, edgeOffset + m_endX, currentHeight);
}
}
painter->restore();
}
- if (m_propertyGraph) {
- // Property graph
- QRectF graphRect(TimelineConstants::RULER_EDGE_OFFSET, 0,
- widget->width(), currentHeight);
+ if (m_propertyGraph) { // Property graph
+ QRectF graphRect(edgeOffset, 0, widget->width(), currentHeight);
m_propertyGraph->paintGraphs(painter, graphRect);
}
@@ -228,23 +236,28 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
const qreal keyFrameHalfH = keyFrameH / 2.0;
const qreal keyFrameY = (qMin(currentHeight, TimelineConstants::ROW_H) / 2.0) - keyFrameHalfH;
const qreal hiddenKeyFrameY = keyFrameY + (keyFrameH * 2.0 / 3.0) + 2.0;
+ const qreal keyFrameOffset = hiResIcons ? 8 : 7.5;
// Hidden descendant keyframe indicators
if (!m_rowTree->expanded()) {
static const QPixmap pixKeyframeHidden = QPixmap(":/images/keyframe-hidden-normal.png");
- QVector<double> childKeyframeTimes;
+ static const QPixmap pixKeyframeHidden2x
+ = QPixmap(":/images/keyframe-hidden-normal@2x.png");
+ QVector<long> childKeyframeTimes;
collectChildKeyframeTimes(childKeyframeTimes);
const qreal oldOpacity = painter->opacity();
painter->setOpacity(0.75);
for (const auto time : qAsConst(childKeyframeTimes)) {
- const qreal xCoord = timeToX(time) - 2.5;
- painter->drawPixmap(QPointF(xCoord, hiddenKeyFrameY), pixKeyframeHidden);
+ const qreal xCoord = edgeOffset + m_rowTree->m_scene->ruler()->timeToDistance(time)
+ - 2.5;
+ painter->drawPixmap(QPointF(xCoord, hiddenKeyFrameY), hiResIcons ? pixKeyframeHidden2x
+ : pixKeyframeHidden);
}
painter->setOpacity(oldOpacity);
}
- if (m_rowTree->hasPropertyChildren()) { // master keyframes
+ if (m_rowTree->hasPropertyChildren()) { // object row keyframes
static const QPixmap pixKeyframeMasterDisabled
= QPixmap(":/images/Keyframe-Master-Disabled.png");
static const QPixmap pixKeyframeMasterNormal
@@ -257,27 +270,60 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
= QPixmap(":/images/Keyframe-MasterDynamic-Normal.png");
static const QPixmap pixKeyframeMasterDynamicSelected
= QPixmap(":/images/Keyframe-MasterDynamic-Selected.png");
+ static const QPixmap pixKeyframeMasterDisabled2x
+ = QPixmap(":/images/Keyframe-Master-Disabled@2x.png");
+ static const QPixmap pixKeyframeMasterNormal2x
+ = QPixmap(":/images/Keyframe-Master-Normal@2x.png");
+ static const QPixmap pixKeyframeMasterSelected2x
+ = QPixmap(":/images/Keyframe-Master-Selected@2x.png");
+ static const QPixmap pixKeyframeMasterDynamicDisabled2x
+ = QPixmap(":/images/Keyframe-MasterDynamic-Disabled@2x.png");
+ static const QPixmap pixKeyframeMasterDynamicNormal2x
+ = QPixmap(":/images/Keyframe-MasterDynamic-Normal@2x.png");
+ static const QPixmap pixKeyframeMasterDynamicSelected2x
+ = QPixmap(":/images/Keyframe-MasterDynamic-Selected@2x.png");
for (auto keyframe : qAsConst(m_keyframes)) {
QPixmap pixmap;
if (m_rowTree->locked()) {
- if (keyframe->dynamic)
- pixmap = pixKeyframeMasterDynamicDisabled;
- else
- pixmap = pixKeyframeMasterDisabled;
+ if (keyframe->dynamic) {
+ pixmap = hiResIcons ? pixKeyframeMasterDynamicDisabled2x
+ : pixKeyframeMasterDynamicDisabled;
+ } else {
+ pixmap = hiResIcons ? pixKeyframeMasterDisabled2x
+ : pixKeyframeMasterDisabled;
+ }
} else if (keyframe->selected()) {
- if (keyframe->dynamic)
- pixmap = pixKeyframeMasterDynamicSelected;
- else
- pixmap = pixKeyframeMasterSelected;
+ if (keyframe->dynamic) {
+ pixmap = hiResIcons ? pixKeyframeMasterDynamicSelected2x
+ : pixKeyframeMasterDynamicSelected;
+ } else {
+ pixmap = hiResIcons ? pixKeyframeMasterSelected2x
+ : pixKeyframeMasterSelected;
+ }
} else {
- if (keyframe->dynamic)
- pixmap = pixKeyframeMasterDynamicNormal;
- else
- pixmap = pixKeyframeMasterNormal;
+ if (keyframe->dynamic) {
+ pixmap = hiResIcons ? pixKeyframeMasterDynamicNormal2x
+ : pixKeyframeMasterDynamicNormal;
+ } else {
+ pixmap = hiResIcons ? pixKeyframeMasterNormal2x
+ : pixKeyframeMasterNormal;
+ }
+ }
+ painter->drawPixmap(QPointF(edgeOffset + m_rowTree->m_scene->ruler()
+ ->timeToDistance(keyframe->time) - keyFrameOffset,
+ keyFrameY), pixmap);
+
+ // highlight the pressed keyframe in a multi-selection (the keyframe that is affected
+ // by snapping, and setting time dialog)
+ if (m_rowTree->m_scene->keyframeManager()->selectedKeyframes().size() > 1
+ && m_rowTree->m_scene->pressedKeyframe() == keyframe) {
+ painter->setPen(QPen(CStudioPreferences::timelinePressedKeyframeColor(), 1));
+ painter->drawArc(edgeOffset + m_rowTree->m_scene->ruler()
+ ->timeToDistance(keyframe->time) - 4, keyFrameY + 4, 9, 9, 0,
+ 5760);
}
- painter->drawPixmap(QPointF(timeToX(keyframe->time) - 8.5, keyFrameY), pixmap);
}
- } else if (m_rowTree->isProperty()) {
+ } else if (m_rowTree->isProperty()) { // property row keyframes
static const QPixmap pixKeyframePropertyDisabled
= QPixmap(":/images/Keyframe-Property-Disabled.png");
static const QPixmap pixKeyframePropertyNormal
@@ -290,26 +336,51 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
= QPixmap(":/images/Keyframe-PropertyDynamic-Normal.png");
static const QPixmap pixKeyframePropertyDynamicSelected
= QPixmap(":/images/Keyframe-PropertyDynamic-Selected.png");
+ static const QPixmap pixKeyframePropertyDisabled2x
+ = QPixmap(":/images/Keyframe-Property-Disabled@2x.png");
+ static const QPixmap pixKeyframePropertyNormal2x
+ = QPixmap(":/images/Keyframe-Property-Normal@2x.png");
+ static const QPixmap pixKeyframePropertySelected2x
+ = QPixmap(":/images/Keyframe-Property-Selected@2x.png");
+ static const QPixmap pixKeyframePropertyDynamicDisabled2x
+ = QPixmap(":/images/Keyframe-PropertyDynamic-Disabled@2x.png");
+ static const QPixmap pixKeyframePropertyDynamicNormal2x
+ = QPixmap(":/images/Keyframe-PropertyDynamic-Normal@2x.png");
+ static const QPixmap pixKeyframePropertyDynamicSelected2x
+ = QPixmap(":/images/Keyframe-PropertyDynamic-Selected@2x.png");
for (auto keyframe : qAsConst(m_keyframes)) {
QPixmap pixmap;
if (m_rowTree->locked()) {
- if (keyframe->dynamic)
- pixmap = pixKeyframePropertyDynamicDisabled;
- else
- pixmap = pixKeyframePropertyDisabled;
+ if (keyframe->dynamic) {
+ pixmap = hiResIcons ? pixKeyframePropertyDynamicDisabled2x
+ : pixKeyframePropertyDynamicDisabled;
+
+ } else {
+ pixmap = hiResIcons ? pixKeyframePropertyDisabled2x
+ : pixKeyframePropertyDisabled;
+ }
} else if (keyframe->selected()) {
- if (keyframe->dynamic)
- pixmap = pixKeyframePropertyDynamicSelected;
- else
- pixmap = pixKeyframePropertySelected;
+ if (keyframe->dynamic) {
+ pixmap = hiResIcons ? pixKeyframePropertyDynamicSelected2x
+ : pixKeyframePropertyDynamicSelected;
+
+ } else {
+ pixmap = hiResIcons ? pixKeyframePropertySelected2x
+ : pixKeyframePropertySelected;
+ }
} else {
- if (keyframe->dynamic)
- pixmap = pixKeyframePropertyDynamicNormal;
- else
- pixmap = pixKeyframePropertyNormal;
+ if (keyframe->dynamic) {
+ pixmap = hiResIcons ? pixKeyframePropertyDynamicNormal2x
+ : pixKeyframePropertyDynamicNormal;
+
+ } else {
+ pixmap = hiResIcons ? pixKeyframePropertyNormal2x
+ : pixKeyframePropertyNormal;
+ }
}
- painter->drawPixmap(QPointF(timeToX(keyframe->time) - (keyframe->selected() ? 7.5 : 5.5),
- keyFrameY), pixmap);
+ painter->drawPixmap(QPointF(edgeOffset + m_rowTree->m_scene->ruler()
+ ->timeToDistance(keyframe->time) - keyFrameOffset,
+ keyFrameY), pixmap);
}
}
}
@@ -340,15 +411,14 @@ void RowTimeline::drawColorPropertyGradient(QPainter *painter, int width)
QLinearGradient bgGradient(0, 0, width, 0);
for (auto keyframe : qAsConst(m_keyframes)) {
- double xPos = timeToX(keyframe->time);
+ double xPos = m_rowTree->m_scene->ruler()->timeToDistance(keyframe->time);
double gradPos = xPos / width;
gradPos = qBound(0.0, gradPos, 1.0);
- long timeMs = keyframe->time * 1000;
QColor currentColor;
// Get the color at the specified time.
- currentColor.setRed(propBinding->GetChannelValueAtTime(0, timeMs));
- currentColor.setGreen(propBinding->GetChannelValueAtTime(1, timeMs));
- currentColor.setBlue(propBinding->GetChannelValueAtTime(2, timeMs));
+ currentColor.setRed(propBinding->GetChannelValueAtTime(0, keyframe->time));
+ currentColor.setGreen(propBinding->GetChannelValueAtTime(1, keyframe->time));
+ currentColor.setBlue(propBinding->GetChannelValueAtTime(2, keyframe->time));
bgGradient.setColorAt(gradPos, currentColor);
}
painter->fillRect(TimelineConstants::RULER_EDGE_OFFSET, 0,
@@ -373,7 +443,8 @@ Keyframe *RowTimeline::getClickedKeyframe(const QPointF &scenePos)
}
for (const auto keyframe : qAsConst(keyframes)) {
- x = timeToX(keyframe->time);
+ x = TimelineConstants::RULER_EDGE_OFFSET
+ + m_rowTree->m_scene->ruler()->timeToDistance(keyframe->time);
if (p.x() > x - 5 && p.x() < x + 5 && p.y() > 3 && p.y() < 16)
return keyframe;
@@ -391,7 +462,8 @@ QList<Keyframe *> RowTimeline::getKeyframesInRange(const QRectF &rect) const
static const int KF_CENTER_Y = 10;
for (auto keyframe : qAsConst(m_keyframes)) {
- x = timeToX(keyframe->time);
+ x = TimelineConstants::RULER_EDGE_OFFSET
+ + m_rowTree->m_scene->ruler()->timeToDistance(keyframe->time);
if (localRect.left() < x && localRect.right() > x
&& localRect.top() < KF_CENTER_Y && localRect.bottom() > KF_CENTER_Y) {
@@ -409,8 +481,8 @@ void RowTimeline::updateDurationFromBinding()
ITimelineTimebar *timebar = m_rowTree->m_binding->GetTimelineItem()->GetTimebar();
clearBoundChildren();
- setStartTime(timebar->GetStartTime() * .001);
- setEndTime(timebar->GetEndTime() * .001);
+ setStartTime(timebar->GetStartTime());
+ setEndTime(timebar->GetEndTime());
}
void RowTimeline::updateKeyframesFromBinding(const QList<int> &properties)
@@ -430,8 +502,7 @@ void RowTimeline::updateKeyframesFromBinding(const QList<int> &properties)
Qt3DSDMTimelineKeyframe *kf = static_cast<Qt3DSDMTimelineKeyframe *>
(child->m_PropBinding->GetKeyframeByIndex(i));
- Keyframe *kfUI = new Keyframe(static_cast<double>(kf->GetTime() * .001),
- child->rowTimeline());
+ Keyframe *kfUI = new Keyframe(kf->GetTime(), child->rowTimeline());
kfUI->binding = kf;
kfUI->dynamic = kf->IsDynamic();
kf->setUI(kfUI);
@@ -504,10 +575,12 @@ TimelineControlType RowTimeline::getClickedControl(const QPointF &scenePos) cons
if (!m_rowTree->locked()) {
QPointF p = mapFromScene(scenePos.x(), scenePos.y());
+ p.setX(p.x() - TimelineConstants::RULER_EDGE_OFFSET);
+
const int halfHandle = TimelineConstants::DURATION_HANDLE_W * .5;
// Never choose start handle if end time is zero, as you cannot adjust it in that case
bool startHandle = p.x() > m_startX - halfHandle && p.x() < m_startX + halfHandle
- && !qFuzzyIsNull(m_endTime);
+ && m_endTime > 0;
bool endHandle = p.x() > m_endX - halfHandle && p.x() < m_endX + halfHandle;
if (startHandle && endHandle) {
// If handles overlap, choose the handle based on the side of the click relative to start
@@ -566,8 +639,8 @@ void RowTimeline::clearBoundChildren()
// move the duration area (start/end x)
void RowTimeline::moveDurationBy(double dx)
{
- if (m_startX + dx < TimelineConstants::RULER_EDGE_OFFSET)
- dx = TimelineConstants::RULER_EDGE_OFFSET - m_startX;
+ if (m_startX + dx < 0)
+ dx = -m_startX;
m_startX += dx;
m_endX += dx;
@@ -578,8 +651,9 @@ void RowTimeline::moveDurationBy(double dx)
m_maxEndX = m_endX;
}
- m_startTime = xToTime(m_startX);
- m_endTime = xToTime(m_endX);
+ Ruler *ruler = m_rowTree->m_scene->ruler();
+ m_startTime = ruler->distanceToTime(m_startX);
+ m_endTime = ruler->distanceToTime(m_endX);
// move keyframes with the row
if (!m_rowTree->isProperty()) { // make sure we don't move the keyframes twice
@@ -602,8 +676,8 @@ void RowTimeline::moveDurationBy(double dx)
void RowTimeline::moveDurationTo(double newX)
{
- if (newX < TimelineConstants::RULER_EDGE_OFFSET)
- newX = TimelineConstants::RULER_EDGE_OFFSET;
+ if (newX < 0)
+ newX = 0;
double dx = newX - m_startX;
double durationX = m_endX - m_startX;
@@ -617,13 +691,14 @@ void RowTimeline::moveDurationTo(double newX)
m_maxEndX = m_endX;
}
- m_startTime = xToTime(m_startX);
- m_endTime = xToTime(m_endX);
+ Ruler *ruler = m_rowTree->m_scene->ruler();
+ m_startTime = ruler->distanceToTime(m_startX);
+ m_endTime = ruler->distanceToTime(m_endX);
// move keyframes with the row
if (!m_rowTree->isProperty()) { // make sure we don't move the keyframes twice
for (Keyframe *keyframe : qAsConst(m_keyframes))
- keyframe->time += rowTree()->m_scene->ruler()->distanceToTime(dx);
+ keyframe->time += ruler->distanceToTime(dx);
}
update();
@@ -639,7 +714,7 @@ void RowTimeline::moveDurationTo(double newX)
}
}
-double RowTimeline::getDurationMoveTime() const
+long RowTimeline::getDurationMoveTime() const
{
return m_startTime - m_startDurationMoveStartTime;
}
@@ -649,26 +724,12 @@ double RowTimeline::getDurationMoveOffsetX() const
return m_startDurationMoveOffsetX;
}
-double RowTimeline::getDuration() const
+long RowTimeline::getDuration() const
{
return m_endTime - m_startTime;
}
-// convert time (seconds) values to x
-double RowTimeline::timeToX(double time) const
-{
- return TimelineConstants::RULER_EDGE_OFFSET + time * TimelineConstants::RULER_SEC_W
- * rowTree()->m_scene->ruler()->timelineScale();
-}
-
-// convert x values to time (seconds)
-double RowTimeline::xToTime(double xPos) const
-{
- return (xPos - TimelineConstants::RULER_EDGE_OFFSET)
- / (TimelineConstants::RULER_SEC_W * rowTree()->m_scene->ruler()->timelineScale());
-}
-
-void RowTimeline::collectChildKeyframeTimes(QVector<double> &childKeyframeTimes)
+void RowTimeline::collectChildKeyframeTimes(QVector<long> &childKeyframeTimes)
{
const auto childRows = m_rowTree->childRows();
for (const auto row : childRows) {
@@ -690,13 +751,13 @@ void RowTimeline::updatePosition()
// Set the position of the start of the row duration
void RowTimeline::setStartX(double startX)
{
- if (startX < TimelineConstants::RULER_EDGE_OFFSET)
- startX = TimelineConstants::RULER_EDGE_OFFSET;
+ if (startX < 0)
+ startX = 0;
else if (startX > m_endX)
startX = m_endX;
m_startX = startX;
- m_startTime = xToTime(startX);
+ m_startTime = m_rowTree->m_scene->ruler()->distanceToTime(startX);
if (!m_rowTree->parentRow() || m_rowTree->parentRow()->rowType() == OBJTYPE_SCENE
|| m_rowTree->hasComponentAncestor()) {
@@ -715,7 +776,7 @@ void RowTimeline::setEndX(double endX)
endX = m_startX;
m_endX = endX;
- m_endTime = xToTime(endX);
+ m_endTime = m_rowTree->m_scene->ruler()->distanceToTime(endX);
if (!m_rowTree->parentRow() || m_rowTree->parentRow()->rowType() == OBJTYPE_SCENE
|| m_rowTree->hasComponentAncestor()) {
@@ -832,10 +893,10 @@ void RowTimeline::updateCommentItemPos()
-TimelineConstants::ROW_TEXT_OFFSET_Y);
}
-void RowTimeline::setStartTime(double startTime)
+void RowTimeline::setStartTime(long startTime)
{
m_startTime = startTime;
- m_startX = timeToX(startTime);
+ m_startX = m_rowTree->m_scene->ruler()->timeToDistance(startTime);
if (!m_rowTree->parentRow() || m_rowTree->parentRow()->rowType() == OBJTYPE_SCENE
|| m_rowTree->hasComponentAncestor()) {
@@ -847,10 +908,10 @@ void RowTimeline::setStartTime(double startTime)
update();
}
-void RowTimeline::setEndTime(double endTime)
+void RowTimeline::setEndTime(long endTime)
{
m_endTime = endTime;
- m_endX = timeToX(endTime);
+ m_endX = m_rowTree->m_scene->ruler()->timeToDistance(endTime);
if (!m_rowTree->parentRow() || m_rowTree->parentRow()->rowType() == OBJTYPE_SCENE
|| m_rowTree->hasComponentAncestor()) {
@@ -862,22 +923,24 @@ void RowTimeline::setEndTime(double endTime)
update();
}
+// duration start x in local space (x=0 at time=0)
double RowTimeline::getStartX() const
{
return m_startX;
}
+// duration end x in local space
double RowTimeline::getEndX() const
{
return m_endX;
}
-double RowTimeline::getStartTime() const
+long RowTimeline::getStartTime() const
{
return m_startTime;
}
-double RowTimeline::getEndTime() const
+long RowTimeline::getEndTime() const
{
return m_endTime;
}
@@ -912,16 +975,16 @@ QList<Keyframe *> RowTimeline::keyframes() const
return m_keyframes;
}
-QString RowTimeline::formatTime(double seconds) const
+QString RowTimeline::formatTime(long millis) const
{
static const QString timeTemplate = tr("%1:%2.%3");
static const QChar fillChar = tr("0").at(0);
- long mins = seconds / 60;
- long secs = seconds - mins * 60;
- long millis = qRound((seconds - (int)seconds) * 1000);
+ long mins = millis % 3600000 / 60000;
+ long secs = millis % 60000 / 1000;
+ long mils = millis % 1000;
- return timeTemplate.arg(mins).arg(secs, 2, 10, fillChar).arg(millis, 3, 10, fillChar);
+ return timeTemplate.arg(mins).arg(secs, 2, 10, fillChar).arg(mils, 3, 10, fillChar);
}
void RowTimeline::showToolTip(const QPointF &pos)
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h
index 32dab1bc..00c81696 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h
@@ -57,8 +57,8 @@ public:
void clearBoundChildren();
void moveDurationBy(double dx);
void moveDurationTo(double newX);
- void setStartTime(double startTime);
- void setEndTime(double endTime);
+ void setStartTime(long startTime);
+ void setEndTime(long endTime);
void setStartX(double startX);
void setEndX(double endX);
void setBarColor(const QColor &color);
@@ -72,13 +72,13 @@ public:
TimelineControlType getClickedControl(const QPointF &scenePos) const;
double getStartX() const;
double getEndX() const;
- double getStartTime() const;
- double getEndTime() const;
- double getDurationMoveTime() const; // the time a row duration has moved (to commit to binding)
+ long getStartTime() const;
+ long getEndTime() const;
+ long getDurationMoveTime() const; // the time a row duration has moved (to commit to binding)
double getDurationMoveOffsetX() const;
- double getDuration() const;
+ long getDuration() const;
QColor barColor() const;
- int type() const;
+ int type() const override;
RowTimeline *parentRow() const;
RowTree *rowTree() const;
Keyframe *getClickedKeyframe(const QPointF &scenePos);
@@ -99,18 +99,16 @@ private:
void updateCommentItemPos();
void drawColorPropertyGradient(QPainter *painter, int width);
bool isColorProperty() const;
- QString formatTime(double seconds) const;
- double timeToX(double time) const;
- double xToTime(double xPos) const;
- void collectChildKeyframeTimes(QVector<double> &childKeyframeTimes);
+ QString formatTime(long millis) const;
+ void collectChildKeyframeTimes(QVector<long> &childKeyframeTimes);
RowTree *m_rowTree;
RowTimelinePropertyGraph *m_propertyGraph = nullptr;
RowTimelineCommentItem *m_commentItem = nullptr;
- double m_startTime = 0;
- double m_startDurationMoveStartTime = 0;
+ long m_startTime = 0;
+ long m_startDurationMoveStartTime = 0;
double m_startDurationMoveOffsetX = 0;
- double m_endTime = 0;
+ long m_endTime = 0;
double m_startX = 0;
double m_endX = 0;
double m_minStartX = 0;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp
index ecd31b9a..7861bb19 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp
@@ -232,7 +232,7 @@ void RowTimelineContextMenu::setInterpolation()
void RowTimelineContextMenu::setKeyframeTime()
{
- m_keyframeManager->SetKeyframeTime(m_keyframe->time * 1000.0);
+ m_keyframeManager->SetKeyframeTime(m_keyframe->time);
}
void RowTimelineContextMenu::changeTimeBarColor()
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp
index a65e235d..3c82d73b 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp
@@ -85,7 +85,7 @@ void RowTimelinePropertyGraph::paintSingleChannel(QPainter *painter, long inChan
QPainterPath path;
for (int i = 0; i < m_rect.width(); i += interval) {
// Value time in ms
- long time = 1000 * (i / (TimelineConstants::RULER_SEC_W * timelineScale));
+ long time = i / (TimelineConstants::RULER_MILLI_W * timelineScale);
float value = m_propBinding->GetChannelValueAtTime(inChannelIndex, time);
float yPos = graphY + (1.0 - (value - minVal) / (maxVal - minVal)) * graphHeight;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
index 0056d90e..db313ca9 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
@@ -38,6 +38,12 @@
#include "TreeHeader.h"
#include "StudioPreferences.h"
#include "KeyframeManager.h"
+#include "StudioApp.h"
+#include "Core.h"
+#include "Doc.h"
+#include "Qt3DSDMStudioSystem.h"
+#include "Qt3DSDMSlides.h"
+#include "StudioUtils.h"
#include <QtGui/qpainter.h>
#include "QtGui/qtextcursor.h"
@@ -53,6 +59,9 @@ RowTree::RowTree(TimelineGraphicsScene *timelineScene, EStudioObjectType rowType
m_scene = timelineScene;
m_rowType = rowType;
m_label = label;
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ m_onMasterSlide = doc->GetStudioSystem()->GetSlideSystem()->IsMasterSlide(
+ doc->GetActiveSlide());
initialize();
}
@@ -173,6 +182,8 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q
Q_UNUSED(option)
Q_UNUSED(widget)
+ bool hiResIcons = StudioUtils::devicePixelRatio(widget->window()->windowHandle()) > 1.0;
+
if (!y()) // prevents flickering when the row is just inserted to the layout
return;
@@ -220,24 +231,45 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q
static const QPixmap pixEmpty = QPixmap(":/images/Toggle-Empty.png");
static const QPixmap pixShy = QPixmap(":/images/Toggle-Shy.png");
static const QPixmap pixHide = QPixmap(":/images/Toggle-HideShow.png");
+ static const QPixmap pixHideDisabled = QPixmap(":/images/Toggle-HideShow-disabled.png");
static const QPixmap pixHideCtrld = QPixmap(":/images/Toggle-HideShowControlled.png");
static const QPixmap pixLock = QPixmap(":/images/Toggle-Lock.png");
+ static const QPixmap pixEmpty2x = QPixmap(":/images/Toggle-Empty@2x.png");
+ static const QPixmap pixShy2x = QPixmap(":/images/Toggle-Shy@2x.png");
+ static const QPixmap pixHide2x = QPixmap(":/images/Toggle-HideShow@2x.png");
+ static const QPixmap pixHideDisabled2x = QPixmap(":/images/Toggle-HideShow-disabled@2x.png");
+ static const QPixmap pixHideCtrld2x = QPixmap(":/images/Toggle-HideShowControlled@2x.png");
+ static const QPixmap pixLock2x = QPixmap(":/images/Toggle-Lock@2x.png");
if (hasActionButtons()) {
- painter->drawPixmap(m_rectShy , m_shy ? pixShy : pixEmpty);
+ painter->drawPixmap(m_rectShy, hiResIcons ? (m_shy ? pixShy2x : pixEmpty2x)
+ : (m_shy ? pixShy : pixEmpty));
// Eyeball visibility follows the visibility setting for the object even if it has
// datainput controller
- if (m_visibilityCtrld)
- painter->drawPixmap(m_rectVisible, m_visible ? pixHideCtrld : pixEmpty);
- else
- painter->drawPixmap(m_rectVisible, m_visible ? pixHide : pixEmpty);
- painter->drawPixmap(m_rectLocked , m_locked ? pixLock : pixEmpty);
+ // Disable eyeball from master slide
+ if (m_onMasterSlide) {
+ painter->drawPixmap(m_rectVisible, hiResIcons ? pixHideDisabled2x
+ : pixHideDisabled);
+ } else if (m_visibilityCtrld) {
+ painter->drawPixmap(m_rectVisible, hiResIcons
+ ? (m_visible ? pixHideCtrld2x : pixEmpty2x)
+ : (m_visible ? pixHideCtrld : pixEmpty));
+ } else {
+ painter->drawPixmap(m_rectVisible, hiResIcons
+ ? (m_visible ? pixHide2x : pixEmpty2x)
+ : (m_visible ? pixHide : pixEmpty));
+ }
+ painter->drawPixmap(m_rectLocked, hiResIcons ? (m_locked ? pixLock2x : pixEmpty2x)
+ : (m_locked ? pixLock : pixEmpty));
}
static const QPixmap pixInsertLeft = QPixmap(":/images/Insert-Left.png");
static const QPixmap pixInsertRight = QPixmap(":/images/Insert-Right.png");
+ static const QPixmap pixInsertLeft2x = QPixmap(":/images/Insert-Left@2x.png");
+ static const QPixmap pixInsertRight2x = QPixmap(":/images/Insert-Right@2x.png");
if (m_dndState == DnDState::SP_TARGET) { // Candidate target of a subpresentation drop
- painter->drawPixmap(19, 2, pixInsertLeft);
- painter->drawPixmap(treeWidth() - TimelineConstants::TREE_ICONS_W - 8, 2, pixInsertRight);
+ painter->drawPixmap(19, 2, hiResIcons ? pixInsertLeft2x : pixInsertLeft);
+ painter->drawPixmap(treeWidth() - TimelineConstants::TREE_ICONS_W - 8, 2, hiResIcons
+ ? pixInsertRight2x : pixInsertRight);
} else if (m_dndState == DnDState::Parent) { // Candidate parent of a dragged row
painter->setPen(QPen(CStudioPreferences::timelineRowMoverColor(), 1));
painter->drawRect(QRect(1, 1, treeWidth() - 2, size().height() - 3));
@@ -250,6 +282,14 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q
static const QPixmap pixChildAction = QPixmap(":/images/Action-ChildAction.png");
static const QPixmap pixCompMasterAction = QPixmap(":/images/Action-ComponentMasterAction.png");
static const QPixmap pixCompAction = QPixmap(":/images/Action-ComponentAction.png");
+ static const QPixmap pixMasterAction2x = QPixmap(":/images/Action-MasterAction@2x.png");
+ static const QPixmap pixAction2x = QPixmap(":/images/Action-Action@2x.png");
+ static const QPixmap pixChildMasterAction2x
+ = QPixmap(":/images/Action-ChildMasterAction@2x.png");
+ static const QPixmap pixChildAction2x = QPixmap(":/images/Action-ChildAction@2x.png");
+ static const QPixmap pixCompMasterAction2x
+ = QPixmap(":/images/Action-ComponentMasterAction@2x.png");
+ static const QPixmap pixCompAction2x = QPixmap(":/images/Action-ComponentAction@2x.png");
if (!isProperty()) {
// subpresentation indicators
@@ -262,116 +302,185 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q
}
if (m_actionStates & ActionState::MasterAction) // has master action
- painter->drawPixmap(0, 0, pixMasterAction);
+ painter->drawPixmap(0, 0, hiResIcons ? pixMasterAction2x : pixMasterAction);
else if (m_actionStates & ActionState::Action) // has action
- painter->drawPixmap(0, 0, pixAction);
+ painter->drawPixmap(0, 0, hiResIcons ? pixAction2x : pixAction);
if (!expanded()) {
- if (m_actionStates & ActionState::MasterChildAction) // children have master action
- painter->drawPixmap(0, 0, pixChildMasterAction);
- else if (m_actionStates & ActionState::ChildAction) // children have action
- painter->drawPixmap(0, 0, pixChildAction);
+ if (m_actionStates & ActionState::MasterChildAction) {
+ // children have master action
+ painter->drawPixmap(0, 0, hiResIcons ? pixChildMasterAction2x
+ : pixChildMasterAction);
+ } else if (m_actionStates & ActionState::ChildAction) {
+ // children have action
+ painter->drawPixmap(0, 0, hiResIcons ? pixChildAction2x : pixChildAction);
+ }
}
if (m_actionStates & ActionState::MasterComponentAction) // component has master action
- painter->drawPixmap(0, 0, pixCompMasterAction);
+ painter->drawPixmap(0, 0, hiResIcons ? pixCompMasterAction2x : pixCompMasterAction);
else if (m_actionStates & ActionState::ComponentAction) // component has action
- painter->drawPixmap(0, 0, pixCompAction);
+ painter->drawPixmap(0, 0, hiResIcons ? pixCompAction2x : pixCompAction);
+ }
+
+ // variants indicator
+ if (m_variantsGroups.size() > 0) {
+ const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef();
+ for (int i = 0; i < m_variantsGroups.size(); ++i) {
+ painter->fillRect(QRect(clipX() + 2 + i * 9, 6, 6, 6),
+ variantsDef[m_variantsGroups[i]].m_color);
+ }
}
// The following items need to be clipped so that they do not draw overlapping shy etc. buttons
- painter->setClipRect(0, 0, treeWidth() - TimelineConstants::TREE_ICONS_W,
- TimelineConstants::ROW_H);
+ painter->setClipRect(0, 0, clipX(), TimelineConstants::ROW_H);
// expand/collapse arrow
static const QPixmap pixArrow = QPixmap(":/images/arrow.png");
static const QPixmap pixArrowDown = QPixmap(":/images/arrow_down.png");
- if (m_arrowVisible)
- painter->drawPixmap(m_rectArrow, expanded() ? pixArrowDown : pixArrow);
+ static const QPixmap pixArrow2x = QPixmap(":/images/arrow@2x.png");
+ static const QPixmap pixArrowDown2x = QPixmap(":/images/arrow_down@2x.png");
+ if (m_arrowVisible) {
+ painter->drawPixmap(m_rectArrow, hiResIcons ? (expanded() ? pixArrowDown2x : pixArrow2x)
+ : (expanded() ? pixArrowDown : pixArrow));
+ }
// Row type icon
- static const QPixmap pixSceneNormal = QPixmap(":/images/Objects-Scene-Normal.png");
- static const QPixmap pixLayerNormal = QPixmap(":/images/Objects-Layer-Normal.png");
- static const QPixmap pixObjectNormal = QPixmap(":/images/Objects-Model-Normal.png");
- static const QPixmap pixLightNormal = QPixmap(":/images/Objects-Light-Normal.png");
- static const QPixmap pixCameraNormal = QPixmap(":/images/Objects-Camera-Normal.png");
- static const QPixmap pixTextNormal = QPixmap(":/images/Objects-Text-Normal.png");
- static const QPixmap pixAliasNormal = QPixmap(":/images/Objects-Alias-Normal.png");
- static const QPixmap pixGroupNormal = QPixmap(":/images/Objects-Group-Normal.png");
+ static const QPixmap pixSceneNormal = QPixmap(":/images/Objects-Scene-Normal.png");
+ static const QPixmap pixLayerNormal = QPixmap(":/images/Objects-Layer-Normal.png");
+ static const QPixmap pixObjectNormal = QPixmap(":/images/Objects-Model-Normal.png");
+ static const QPixmap pixLightNormal = QPixmap(":/images/Objects-Light-Normal.png");
+ static const QPixmap pixCameraNormal = QPixmap(":/images/Objects-Camera-Normal.png");
+ static const QPixmap pixTextNormal = QPixmap(":/images/Objects-Text-Normal.png");
+ static const QPixmap pixAliasNormal = QPixmap(":/images/Objects-Alias-Normal.png");
+ static const QPixmap pixGroupNormal = QPixmap(":/images/Objects-Group-Normal.png");
static const QPixmap pixComponentNormal = QPixmap(":/images/Objects-Component-Normal.png");
- static const QPixmap pixMaterialNormal = QPixmap(":/images/Objects-Material-Normal.png");
- static const QPixmap pixPropertyNormal = QPixmap(":/images/Objects-Property-Normal.png");
- static const QPixmap pixImageNormal = QPixmap(":/images/Objects-Image-Normal.png");
- static const QPixmap pixBehaviorNormal = QPixmap(":/images/Objects-Behavior-Normal.png");
- static const QPixmap pixEffectNormal = QPixmap(":/images/Objects-Effect-Normal.png");
-
- static const QPixmap pixSceneDisabled = QPixmap(":/images/Objects-Scene-Disabled.png");
- static const QPixmap pixLayerDisabled = QPixmap(":/images/Objects-Layer-Disabled.png");
- static const QPixmap pixObjectDisabled = QPixmap(":/images/Objects-Model-Disabled.png");
- static const QPixmap pixLightDisabled = QPixmap(":/images/Objects-Light-Disabled.png");
- static const QPixmap pixCameraDisabled = QPixmap(":/images/Objects-Camera-Disabled.png");
- static const QPixmap pixTextDisabled = QPixmap(":/images/Objects-Text-Disabled.png");
- static const QPixmap pixAliasDisabled = QPixmap(":/images/Objects-Alias-Disabled.png");
- static const QPixmap pixGroupDisabled = QPixmap(":/images/Objects-Group-Disabled.png");
+ static const QPixmap pixMaterialNormal = QPixmap(":/images/Objects-Material-Normal.png");
+ static const QPixmap pixPropertyNormal = QPixmap(":/images/Objects-Property-Normal.png");
+ static const QPixmap pixImageNormal = QPixmap(":/images/Objects-Image-Normal.png");
+ static const QPixmap pixBehaviorNormal = QPixmap(":/images/Objects-Behavior-Normal.png");
+ static const QPixmap pixEffectNormal= QPixmap(":/images/Objects-Effect-Normal.png");
+ static const QPixmap pixSceneNormal2x = QPixmap(":/images/Objects-Scene-Normal@2x.png");
+ static const QPixmap pixLayerNormal2x = QPixmap(":/images/Objects-Layer-Normal@2x.png");
+ static const QPixmap pixObjectNormal2x = QPixmap(":/images/Objects-Model-Normal@2x.png");
+ static const QPixmap pixLightNormal2x = QPixmap(":/images/Objects-Light-Normal@2x.png");
+ static const QPixmap pixCameraNormal2x = QPixmap(":/images/Objects-Camera-Normal@2x.png");
+ static const QPixmap pixTextNormal2x = QPixmap(":/images/Objects-Text-Normal@2x.png");
+ static const QPixmap pixAliasNormal2x = QPixmap(":/images/Objects-Alias-Normal@2x.png");
+ static const QPixmap pixGroupNormal2x = QPixmap(":/images/Objects-Group-Normal@2x.png");
+ static const QPixmap pixComponentNormal2x = QPixmap(":/images/Objects-Component-Normal@2x.png");
+ static const QPixmap pixMaterialNormal2x = QPixmap(":/images/Objects-Material-Normal@2x.png");
+ static const QPixmap pixPropertyNormal2x = QPixmap(":/images/Objects-Property-Normal@2x.png");
+ static const QPixmap pixImageNormal2x = QPixmap(":/images/Objects-Image-Normal@2x.png");
+ static const QPixmap pixBehaviorNormal2x = QPixmap(":/images/Objects-Behavior-Normal@2x.png");
+ static const QPixmap pixEffectNormal2x = QPixmap(":/images/Objects-Effect-Normal@2x.png");
+
+ static const QPixmap pixSceneDisabled = QPixmap(":/images/Objects-Scene-Disabled.png");
+ static const QPixmap pixLayerDisabled = QPixmap(":/images/Objects-Layer-Disabled.png");
+ static const QPixmap pixObjectDisabled = QPixmap(":/images/Objects-Model-Disabled.png");
+ static const QPixmap pixLightDisabled = QPixmap(":/images/Objects-Light-Disabled.png");
+ static const QPixmap pixCameraDisabled = QPixmap(":/images/Objects-Camera-Disabled.png");
+ static const QPixmap pixTextDisabled = QPixmap(":/images/Objects-Text-Disabled.png");
+ static const QPixmap pixAliasDisabled = QPixmap(":/images/Objects-Alias-Disabled.png");
+ static const QPixmap pixGroupDisabled = QPixmap(":/images/Objects-Group-Disabled.png");
static const QPixmap pixComponentDisabled = QPixmap(":/images/Objects-Component-Disabled.png");
- static const QPixmap pixMaterialDisabled = QPixmap(":/images/Objects-Material-Disabled.png");
- static const QPixmap pixPropertyDisabled = QPixmap(":/images/Objects-Property-Disabled.png");
- static const QPixmap pixImageDisabled = QPixmap(":/images/Objects-Image-Disabled.png");
- static const QPixmap pixBehaviorDisabled = QPixmap(":/images/Objects-Behavior-Disabled.png");
- static const QPixmap pixEffectDisabled = QPixmap(":/images/Objects-Effect-Disabled.png");
+ static const QPixmap pixMaterialDisabled = QPixmap(":/images/Objects-Material-Disabled.png");
+ static const QPixmap pixPropertyDisabled = QPixmap(":/images/Objects-Property-Disabled.png");
+ static const QPixmap pixImageDisabled = QPixmap(":/images/Objects-Image-Disabled.png");
+ static const QPixmap pixBehaviorDisabled = QPixmap(":/images/Objects-Behavior-Disabled.png");
+ static const QPixmap pixEffectDisabled = QPixmap(":/images/Objects-Effect-Disabled.png");
+ static const QPixmap pixSceneDisabled2x = QPixmap(":/images/Objects-Scene-Disabled@2x.png");
+ static const QPixmap pixLayerDisabled2x = QPixmap(":/images/Objects-Layer-Disabled@2x.png");
+ static const QPixmap pixObjectDisabled2x = QPixmap(":/images/Objects-Model-Disabled@2x.png");
+ static const QPixmap pixLightDisabled2x = QPixmap(":/images/Objects-Light-Disabled@2x.png");
+ static const QPixmap pixCameraDisabled2x = QPixmap(":/images/Objects-Camera-Disabled@2x.png");
+ static const QPixmap pixTextDisabled2x = QPixmap(":/images/Objects-Text-Disabled@2x.png");
+ static const QPixmap pixAliasDisabled2x = QPixmap(":/images/Objects-Alias-Disabled@2x.png");
+ static const QPixmap pixGroupDisabled2x = QPixmap(":/images/Objects-Group-Disabled@2x.png");
+ static const QPixmap pixComponentDisabled2x
+ = QPixmap(":/images/Objects-Component-Disabled@2x.png");
+ static const QPixmap pixMaterialDisabled2x
+ = QPixmap(":/images/Objects-Material-Disabled@2x.png");
+ static const QPixmap pixPropertyDisabled2x
+ = QPixmap(":/images/Objects-Property-Disabled@2x.png");
+ static const QPixmap pixImageDisabled2x = QPixmap(":/images/Objects-Image-Disabled@2x.png");
+ static const QPixmap pixBehaviorDisabled2x
+ = QPixmap(":/images/Objects-Behavior-Disabled@2x.png");
+ static const QPixmap pixEffectDisabled2x = QPixmap(":/images/Objects-Effect-Disabled@2x.png");
QPixmap pixRowType;
- switch (m_rowType) {
- case OBJTYPE_SCENE:
- pixRowType = m_locked ? pixSceneDisabled : pixSceneNormal;
- break;
- case OBJTYPE_LAYER:
- pixRowType = m_locked ? pixLayerDisabled : pixLayerNormal;
- break;
- case OBJTYPE_MODEL:
- pixRowType = m_locked ? pixObjectDisabled : pixObjectNormal;
- break;
- case OBJTYPE_LIGHT:
- pixRowType = m_locked ? pixLightDisabled : pixLightNormal;
- break;
- case OBJTYPE_CAMERA:
- pixRowType = m_locked ? pixCameraDisabled : pixCameraNormal;
- break;
- case OBJTYPE_TEXT:
- pixRowType = m_locked ? pixTextDisabled : pixTextNormal;
- break;
- case OBJTYPE_ALIAS:
- pixRowType = m_locked ? pixAliasDisabled : pixAliasNormal;
- break;
- case OBJTYPE_GROUP:
- pixRowType = m_locked ? pixGroupDisabled : pixGroupNormal;
- break;
- case OBJTYPE_COMPONENT:
- pixRowType = m_locked ? pixComponentDisabled : pixComponentNormal;
- break;
- case OBJTYPE_MATERIAL:
- pixRowType = m_locked ? pixMaterialDisabled : pixMaterialNormal;
- break;
- case OBJTYPE_IMAGE:
- pixRowType = m_locked ? pixImageDisabled : pixImageNormal;
- break;
- case OBJTYPE_BEHAVIOR:
- pixRowType = m_locked ? pixBehaviorDisabled : pixBehaviorNormal;
- break;
- case OBJTYPE_EFFECT:
- pixRowType = m_locked ? pixEffectDisabled : pixEffectNormal;
- break;
- default:
- break;
+ if (m_isProperty) {
+ pixRowType = hiResIcons ? (m_locked ? pixPropertyDisabled2x : pixPropertyNormal2x)
+ : (m_locked ? pixPropertyDisabled : pixPropertyNormal);
+ } else {
+ switch (m_rowType) {
+ case OBJTYPE_SCENE:
+ pixRowType = hiResIcons ? (m_locked ? pixSceneDisabled2x : pixSceneNormal2x)
+ : (m_locked ? pixSceneDisabled : pixSceneNormal);
+ break;
+ case OBJTYPE_LAYER:
+ pixRowType = hiResIcons ? (m_locked ? pixLayerDisabled2x : pixLayerNormal2x)
+ : (m_locked ? pixLayerDisabled : pixLayerNormal);
+ break;
+ case OBJTYPE_MODEL:
+ pixRowType = hiResIcons ? (m_locked ? pixObjectDisabled2x : pixObjectNormal2x)
+ : (m_locked ? pixObjectDisabled : pixObjectNormal);
+ break;
+ case OBJTYPE_LIGHT:
+ pixRowType = hiResIcons ? (m_locked ? pixLightDisabled2x : pixLightNormal2x)
+ : (m_locked ? pixLightDisabled : pixLightNormal);
+ break;
+ case OBJTYPE_CAMERA:
+ pixRowType = hiResIcons ? (m_locked ? pixCameraDisabled2x : pixCameraNormal2x)
+ : (m_locked ? pixCameraDisabled : pixCameraNormal);
+ break;
+ case OBJTYPE_TEXT:
+ pixRowType = hiResIcons ? (m_locked ? pixTextDisabled2x : pixTextNormal2x)
+ : (m_locked ? pixTextDisabled : pixTextNormal);
+ break;
+ case OBJTYPE_ALIAS:
+ pixRowType = hiResIcons ? (m_locked ? pixAliasDisabled2x : pixAliasNormal2x)
+ : (m_locked ? pixAliasDisabled : pixAliasNormal);
+ break;
+ case OBJTYPE_GROUP:
+ pixRowType = hiResIcons ? (m_locked ? pixGroupDisabled2x : pixGroupNormal2x)
+ : (m_locked ? pixGroupDisabled : pixGroupNormal);
+ break;
+ case OBJTYPE_COMPONENT:
+ pixRowType = hiResIcons ? (m_locked ? pixComponentDisabled2x : pixComponentNormal2x)
+ : (m_locked ? pixComponentDisabled : pixComponentNormal);
+ break;
+ case OBJTYPE_MATERIAL:
+ pixRowType = hiResIcons ? (m_locked ? pixMaterialDisabled2x : pixMaterialNormal2x)
+ : (m_locked ? pixMaterialDisabled : pixMaterialNormal);
+ break;
+ case OBJTYPE_IMAGE:
+ pixRowType = hiResIcons ? (m_locked ? pixImageDisabled2x : pixImageNormal2x)
+ : (m_locked ? pixImageDisabled : pixImageNormal);
+ break;
+ case OBJTYPE_BEHAVIOR:
+ pixRowType = hiResIcons ? (m_locked ? pixBehaviorDisabled2x : pixBehaviorNormal2x)
+ : (m_locked ? pixBehaviorDisabled : pixBehaviorNormal);
+ break;
+ case OBJTYPE_EFFECT:
+ pixRowType = hiResIcons ? (m_locked ? pixEffectDisabled2x : pixEffectNormal2x)
+ : (m_locked ? pixEffectDisabled : pixEffectNormal);
+ break;
+ default:
+ break;
+ }
}
- if (m_isProperty)
- pixRowType = m_locked ? pixPropertyDisabled : pixPropertyNormal;
-
painter->drawPixmap(m_rectType, pixRowType);
}
+void RowTree::updateVariants(const QStringList &groups)
+{
+ m_variantsGroups = groups;
+ update();
+}
+
int RowTree::treeWidth() const
{
return m_scene->treeWidth() - m_scene->getScrollbarOffsets().x();
@@ -415,6 +524,12 @@ void RowTree::setBinding(ITimelineItemBinding *binding)
updateFromBinding();
}
+// x value where label should clip
+int RowTree::clipX() const
+{
+ return treeWidth() - TimelineConstants::TREE_ICONS_W - m_variantsGroups.size() * 9 - 2;
+}
+
ITimelineItemProperty *RowTree::propBinding()
{
return m_PropBinding;
@@ -793,7 +908,8 @@ TreeControlType RowTree::getClickedControl(const QPointF &scenePos)
if (m_rectShy.contains(p.x(), p.y())) {
toggleShy();
return TreeControlType::Shy;
- } else if (m_rectVisible.contains(p.x(), p.y())) {
+ } else if (!m_onMasterSlide && m_rectVisible.contains(p.x(), p.y())) {
+ // Prevent toggling hide on master slide
toggleVisible();
return TreeControlType::Hide;
} else if (m_rectLocked.contains(p.x(), p.y())) {
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h
index bde2da48..4524f345 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h
@@ -140,6 +140,7 @@ public:
void updateLabel();
void setRowVisible(bool visible);
void setDnDHover(bool val);
+ void updateVariants(const QStringList &groups);
DnDState getDnDState() const;
ITimelineItemBinding *getBinding() const;
@@ -148,6 +149,8 @@ public:
void updateFilter();
void updateLock(bool state);
void updateSubpresentations(int updateParentsOnlyVal = 0);
+ int clipX() const;
+
protected:
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
@@ -181,6 +184,7 @@ private:
bool m_arrowVisible = false;
bool m_dndHover = false;
bool m_visibilityCtrld = false;
+ bool m_onMasterSlide = false;
DnDState m_dndState = DnDState::None;
ActionStates m_actionStates = ActionState::None;
bool m_hasSubpresentation = false;
@@ -193,6 +197,7 @@ private:
QString m_label;
QList<RowTree *> m_childRows;
QList<RowTree *> m_childProps;
+ QStringList m_variantsGroups;
ITimelineItemBinding *m_binding = nullptr;
ITimelineItemProperty *m_PropBinding = nullptr; // for property rows
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeLabelItem.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeLabelItem.cpp
index cfd0ddd8..1029c00a 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeLabelItem.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeLabelItem.cpp
@@ -146,7 +146,7 @@ QRectF RowTreeLabelItem::boundingRect() const
if (!m_rowTree)
return QGraphicsTextItem::boundingRect();
- double w = m_rowTree->treeWidth() - x() - TimelineConstants::TREE_ICONS_W;
+ double w = m_rowTree->clipX() - x();
// Bounding rect width must be at least 1
w = std::max(w, 1.0);
return QRectF(0, 0, w, TimelineConstants::ROW_H);
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp
index 86a250f4..62c6de01 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp
@@ -32,7 +32,6 @@
#include <QtGui/qpainter.h>
#include <QtWidgets/qwidget.h>
-#include <QtCore/qdebug.h>
Ruler::Ruler(TimelineItem *parent) : TimelineItem(parent)
{
@@ -45,9 +44,9 @@ void Ruler::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWi
double xStep = TimelineConstants::RULER_SEC_W / TimelineConstants::RULER_SEC_DIV * m_timeScale;
double activeSegmentsWidth = TimelineConstants::RULER_EDGE_OFFSET
- + m_duration * xStep * TimelineConstants::RULER_SEC_DIV;
+ + m_duration / 1000.0 * xStep * TimelineConstants::RULER_SEC_DIV;
double totalSegmentsWidth = TimelineConstants::RULER_EDGE_OFFSET
- + m_maxDuration * xStep * TimelineConstants::RULER_SEC_DIV;
+ + m_maxDuration / 1000.0 * xStep * TimelineConstants::RULER_SEC_DIV;
// Ruler painted width to be at least widget width
double minRulerWidth = widget->width();
@@ -80,9 +79,9 @@ void Ruler::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWi
if (rowX < (m_viewportX - margin) || rowX > (m_viewportX + minRulerWidth + margin))
continue;
- const int h = i % secDiv == 0 ? TimelineConstants::RULER_DIV_H1 :
- i % secDiv == secDiv * 0.5 ? TimelineConstants::RULER_DIV_H2 :
- TimelineConstants::RULER_DIV_H3;
+ const int h = i % secDiv == 0 ? TimelineConstants::RULER_DIV_H1
+ : i % secDiv == secDiv * 0.5 ? TimelineConstants::RULER_DIV_H2
+ : TimelineConstants::RULER_DIV_H3;
if (!useDisabledColor && rowX > activeSegmentsWidth) {
painter->setPen(CStudioPreferences::timelineRulerColorDisabled());
@@ -122,28 +121,16 @@ void Ruler::setTimelineScale(double scl)
update();
}
-// convert distance values to time (seconds)
-double Ruler::distanceToTime(double distance) const
+// convert distance values to time (milliseconds)
+long Ruler::distanceToTime(double distance) const
{
- return distance / (TimelineConstants::RULER_SEC_W * m_timeScale);
+ return distance / (TimelineConstants::RULER_MILLI_W * m_timeScale);
}
-// convert time (seconds) values to distance
-double Ruler::timeToDistance(double time) const
+// convert time (milliseconds) values to distance
+double Ruler::timeToDistance(long time) const
{
- return time * TimelineConstants::RULER_SEC_W * m_timeScale;
-}
-
-// x position of ruler value 0
-double Ruler::durationStartX() const
-{
- return x() + TimelineConstants::RULER_EDGE_OFFSET;
-}
-
-// x position of ruler max value (duration)
-double Ruler::durationEndX() const
-{
- return durationStartX() + timeToDistance(m_duration);
+ return time * TimelineConstants::RULER_MILLI_W * m_timeScale;
}
double Ruler::timelineScale() const
@@ -154,7 +141,7 @@ double Ruler::timelineScale() const
// Returns end of right-most layer/component row.
// Active color of ruler is used up to this point.
// Slide plays up to this point.
-double Ruler::duration() const
+long Ruler::duration() const
{
return m_duration;
}
@@ -162,12 +149,12 @@ double Ruler::duration() const
// Returns end of right-most row.
// Ruler steps & labels are drawn up to this point.
// Timeline scrollbar allows scrolling up to this point.
-double Ruler::maxDuration() const
+long Ruler::maxDuration() const
{
return m_maxDuration;
}
-void Ruler::setDuration(double duration)
+void Ruler::setDuration(long duration)
{
if (m_duration != duration) {
m_duration = duration;
@@ -176,7 +163,7 @@ void Ruler::setDuration(double duration)
}
}
-void Ruler::setMaxDuration(double maxDuration)
+void Ruler::setMaxDuration(long maxDuration)
{
if (m_maxDuration != maxDuration) {
m_maxDuration = maxDuration;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.h
index a234b72b..005a23c3 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.h
@@ -42,33 +42,31 @@ public:
explicit Ruler(TimelineItem *parent = nullptr);
void setTimelineScale(double scl);
- double distanceToTime(double distance) const;
- double timeToDistance(double time) const;
- double durationStartX() const;
- double durationEndX() const;
+ long distanceToTime(double distance) const;
+ double timeToDistance(long time) const;
double timelineScale() const;
- double duration() const;
- double maxDuration() const;
- void setDuration(double duration);
- void setMaxDuration(double maxDuration);
+ long duration() const;
+ long maxDuration() const;
+ void setDuration(long duration);
+ void setMaxDuration(long maxDuration);
void setViewportX(int viewportX);
int viewportX() const;
- int type() const;
+ int type() const override;
protected:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget = nullptr) override;
signals:
- void maxDurationChanged(double maxDuration);
- void durationChanged(double duration);
+ void maxDurationChanged(long maxDuration);
+ void durationChanged(long duration);
void viewportXChanged(int viewportX);
private:
const QString timestampString(int timeMs);
double m_timeScale = 2;
- double m_duration = 0; // in seconds
- double m_maxDuration = 0; // in seconds
+ long m_duration = 0; // milliseconds
+ long m_maxDuration = 0; // milliseconds
int m_viewportX = 0;
};
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h
index 76af75ef..71d26c0d 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h
@@ -51,7 +51,7 @@ public:
TypeRowMover
};
- int type() const;
+ int type() const override;
};
#endif // TIMELINEITEM_H
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp
index 295a5273..f3232b9d 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp
@@ -28,6 +28,7 @@
#include "TreeHeader.h"
#include "StudioPreferences.h"
+#include "StudioUtils.h"
#include <QtGui/qpainter.h>
@@ -45,14 +46,19 @@ void TreeHeader::paint(QPainter *painter, const QStyleOptionGraphicsItem *option
Q_UNUSED(option)
Q_UNUSED(widget)
+ bool hiResIcons = StudioUtils::devicePixelRatio(widget->window()->windowHandle()) > 1.0;
+
double treeWidth = m_scene->treeWidth() - m_scene->getScrollbarOffsets().x();
m_rectShy .setRect(treeWidth - 16 * 3.3, size().height() * .5 - 8, 16, 16);
m_rectVisible.setRect(treeWidth - 16 * 2.2, size().height() * .5 - 8, 16, 16);
m_rectLock .setRect(treeWidth - 16 * 1.1, size().height() * .5 - 8, 16, 16);
- static const QPixmap pixShy = QPixmap(":/images/Toggle-Shy.png");
+ static const QPixmap pixShy = QPixmap(":/images/Toggle-Shy.png");
static const QPixmap pixVisible = QPixmap(":/images/Toggle-HideShow.png");
- static const QPixmap pixLock = QPixmap(":/images/Toggle-Lock.png");
+ static const QPixmap pixLock = QPixmap(":/images/Toggle-Lock.png");
+ static const QPixmap pixShy2x = QPixmap(":/images/Toggle-Shy@2x.png");
+ static const QPixmap pixVisible2x = QPixmap(":/images/Toggle-HideShow@2x.png");
+ static const QPixmap pixLock2x = QPixmap(":/images/Toggle-Lock@2x.png");
const QColor selectedColor = CStudioPreferences::timelineFilterButtonSelectedColor();
const QColor hoveredColor = CStudioPreferences::timelineFilterButtonHoveredColor();
@@ -74,9 +80,9 @@ void TreeHeader::paint(QPainter *painter, const QStyleOptionGraphicsItem *option
else if (m_hoveredItem == 2)
painter->fillRect(m_rectLock, hoveredColor);
- painter->drawPixmap(m_rectShy , pixShy);
- painter->drawPixmap(m_rectVisible, pixVisible);
- painter->drawPixmap(m_rectLock , pixLock);
+ painter->drawPixmap(m_rectShy , hiResIcons ? pixShy2x : pixShy);
+ painter->drawPixmap(m_rectVisible, hiResIcons ? pixVisible2x : pixVisible);
+ painter->drawPixmap(m_rectLock , hiResIcons ? pixLock2x : pixLock);
}
TreeControlType TreeHeader::handleButtonsClick(const QPointF &scenePos)
diff --git a/src/Authoring/Studio/Qt3DStudio.pro b/src/Authoring/Studio/Qt3DStudio.pro
index 28704bd3..16f850c4 100644
--- a/src/Authoring/Studio/Qt3DStudio.pro
+++ b/src/Authoring/Studio/Qt3DStudio.pro
@@ -201,7 +201,6 @@ HEADERS += \
Palettes/Timeline/Bindings/ITimelineItem.h \
Palettes/Timeline/Bindings/ITimelineItemBinding.h \
Palettes/Timeline/Bindings/ITimelineItemProperty.h \
- Palettes/Timeline/Bindings/ITimelineKeyframesManager.h \
Palettes/Timeline/Bindings/ITimelineTimebar.h \
Palettes/Timeline/Bindings/IBreadCrumbProvider.h \
Palettes/TimelineGraphicsView/Keyframe.h \
@@ -261,15 +260,18 @@ HEADERS += \
UI/Q3DSPlayerWidget.h \
Render/StudioEnums.h \
Render/Q3DSTranslators.h \
- Palettes/Inspector/MaterialRefView.h \
+ Render/Q3DSSelectionWidget.h \
+ Render/Q3DSVisualAidWidget.h \
+ Render/Q3DSWidgetUtils.h \
+ Render/Q3DSManipulationWidget.h \
Palettes/scenecamera/scenecameraview.h \
Palettes/scenecamera/scenecamerascrollarea.h \
Palettes/scenecamera/scenecameraglwidget.h \
+ Palettes/Inspector/MaterialRefView.h \
Palettes/TimelineGraphicsView/ui/RowTimelineCommentItem.h \
- Render/Q3DSSelectionWidget.h \
- Render/Q3DSVisualAidWidget.h \
- Render/Q3DSWidgetUtils.h \
- Render/Q3DSManipulationWidget.h
+ Palettes/Inspector/VariantsGroupModel.h \
+ Palettes/Inspector/VariantsTagModel.h \
+ Palettes/Inspector/VariantTagDialog.h
FORMS += \
MainFrm.ui \
@@ -289,7 +291,8 @@ FORMS += \
UI/StartupDlg.ui \
Palettes/Project/EditPresentationIdDlg.ui \
Palettes/Project/ChooseImagePropertyDlg.ui \
- Palettes/scenecamera/scenecameraview.ui
+ Palettes/scenecamera/scenecameraview.ui \
+ Palettes/Inspector/VariantTagDialog.ui
SOURCES += \
Application/AboutDlg.cpp \
@@ -434,15 +437,18 @@ SOURCES += \
UI/Q3DSPlayerWidget.cpp \
Render/Q3DSEditCamera.cpp \
Render/Q3DSTranslators.cpp \
+ Render/Q3DSSelectionWidget.cpp \
+ Render/Q3DSVisualAidWidget.cpp \
+ Render/Q3DSWidgetUtils.cpp \
+ Render/Q3DSManipulationWidget.cpp \
Palettes/Inspector/MaterialRefView.cpp \
Palettes/scenecamera/scenecameraview.cpp \
Palettes/scenecamera/scenecamerascrollarea.cpp \
Palettes/scenecamera/scenecameraglwidget.cpp \
Palettes/TimelineGraphicsView/ui/RowTimelineCommentItem.cpp \
- Render/Q3DSSelectionWidget.cpp \
- Render/Q3DSVisualAidWidget.cpp \
- Render/Q3DSWidgetUtils.cpp \
- Render/Q3DSManipulationWidget.cpp
+ Palettes/Inspector/VariantsGroupModel.cpp \
+ Palettes/Inspector/VariantsTagModel.cpp \
+ Palettes/Inspector/VariantTagDialog.cpp
RESOURCES += \
MainFrm.qrc \
diff --git a/src/Authoring/Studio/UI/StudioAppPrefsPage.cpp b/src/Authoring/Studio/UI/StudioAppPrefsPage.cpp
index c20b6727..5e8f0e96 100644
--- a/src/Authoring/Studio/UI/StudioAppPrefsPage.cpp
+++ b/src/Authoring/Studio/UI/StudioAppPrefsPage.cpp
@@ -43,7 +43,6 @@
#include "Core.h"
#include "IStudioRenderer.h"
-#include <QtWidgets/qcolordialog.h>
#include <QtWidgets/qmessagebox.h>
#include <QtGui/qstandarditemmodel.h>
#include <QtCore/qdiriterator.h>
diff --git a/src/Authoring/Studio/Utils/StudioUtils.cpp b/src/Authoring/Studio/Utils/StudioUtils.cpp
index c0063ebe..43126de1 100644
--- a/src/Authoring/Studio/Utils/StudioUtils.cpp
+++ b/src/Authoring/Studio/Utils/StudioUtils.cpp
@@ -70,12 +70,16 @@ qreal StudioUtils::devicePixelRatio(QWindow *window)
{
qreal pixelRatio = 1.0;
- QWindow *w = window ? window : g_StudioApp.m_pMainWnd->windowHandle();
+ QWindow *w = window ? window
+ : g_StudioApp.m_pMainWnd
+ ? g_StudioApp.m_pMainWnd->windowHandle() : nullptr;
+
if (w) {
QScreen *s = w->screen();
if (s)
pixelRatio = s->devicePixelRatio();
}
+
return pixelRatio;
}
@@ -83,7 +87,8 @@ qreal StudioUtils::devicePixelRatio(QWindow *window)
bool StudioUtils::readFileToDomDocument(const QString &filePath, QDomDocument &domDoc)
{
QFile file(filePath);
- if (!file.open(QFile::Text | QIODevice::ReadOnly)) {
+ if (!file.open(QIODevice::ReadOnly)) {
+ file.setTextModeEnabled(false);
qWarning() << __FUNCTION__ << file.errorString() << "'" << filePath << "'";
return false;
}
@@ -96,7 +101,8 @@ bool StudioUtils::openDomDocumentSave(QSaveFile &file, QDomDocument &domDoc)
{
if (!readFileToDomDocument(file.fileName(), domDoc))
return false;
- if (!file.open(QFile::Text | QIODevice::WriteOnly)) {
+ if (!file.open(QIODevice::WriteOnly)) {
+ file.setTextModeEnabled(false);
qWarning() << __FUNCTION__ << file.errorString();
return false;
}
@@ -106,6 +112,8 @@ bool StudioUtils::openDomDocumentSave(QSaveFile &file, QDomDocument &domDoc)
// Saves contents of a QDomDocument into a previously opened text file
bool StudioUtils::commitDomDocumentSave(QSaveFile &file, const QDomDocument &domDoc)
{
+ // Disable end-of-line conversions
+ file.setTextModeEnabled(false);
// Overwrites entire file
if (file.resize(0) && file.write(domDoc.toByteArray(4)) != -1 && file.commit())
return true;
@@ -117,7 +125,8 @@ bool StudioUtils::commitDomDocumentSave(QSaveFile &file, const QDomDocument &dom
// Opens text file for saving without reading its contents
bool StudioUtils::openTextSave(QSaveFile &file)
{
- if (!file.open(QFile::Text | QIODevice::WriteOnly)) {
+ if (!file.open(QIODevice::WriteOnly)) {
+ file.setTextModeEnabled(false);
qWarning() << __FUNCTION__ << file.errorString();
return false;
}
diff --git a/src/Authoring/Studio/Utils/StudioUtils.h b/src/Authoring/Studio/Utils/StudioUtils.h
index 945ffeb2..f1db4c57 100644
--- a/src/Authoring/Studio/Utils/StudioUtils.h
+++ b/src/Authoring/Studio/Utils/StudioUtils.h
@@ -33,6 +33,7 @@
#include <QtXml/qdom.h>
#include <QtCore/qsavefile.h>
#include <QtCore/qxmlstream.h>
+#include <QtGui/qwindow.h>
QT_FORWARD_DECLARE_CLASS(QWindow)
diff --git a/src/Authoring/Studio/Workspace/Dialogs.cpp b/src/Authoring/Studio/Workspace/Dialogs.cpp
index c32d1568..a6e9f605 100644
--- a/src/Authoring/Studio/Workspace/Dialogs.cpp
+++ b/src/Authoring/Studio/Workspace/Dialogs.cpp
@@ -1037,6 +1037,42 @@ QString CDialogs::GetSaveAsChoice(const QString &inDialogTitle, bool isProject,
return theFile;
}
+QString CDialogs::getImportVariantsDlg()
+{
+ QString docDir = QFileInfo(g_StudioApp.GetCore()->GetDoc()->GetDocumentPath()).absolutePath();
+
+ QFileDialog dlg;
+ dlg.setDirectory(docDir);
+ dlg.setWindowTitle(tr("Import variants"));
+ dlg.setDefaultSuffix(QStringLiteral(".variants"));
+ dlg.setNameFilters({tr("All supported files (*.variants *.uia)"),
+ tr("Variants files (*.variants)"), tr("Project files (*.uia)")});
+ dlg.exec();
+
+ if (!dlg.selectedFiles().empty())
+ return dlg.selectedFiles().front();
+
+ return {};
+}
+
+QString CDialogs::getExportVariantsDlg()
+{
+ QString docDir = QFileInfo(g_StudioApp.GetCore()->GetDoc()->GetDocumentPath()).absolutePath();
+
+ QFileDialog dlg;
+ dlg.setDirectory(docDir);
+ dlg.setAcceptMode(QFileDialog::AcceptSave);
+ dlg.setWindowTitle(tr("Export variants"));
+ dlg.setDefaultSuffix(QStringLiteral(".variants"));
+ dlg.setNameFilters({QObject::tr("Variants files (*.variants)")});
+ dlg.exec();
+
+ if (!dlg.selectedFiles().empty())
+ return dlg.selectedFiles().front();
+
+ return {};
+}
+
//==============================================================================
/**
* Prompt the user for a file to create.
@@ -1225,21 +1261,20 @@ void CDialogs::DisplayGLVersionWarning(const Q3DStudio::CString &inGLVersion,
}
void CDialogs::asyncDisplayTimeEditDialog(long time, IDoc *doc, long objectAssociation,
- ITimelineKeyframesManager *keyframesManager) const
+ KeyframeManager *keyframesManager) const
{
QTimer::singleShot(0, [time, doc, objectAssociation, keyframesManager]() {
- CTimeEditDlg timeEditDlg;
- timeEditDlg.setKeyframesManager(keyframesManager);
+ CTimeEditDlg timeEditDlg(keyframesManager);
timeEditDlg.showDialog(time, doc, objectAssociation);
});
}
-void CDialogs::asyncDisplayDurationEditDialog(long startTime, long endTime, IDoc *doc,
+void CDialogs::asyncDisplayDurationEditDialog(long startTime, long endTime,
ITimeChangeCallback *callback) const
{
- QTimer::singleShot(0, [startTime, endTime, doc, callback]() {
+ QTimer::singleShot(0, [startTime, endTime, callback]() {
CDurationEditDlg durationEditDlg;
- durationEditDlg.showDialog(startTime, endTime, doc, callback);
+ durationEditDlg.showDialog(startTime, endTime, callback);
});
}
@@ -1380,8 +1415,8 @@ QStringList CDialogs::qmlStreamExtensions()
QColor CDialogs::displayColorDialog(const QColor &color) const
{
QColorDialog theColorDlg;
- theColorDlg.setCurrentColor(color);
theColorDlg.setOption(QColorDialog::DontUseNativeDialog, true);
+ theColorDlg.setCurrentColor(color);
connect(&theColorDlg, &QColorDialog::currentColorChanged, this, &CDialogs::onColorChanged);
int result = theColorDlg.exec();
disconnect(&theColorDlg, &QColorDialog::currentColorChanged, this, &CDialogs::onColorChanged);
diff --git a/src/Authoring/Studio/Workspace/Dialogs.h b/src/Authoring/Studio/Workspace/Dialogs.h
index d8163eb8..c54f17a1 100644
--- a/src/Authoring/Studio/Workspace/Dialogs.h
+++ b/src/Authoring/Studio/Workspace/Dialogs.h
@@ -55,7 +55,7 @@ class CStudioApp;
class CControl;
class CDialogControl;
class CProgressView;
-class ITimelineKeyframesManager;
+class KeyframeManager;
class ITimeChangeCallback;
class CDialogs : public QObject
@@ -120,6 +120,8 @@ public:
bool isCopy = false);
QString GetNewDocumentChoice(const QString &inInitialDirectory = {}, bool isProject = true);
QString GetFileOpenChoice(const QString &inInitialDirectory = {});
+ QString getExportVariantsDlg();
+ QString getImportVariantsDlg();
void DisplayImportFailed(const QUrl &inURL, const QString &inDescription, bool inWarningsOnly);
void DisplayLoadingPresentationFailed(const QFileInfo &loadFileInfo,
@@ -166,8 +168,8 @@ public:
const Q3DStudio::CString &inRecommendedVersion);
void asyncDisplayTimeEditDialog(long time, IDoc *doc, long objectAssociation,
- ITimelineKeyframesManager *keyframesManager = nullptr) const;
- void asyncDisplayDurationEditDialog(long startTime, long endTime, IDoc *doc,
+ KeyframeManager *keyframesManager = nullptr) const;
+ void asyncDisplayDurationEditDialog(long startTime, long endTime,
ITimeChangeCallback *callback) const;
enum class WidgetBrowserAlign {
diff --git a/src/Authoring/Studio/images.qrc b/src/Authoring/Studio/images.qrc
index e57eee1d..0c6e16f5 100644
--- a/src/Authoring/Studio/images.qrc
+++ b/src/Authoring/Studio/images.qrc
@@ -286,6 +286,29 @@
<file>images/matdef-active@2x.png</file>
<file>images/matdef-disabled.png</file>
<file>images/matdef-disabled@2x.png</file>
+ <file>images/playback_tools_low-04@2x.png</file>
+ <file>images/Action-Action@2x.png</file>
+ <file>images/Action-ChildAction@2x.png</file>
+ <file>images/Action-ChildMasterAction@2x.png</file>
+ <file>images/Action-ComponentAction@2x.png</file>
+ <file>images/Action-ComponentMasterAction@2x.png</file>
+ <file>images/Action-MasterAction@2x.png</file>
+ <file>images/Insert-Left@2x.png</file>
+ <file>images/Insert-Right@2x.png</file>
+ <file>images/Toggle-Empty@2x.png</file>
+ <file>images/keyframe-hidden-normal@2x.png</file>
+ <file>images/Keyframe-MasterDynamic-Selected@2x.png</file>
+ <file>images/Keyframe-MasterDynamic-Normal@2x.png</file>
+ <file>images/Keyframe-MasterDynamic-Disabled@2x.png</file>
+ <file>images/Keyframe-Master-Selected@2x.png</file>
+ <file>images/Keyframe-Master-Normal@2x.png</file>
+ <file>images/Keyframe-Master-Disabled@2x.png</file>
+ <file>images/Keyframe-PropertyDynamic-Selected@2x.png</file>
+ <file>images/Keyframe-PropertyDynamic-Normal@2x.png</file>
+ <file>images/Keyframe-PropertyDynamic-Disabled@2x.png</file>
+ <file>images/Keyframe-Property-Selected@2x.png</file>
+ <file>images/Keyframe-Property-Normal@2x.png</file>
+ <file>images/Keyframe-Property-Disabled@2x.png</file>
</qresource>
<qresource prefix="/startup">
<file alias="open_dialog.png">images/open_dialog.png</file>
diff --git a/src/Authoring/Studio/images/Action-Action@2x.png b/src/Authoring/Studio/images/Action-Action@2x.png
new file mode 100644
index 00000000..affa6c01
--- /dev/null
+++ b/src/Authoring/Studio/images/Action-Action@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Action-ChildAction@2x.png b/src/Authoring/Studio/images/Action-ChildAction@2x.png
new file mode 100644
index 00000000..ba066860
--- /dev/null
+++ b/src/Authoring/Studio/images/Action-ChildAction@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Action-ChildMasterAction@2x.png b/src/Authoring/Studio/images/Action-ChildMasterAction@2x.png
new file mode 100644
index 00000000..f0c8a1da
--- /dev/null
+++ b/src/Authoring/Studio/images/Action-ChildMasterAction@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Action-ComponentAction@2x.png b/src/Authoring/Studio/images/Action-ComponentAction@2x.png
new file mode 100644
index 00000000..26a2c36c
--- /dev/null
+++ b/src/Authoring/Studio/images/Action-ComponentAction@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Action-ComponentMasterAction@2x.png b/src/Authoring/Studio/images/Action-ComponentMasterAction@2x.png
new file mode 100644
index 00000000..fa40fb4b
--- /dev/null
+++ b/src/Authoring/Studio/images/Action-ComponentMasterAction@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Action-MasterAction@2x.png b/src/Authoring/Studio/images/Action-MasterAction@2x.png
new file mode 100644
index 00000000..c3b8e2e5
--- /dev/null
+++ b/src/Authoring/Studio/images/Action-MasterAction@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Insert-Left@2x.png b/src/Authoring/Studio/images/Insert-Left@2x.png
new file mode 100644
index 00000000..ad0696c6
--- /dev/null
+++ b/src/Authoring/Studio/images/Insert-Left@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Insert-Right@2x.png b/src/Authoring/Studio/images/Insert-Right@2x.png
new file mode 100644
index 00000000..d7a20850
--- /dev/null
+++ b/src/Authoring/Studio/images/Insert-Right@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Master-Disabled.png b/src/Authoring/Studio/images/Keyframe-Master-Disabled.png
index 7e66cd27..41c7bbe3 100644
--- a/src/Authoring/Studio/images/Keyframe-Master-Disabled.png
+++ b/src/Authoring/Studio/images/Keyframe-Master-Disabled.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Master-Disabled@2x.png b/src/Authoring/Studio/images/Keyframe-Master-Disabled@2x.png
new file mode 100644
index 00000000..a1291e92
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-Master-Disabled@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Master-Normal.png b/src/Authoring/Studio/images/Keyframe-Master-Normal.png
index 9fb6281b..af88c894 100644
--- a/src/Authoring/Studio/images/Keyframe-Master-Normal.png
+++ b/src/Authoring/Studio/images/Keyframe-Master-Normal.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Master-Normal@2x.png b/src/Authoring/Studio/images/Keyframe-Master-Normal@2x.png
new file mode 100644
index 00000000..503942c8
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-Master-Normal@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Master-Selected.png b/src/Authoring/Studio/images/Keyframe-Master-Selected.png
index 5d3806ba..7e27743c 100644
--- a/src/Authoring/Studio/images/Keyframe-Master-Selected.png
+++ b/src/Authoring/Studio/images/Keyframe-Master-Selected.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Master-Selected@2x.png b/src/Authoring/Studio/images/Keyframe-Master-Selected@2x.png
new file mode 100644
index 00000000..e86bacf5
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-Master-Selected@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled.png
index 734f8e2c..d6abe9f1 100644
--- a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled.png
+++ b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled@2x.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled@2x.png
new file mode 100644
index 00000000..0b90181d
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.png
index 919c310f..6d6dab76 100644
--- a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.png
+++ b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal@2x.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal@2x.png
new file mode 100644
index 00000000..4a1f83fc
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.png
index 7712d96f..6e00aeba 100644
--- a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.png
+++ b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected@2x.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected@2x.png
new file mode 100644
index 00000000..c402defc
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Property-Disabled.png b/src/Authoring/Studio/images/Keyframe-Property-Disabled.png
index 87e5dde9..2bba3f4b 100644
--- a/src/Authoring/Studio/images/Keyframe-Property-Disabled.png
+++ b/src/Authoring/Studio/images/Keyframe-Property-Disabled.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Property-Disabled@2x.png b/src/Authoring/Studio/images/Keyframe-Property-Disabled@2x.png
new file mode 100644
index 00000000..957fb36e
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-Property-Disabled@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Property-Normal.png b/src/Authoring/Studio/images/Keyframe-Property-Normal.png
index 7afc5b09..aaebda90 100644
--- a/src/Authoring/Studio/images/Keyframe-Property-Normal.png
+++ b/src/Authoring/Studio/images/Keyframe-Property-Normal.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Property-Normal@2x.png b/src/Authoring/Studio/images/Keyframe-Property-Normal@2x.png
new file mode 100644
index 00000000..06919fa3
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-Property-Normal@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Property-Selected.png b/src/Authoring/Studio/images/Keyframe-Property-Selected.png
index 7eb45ab3..456a4b90 100644
--- a/src/Authoring/Studio/images/Keyframe-Property-Selected.png
+++ b/src/Authoring/Studio/images/Keyframe-Property-Selected.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Property-Selected@2x.png b/src/Authoring/Studio/images/Keyframe-Property-Selected@2x.png
new file mode 100644
index 00000000..b2008a29
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-Property-Selected@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled.png
index 8f23ea26..84263b0d 100644
--- a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled.png
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled@2x.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled@2x.png
new file mode 100644
index 00000000..229fddf2
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.png
index 2231a10c..733e0718 100644
--- a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.png
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png
new file mode 100644
index 00000000..aa24ccac
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png~ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png~
new file mode 100644
index 00000000..aa24ccac
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png~
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.png
index 02186956..ef1cf1bd 100644
--- a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.png
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected@2x.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected@2x.png
new file mode 100644
index 00000000..ad155725
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Toggle-Empty@2x.png b/src/Authoring/Studio/images/Toggle-Empty@2x.png
new file mode 100644
index 00000000..94c695c6
--- /dev/null
+++ b/src/Authoring/Studio/images/Toggle-Empty@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/keyframe-hidden-normal@2x.png b/src/Authoring/Studio/images/keyframe-hidden-normal@2x.png
new file mode 100644
index 00000000..040d281d
--- /dev/null
+++ b/src/Authoring/Studio/images/keyframe-hidden-normal@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/playback_tools_low-04@2x.png b/src/Authoring/Studio/images/playback_tools_low-04@2x.png
new file mode 100644
index 00000000..0f74d37e
--- /dev/null
+++ b/src/Authoring/Studio/images/playback_tools_low-04@2x.png
Binary files differ
diff --git a/src/Runtime/qt3d-runtime b/src/Runtime/qt3d-runtime
-Subproject 34e028b916fb1d215cdbb20fe1fecb677145cb5
+Subproject 72c4b5fc9d7fde2a2bdf730eab22ffb99b9c2ca
diff --git a/src/shared/header/foundation/ConvertUTF.h b/src/shared/header/foundation/ConvertUTF.h
index 14b88c7c..e5a917bd 100644
--- a/src/shared/header/foundation/ConvertUTF.h
+++ b/src/shared/header/foundation/ConvertUTF.h
@@ -146,25 +146,33 @@ typedef enum { strictConversion = 0, lenientConversion } ConversionFlags;
extern "C" {
#endif
-ConversionResult ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd,
- UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags);
+// Note: Functions renamed from original Unicode functions to avoid conflicting with the same
+// functions in breakpad implementation which is also statically linked
+ConversionResult Unicode_ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd,
+ ConversionFlags flags);
-ConversionResult ConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd,
- UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags);
+ConversionResult Unicode_ConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd,
+ ConversionFlags flags);
-ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd,
- UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags);
+ConversionResult Unicode_ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd,
+ ConversionFlags flags);
-ConversionResult ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd,
- UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags);
+ConversionResult Unicode_ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd,
+ ConversionFlags flags);
-ConversionResult ConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd,
- UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags);
+ConversionResult Unicode_ConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd,
+ ConversionFlags flags);
-ConversionResult ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd,
- UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags);
+ConversionResult Unicode_ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd,
+ ConversionFlags flags);
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
+Boolean Unicode_isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
#ifdef __cplusplus
}
diff --git a/src/shared/header/foundation/StrConvertUTF.h b/src/shared/header/foundation/StrConvertUTF.h
index 678411e2..81428fef 100644
--- a/src/shared/header/foundation/StrConvertUTF.h
+++ b/src/shared/header/foundation/StrConvertUTF.h
@@ -91,7 +91,7 @@ namespace foundation {
UTF16 **targetStart, UTF16 *targetEnd,
ConversionFlags flags)
{
- return ConvertUTF8toUTF16(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ return Unicode_ConvertUTF8toUTF16(sourceStart, sourceEnd, targetStart, targetEnd, flags);
}
};
@@ -102,7 +102,7 @@ namespace foundation {
UTF32 **targetStart, UTF32 *targetEnd,
ConversionFlags flags)
{
- return ConvertUTF8toUTF32(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ return Unicode_ConvertUTF8toUTF32(sourceStart, sourceEnd, targetStart, targetEnd, flags);
}
};
template <>
@@ -111,7 +111,7 @@ namespace foundation {
static ConversionResult Convert(const UTF16 **sourceStart, const UTF16 *sourceEnd,
UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
{
- return ConvertUTF16toUTF8(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ return Unicode_ConvertUTF16toUTF8(sourceStart, sourceEnd, targetStart, targetEnd, flags);
}
};
template <>
@@ -121,7 +121,7 @@ namespace foundation {
UTF32 **targetStart, UTF32 *targetEnd,
ConversionFlags flags)
{
- return ConvertUTF16toUTF32(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ return Unicode_ConvertUTF16toUTF32(sourceStart, sourceEnd, targetStart, targetEnd, flags);
}
};
template <>
@@ -130,7 +130,7 @@ namespace foundation {
static ConversionResult Convert(const UTF32 **sourceStart, const UTF32 *sourceEnd,
UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
{
- return ConvertUTF32toUTF8(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ return Unicode_ConvertUTF32toUTF8(sourceStart, sourceEnd, targetStart, targetEnd, flags);
}
};
template <>
@@ -140,7 +140,7 @@ namespace foundation {
UTF16 **targetStart, UTF16 *targetEnd,
ConversionFlags flags)
{
- return ConvertUTF32toUTF16(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ return Unicode_ConvertUTF32toUTF16(sourceStart, sourceEnd, targetStart, targetEnd, flags);
}
};
diff --git a/src/shared/qt-breakpad/qtcrashhandler/mainwidget.h b/src/shared/qt-breakpad/qtcrashhandler/mainwidget.h
index 4cb00a38..bd727997 100644
--- a/src/shared/qt-breakpad/qtcrashhandler/mainwidget.h
+++ b/src/shared/qt-breakpad/qtcrashhandler/mainwidget.h
@@ -34,7 +34,13 @@
#include <QtWidgets/qwidget.h>
#include <QtCore/qpointer.h>
+#ifdef QT_NAMESPACE
+using namespace QT_NAMESPACE;
+#endif
+
+QT_BEGIN_NAMESPACE
namespace Ui { class MainWidget; }
+QT_END_NAMESPACE
class MainWidget : public QWidget
{
diff --git a/src/shared/source/ConvertUTF.cpp b/src/shared/source/ConvertUTF.cpp
index 14017948..d00040e6 100644
--- a/src/shared/source/ConvertUTF.cpp
+++ b/src/shared/source/ConvertUTF.cpp
@@ -89,7 +89,7 @@ static const UTF32 halfMask = 0x3FFUL;
/* --------------------------------------------------------------------- */
-ConversionResult ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ConversionResult Unicode_ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd,
UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
@@ -141,7 +141,7 @@ ConversionResult ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sou
/* --------------------------------------------------------------------- */
-ConversionResult ConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ConversionResult Unicode_ConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd,
UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
@@ -247,7 +247,7 @@ static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
/* --------------------------------------------------------------------- */
-ConversionResult ConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ConversionResult Unicode_ConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd,
UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
@@ -399,7 +399,7 @@ static Boolean isLegalUTF8(const UTF8 *source, int length)
* Exported function to return whether a UTF-8 sequence is legal or not.
* This is not used here; it's just exported.
*/
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd)
+Boolean Unicode_isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd)
{
int length = trailingBytesForUTF8[*source] + 1;
if (source + length > sourceEnd) {
@@ -410,7 +410,7 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd)
/* --------------------------------------------------------------------- */
-ConversionResult ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ConversionResult Unicode_ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd,
UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
@@ -497,7 +497,7 @@ ConversionResult ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *source
/* --------------------------------------------------------------------- */
-ConversionResult ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ConversionResult Unicode_ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd,
UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
@@ -564,7 +564,7 @@ ConversionResult ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sour
/* --------------------------------------------------------------------- */
-ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ConversionResult Unicode_ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd,
UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;