summaryrefslogtreecommitdiffstats
path: root/src/Authoring/Studio/Palettes
diff options
context:
space:
mode:
Diffstat (limited to 'src/Authoring/Studio/Palettes')
-rw-r--r--src/Authoring/Studio/Palettes/Action/ActionContextMenu.cpp76
-rw-r--r--src/Authoring/Studio/Palettes/Action/ActionContextMenu.h58
-rw-r--r--src/Authoring/Studio/Palettes/Action/ActionModel.cpp225
-rw-r--r--src/Authoring/Studio/Palettes/Action/ActionModel.h77
-rw-r--r--src/Authoring/Studio/Palettes/Action/ActionView.cpp848
-rw-r--r--src/Authoring/Studio/Palettes/Action/ActionView.h201
-rw-r--r--src/Authoring/Studio/Palettes/Action/ActionView.qml426
-rw-r--r--src/Authoring/Studio/Palettes/Action/EventsBrowser.qml163
-rw-r--r--src/Authoring/Studio/Palettes/Action/EventsBrowserView.cpp99
-rw-r--r--src/Authoring/Studio/Palettes/Action/EventsBrowserView.h70
-rw-r--r--src/Authoring/Studio/Palettes/Action/EventsModel.cpp262
-rw-r--r--src/Authoring/Studio/Palettes/Action/EventsModel.h96
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerEmitSignal.qml51
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerFireEvent.qml55
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerGenericBaseColor.qml80
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerGenericCheckbox.qml59
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerGenericColor.qml53
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerGenericText.qml53
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerGoToSlide.qml62
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerMultilineText.qml84
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerProperty.qml255
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseSlider.qml164
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseXYZ.qml91
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerPropertyCombo.qml55
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerPropertySlider.qml64
-rw-r--r--src/Authoring/Studio/Palettes/Action/HandlerPropertyXYZ.qml63
-rw-r--r--src/Authoring/Studio/Palettes/Action/PropertyModel.cpp219
-rw-r--r--src/Authoring/Studio/Palettes/Action/PropertyModel.h80
-rw-r--r--src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.cpp119
-rw-r--r--src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.h99
-rw-r--r--src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.cpp74
-rw-r--r--src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.h52
-rw-r--r--src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.qml88
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ChooserDelegate.qml81
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp592
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.h119
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.cpp56
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.h58
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/FileChooser.qml65
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/FileChooserModel.cpp50
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/FileChooserModel.h46
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/FileChooserView.cpp108
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/FileChooserView.h67
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/GuideInspectable.cpp322
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/GuideInspectable.h86
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/HandlerFilesChooser.qml48
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/HandlerGenericChooser.qml47
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/IEasyInspectorRowListener.h48
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/IInspectableItem.h211
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ImageChooser.qml65
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.cpp49
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.h47
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ImageChooserView.cpp117
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ImageChooserView.h67
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectableBase.cpp38
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectableBase.h67
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp862
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h180
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp429
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h125
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml771
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorGroup.cpp61
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorGroup.h67
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/MeshChooser.qml63
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.cpp64
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.h47
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/MeshChooserView.cpp131
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/MeshChooserView.h68
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectBrowser.qml175
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp117
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.h94
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp336
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h120
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectReference.qml41
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.cpp53
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.h45
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.cpp101
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.h65
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.cpp120
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.h65
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/TextureChooser.qml70
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/TextureChooserView.cpp107
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/TextureChooserView.h67
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.cpp325
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.h77
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.cpp83
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.h78
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.cpp75
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.h92
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.cpp226
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.h60
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.cpp77
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.h66
-rw-r--r--src/Authoring/Studio/Palettes/Master/MasterControl.cpp295
-rw-r--r--src/Authoring/Studio/Palettes/Master/MasterControl.h114
-rw-r--r--src/Authoring/Studio/Palettes/Master/MasterView.cpp154
-rw-r--r--src/Authoring/Studio/Palettes/Master/MasterView.h78
-rw-r--r--src/Authoring/Studio/Palettes/Progress/ProgressCallback.h57
-rw-r--r--src/Authoring/Studio/Palettes/Progress/ProgressControl.cpp133
-rw-r--r--src/Authoring/Studio/Palettes/Progress/ProgressControl.h72
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectContextMenu.cpp81
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectContextMenu.h53
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp587
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.h107
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectView.cpp250
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectView.h102
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectView.qml231
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideContextMenu.cpp71
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideContextMenu.h53
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideModel.cpp273
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideModel.h81
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideView.cpp315
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideView.h113
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideView.qml249
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.cpp64
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.h53
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.cpp440
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.h110
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/BaseStateRow.cpp1139
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/BaseStateRow.h205
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.cpp186
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.h80
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.cpp685
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.h125
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.cpp65
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.h61
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.cpp115
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.h66
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.cpp115
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.h63
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/IKeyframeSelector.h52
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItem.h73
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h190
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemProperty.h81
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h55
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineTimebar.h74
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.cpp97
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.h78
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.cpp506
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.h108
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.cpp317
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.h77
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.cpp336
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.h83
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.cpp73
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.h65
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/PasteKeyframesCommandHelper.h118
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.cpp44
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.h69
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.cpp58
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.h65
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.cpp104
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.h121
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.cpp239
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.h74
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.cpp599
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.h160
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.cpp80
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.h69
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimeline.h42
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.cpp1260
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.h225
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.cpp579
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.h119
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.cpp213
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.h84
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.cpp263
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.h90
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.cpp169
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.h65
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.cpp86
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.h60
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ColorControl.cpp307
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ColorControl.h98
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/CommentEdit.cpp231
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/CommentEdit.h77
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.cpp309
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.h107
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/FilterToolbar.cpp271
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/FilterToolbar.h80
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/IBreadCrumbProvider.h72
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ITimelineControl.h53
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.cpp405
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.h154
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.cpp30
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.h149
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Playhead.cpp266
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Playhead.h82
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.cpp89
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.h55
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.cpp152
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.h73
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyRow.cpp377
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyRow.h102
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.cpp234
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.h70
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.cpp508
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.h103
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.cpp374
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.h95
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.cpp110
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.h58
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.cpp190
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.h68
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ScalableScroller.cpp78
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ScalableScroller.h57
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.cpp359
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.h112
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/SlideRow.cpp124
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/SlideRow.h63
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.cpp78
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.h60
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Snapper.cpp455
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Snapper.h118
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/StateRow.cpp311
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/StateRow.h90
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/StateRowFactory.cpp60
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/StateRowFactory.h50
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.cpp156
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.h67
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.cpp364
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.h87
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.cpp49
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.h51
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimeMeasure.cpp340
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimeMeasure.h74
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimeToolbar.cpp135
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimeToolbar.h75
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimebarControl.cpp690
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimebarControl.h144
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimebarTip.cpp235
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimebarTip.h84
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineControl.cpp587
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineControl.h158
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineFilter.cpp246
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineFilter.h84
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.cpp75
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.h57
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineRow.cpp170
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineRow.h87
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.cpp67
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.h56
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp713
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.h153
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.cpp360
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.h122
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.cpp86
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.h60
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ToggleControl.cpp171
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ToggleControl.h63
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.cpp205
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.h82
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.cpp83
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.h63
-rw-r--r--src/Authoring/Studio/Palettes/controls/BrowserCombo.qml79
-rw-r--r--src/Authoring/Studio/Palettes/controls/FloatTextField.qml98
-rw-r--r--src/Authoring/Studio/Palettes/controls/StyledComboBox.qml155
-rw-r--r--src/Authoring/Studio/Palettes/controls/StyledLabel.qml41
-rw-r--r--src/Authoring/Studio/Palettes/controls/StyledMenuItem.qml48
-rw-r--r--src/Authoring/Studio/Palettes/controls/StyledMenuSeparator.qml45
-rw-r--r--src/Authoring/Studio/Palettes/controls/StyledTextField.qml59
-rw-r--r--src/Authoring/Studio/Palettes/controls/StyledToolButton.qml54
-rw-r--r--src/Authoring/Studio/Palettes/controls/StyledTooltip.qml44
263 files changed, 41225 insertions, 0 deletions
diff --git a/src/Authoring/Studio/Palettes/Action/ActionContextMenu.cpp b/src/Authoring/Studio/Palettes/Action/ActionContextMenu.cpp
new file mode 100644
index 00000000..d2957e8b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/ActionContextMenu.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2005 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+#include "Strings.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "ActionContextMenu.h"
+#include "StudioClipboard.h"
+
+//==============================================================================
+/**
+ * Constructor
+ *
+ * @param inActionControl Owner Action Control (commonly known as the Action Palette)
+ *that will handle all cut/copy/paste/delete of Actions.
+ */
+CActionContextMenu::CActionContextMenu(QWidget *parent)
+ : QMenu(parent)
+{
+ QAction *action = new QAction(tr("Copy Action"));
+ connect(action, &QAction::triggered, this, &CActionContextMenu::copyAction);
+ addAction(action);
+
+ action = new QAction(tr("Paste Action"));
+ action->setEnabled(CStudioClipboard::CanPasteAction());
+ connect(action, &QAction::triggered, this, &CActionContextMenu::pasteAction);
+ addAction(action);
+
+ action = new QAction(tr("Cut Action"));
+ connect(action, &QAction::triggered, this, &CActionContextMenu::cutAction);
+ addAction(action);
+
+ action = new QAction(tr("Delete Action"));
+ connect(action, &QAction::triggered, this, &CActionContextMenu::deleteAction);
+ addAction(action);
+}
+
+//==============================================================================
+/**
+ * Destructor
+ */
+CActionContextMenu::~CActionContextMenu()
+{
+}
diff --git a/src/Authoring/Studio/Palettes/Action/ActionContextMenu.h b/src/Authoring/Studio/Palettes/Action/ActionContextMenu.h
new file mode 100644
index 00000000..f413232d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/ActionContextMenu.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2005 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_ACTION_CONTEXT_MENU_H
+#define INCLUDED_ACTION_CONTEXT_MENU_H 1
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include <QMenu>
+
+//==============================================================================
+/**
+ * Context menu that springs up on right mouseclick in the Action Palette.
+ */
+class CActionContextMenu : public QMenu
+{
+ Q_OBJECT
+public:
+ explicit CActionContextMenu(QWidget *parent = nullptr);
+ virtual ~CActionContextMenu();
+
+Q_SIGNALS:
+ void cutAction();
+ void copyAction();
+ void pasteAction();
+ void deleteAction();
+};
+#endif // INCLUDED_ACTION_CONTEXT_MENU_H
diff --git a/src/Authoring/Studio/Palettes/Action/ActionModel.cpp b/src/Authoring/Studio/Palettes/Action/ActionModel.cpp
new file mode 100644
index 00000000..249aa636
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/ActionModel.cpp
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ActionModel.h"
+
+#include "stdafx.h"
+#include "ClientDataModelBridge.h"
+#include "CmdDataModelActionSetValue.h"
+#include "Core.h"
+#include "Doc.h"
+#include "StudioApp.h"
+#include "UICDMActionSystem.h"
+#include "UICDMStudioSystem.h"
+
+ActionModel::ActionModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+}
+
+void ActionModel::setInstanceHandle(const UICDM::CUICDMInstanceHandle &handle)
+{
+ beginResetModel();
+ m_handle = handle;
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ m_actions.clear();
+ doc->GetStudioSystem()->GetActionSystem()->GetActions(doc->GetActiveSlide(),
+ handle, m_actions);
+
+ endResetModel();
+}
+
+QHash<int, QByteArray> ActionModel::roleNames() const
+{
+ auto names = QAbstractItemModel::roleNames();
+ names.insert(DescriptionRole, "description");
+ names.insert(VisibleRole, "visible");
+
+ return names;
+}
+
+
+int ActionModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return m_actions.size();
+}
+
+QVariant ActionModel::data(const QModelIndex &index, int role) const
+{
+ if (!hasIndex(index.row(), index.column(), index.parent()))
+ return {};
+
+ const auto action = m_actions.at(index.row());
+ switch (role)
+ {
+ case DescriptionRole:
+ return actionString(action);
+ case VisibleRole:
+ return actionSystem()->GetActionEyeballValue(activeSlide(), action);
+ default:
+ return {};
+ }
+
+ return {};
+}
+
+bool ActionModel::setData(const QModelIndex &index, const QVariant &data, int role)
+{
+ if (!hasIndex(index.row(), index.column(), index.parent()))
+ return false;
+
+ const auto action = m_actions.at(index.row());
+
+ if (role == VisibleRole) {
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ CCmd *theCmd = new CCmdDataModelActionSetEyeball(doc, activeSlide(), action, data.toBool());
+ g_StudioApp.GetCore()->ExecuteCommand(theCmd);
+ Q_EMIT dataChanged(index, index, {VisibleRole});
+ }
+
+
+ return false;
+}
+
+void ActionModel::addAction(const CUICDMActionHandle &action)
+{
+ if (std::find(m_actions.begin(), m_actions.end(), action) == m_actions.end()) {
+ const auto count = rowCount();
+ beginInsertRows({}, count, count);
+ m_actions.push_back(action);
+ endInsertRows();
+ }
+}
+
+void ActionModel::removeAction(const CUICDMActionHandle &action)
+{
+ // KDAB_FIXME use beginRemoveRows
+ beginResetModel();
+ m_actions.erase(std::remove(m_actions.begin(), m_actions.end(), action), m_actions.end());
+ endResetModel();
+}
+
+void ActionModel::updateAction(const CUICDMActionHandle &action)
+{
+ for (unsigned i = 0; i < m_actions.size(); i++) {
+ if (m_actions[i] == action) {
+ auto idx = index(i, 0);
+ Q_EMIT dataChanged(idx, idx, {});
+ }
+ }
+}
+
+const CUICDMActionHandle ActionModel::actionAt(int row)
+{
+ if (row >= 0 && static_cast<unsigned>(row) < m_actions.size())
+ return m_actions[row];
+
+ return {};
+}
+
+const SActionInfo ActionModel::actionInfoAt(int row)
+{
+ const auto action = actionAt(row);
+ if (!action.Valid())
+ return {};
+ auto actionCore = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetActionCore();
+ return actionCore->GetActionInfo(action);
+}
+
+UICDM::IActionSystem *ActionModel::actionSystem() const
+{
+ return g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetActionSystem();
+}
+
+UICDM::CUICDMSlideHandle ActionModel::activeSlide() const
+{
+ return g_StudioApp.GetCore()->GetDoc()->GetActiveSlide();
+}
+
+QString ActionModel::actionString(const CUICDMActionHandle &action) const
+{
+ QString result;
+ if (action.Valid()) {
+ auto core = g_StudioApp.GetCore();
+ auto doc = core->GetDoc();
+ auto actionCore = doc->GetStudioSystem()->GetActionCore();
+ auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+
+ const SActionInfo &actionInfo = actionCore->GetActionInfo(action);
+
+ // Query the event name
+ QString eventFormalName(tr("[Unknown Event]"));
+ CUICDMEventHandle eventHandle = bridge->ResolveEvent(actionInfo);
+ if (eventHandle.Valid())
+ eventFormalName =
+ QString::fromWCharArray(bridge->GetEventInfo(eventHandle).m_FormalName.wide_str());
+
+ // Query the asset name
+ QString assetName = tr("[Unknown]");
+ assetName = bridge->GetName(actionInfo.m_Owner).toQString();
+
+ const auto sourceInstance =
+ bridge->GetInstance(actionInfo.m_Owner, actionInfo.m_TriggerObject);
+ const auto targetInstance =
+ bridge->GetInstance(actionInfo.m_Owner, actionInfo.m_TargetObject);
+ QString sourceName = sourceInstance.Valid()
+ ? bridge->GetName(sourceInstance).toQString()
+ : tr("[Unknown Source]");
+ QString targetName = targetInstance.Valid()
+ ? bridge->GetName(targetInstance).toQString()
+ : tr("[Unknown Target]");
+
+ // Query the action name
+ QString handlerFormalName(tr("[Unknown Handler]"));
+ const auto handlerHandle = bridge->ResolveHandler(actionInfo);
+ if (handlerHandle.Valid())
+ handlerFormalName = QString::fromWCharArray(bridge->GetHandlerInfo(handlerHandle).m_FormalName.wide_str());
+
+ // Format the strings
+ if (actionInfo.m_Owner == sourceInstance) {
+ if (sourceInstance == targetInstance) {
+ result = tr("Listen for '%1', '%2'").arg(eventFormalName, handlerFormalName);
+ } else {
+ result = tr("Listen for '%1', tell %2 to '%3'").arg(eventFormalName, targetName,
+ handlerFormalName);
+ }
+ } else if (actionInfo.m_Owner == targetInstance) {
+ result = tr("Listen to '%1' for '%2', '%3'").arg(sourceName, eventFormalName,
+ handlerFormalName);
+ } else {
+ result = tr("Listen to '%1' for '%2', tell %3 to '%4'").arg(sourceName,
+ eventFormalName,
+ targetName,
+ handlerFormalName);
+ }
+ }
+ return result;
+}
diff --git a/src/Authoring/Studio/Palettes/Action/ActionModel.h b/src/Authoring/Studio/Palettes/Action/ActionModel.h
new file mode 100644
index 00000000..89a4586d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/ActionModel.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ACTIONMODEL_H
+#define ACTIONMODEL_H
+
+#include <QAbstractListModel>
+
+#include "UICDMActionInfo.h"
+#include "UICDMHandles.h"
+
+namespace UICDM {
+ class IActionSystem;
+}
+
+class ActionModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ explicit ActionModel(QObject *parent = nullptr);
+
+ void setInstanceHandle(const UICDM::CUICDMInstanceHandle &handle);
+
+ enum Roles {
+ DescriptionRole = Qt::DisplayRole,
+ VisibleRole = Qt::UserRole + 1,
+
+ };
+
+ QHash<int, QByteArray> roleNames() const override;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ bool setData(const QModelIndex &index, const QVariant &data, int role = Qt::EditRole) override;
+
+ void addAction(const UICDM::CUICDMActionHandle &action);
+ void removeAction(const UICDM::CUICDMActionHandle &action);
+ void updateAction(const UICDM::CUICDMActionHandle &action);
+ const UICDM::CUICDMActionHandle actionAt(int row);
+ const UICDM::SActionInfo actionInfoAt(int row);
+
+private:
+ UICDM::IActionSystem *actionSystem() const;
+ UICDM::CUICDMSlideHandle activeSlide() const;
+ QString actionString(const UICDM::CUICDMActionHandle &action) const;
+
+ UICDM::CUICDMInstanceHandle m_handle;
+ UICDM::TActionHandleList m_actions;
+};
+
+#endif // ACTIONMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Action/ActionView.cpp b/src/Authoring/Studio/Palettes/Action/ActionView.cpp
new file mode 100644
index 00000000..4aace20a
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/ActionView.cpp
@@ -0,0 +1,848 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ActionView.h"
+#include "ActionContextMenu.h"
+#include "ActionModel.h"
+#include "CmdDataModelActionSetValue.h"
+#include "ClientDataModelBridge.h"
+#include "Core.h"
+#include "Dispatch.h"
+#include "Doc.h"
+#include "IDocumentEditor.h"
+#include "IDocumentReader.h"
+#include "IObjectReferenceHelper.h"
+#include "Literals.h"
+#include "ObjectListModel.h"
+#include "StudioUtils.h"
+#include "StudioApp.h"
+#include "StudioClipboard.h"
+#include "StudioObjectTypes.h"
+#include "StudioPreferences.h"
+#include "UICFileTools.h"
+#include "UICDMActionCore.h"
+#include "UICDMDataTypes.h"
+#include "UICDMSlides.h"
+
+#include <QCoreApplication>
+#include <QQmlContext>
+#include <QQmlEngine>
+#include <QTimer>
+
+ActionView::ActionView(QWidget *parent)
+ : QQuickWidget(parent)
+ , TabNavigable()
+ , m_actionsModel(new ActionModel(this))
+{
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QTimer::singleShot(0, this, &ActionView::initialize);
+
+ g_StudioApp.GetCore()->GetDispatch()->AddPresentationChangeListener(this);
+
+ connect(this, &ActionView::actionChanged, this, [this] {
+ if (!m_propertyModel)
+ m_propertyModel = new PropertyModel(this);
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ if (actionInfo.m_Handler == L"Set Property") {
+ m_currentPropertyNameHandle = actionInfo.m_HandlerArgs.at(0);
+ m_currentPropertyValueHandle = actionInfo.m_HandlerArgs.at(1);
+ m_propertyModel->setAction(m_actionsModel->actionAt(m_currentActionIndex));
+ m_propertyModel->setNameHandle(m_currentPropertyNameHandle);
+ m_propertyModel->setValueHandle(m_currentPropertyValueHandle);
+
+ Q_EMIT propertyModelChanged();
+ }
+
+ });
+
+ m_actionChangedCompressionTimer.setInterval(500);
+ m_actionChangedCompressionTimer.setSingleShot(true);
+ connect(&m_actionChangedCompressionTimer, &QTimer::timeout, this, [this] {
+ updateHandlerArguments();
+ updateFiredEvent();
+ Q_EMIT actionChanged();
+ });
+}
+
+ActionView::~ActionView()
+{
+ m_connections.clear();
+}
+
+QSize ActionView::sizeHint() const
+{
+ return {500, 500};
+}
+
+void ActionView::setItem(const UICDM::CUICDMInstanceHandle &handle)
+{
+ m_objRefHelper = GetDoc()->GetDataModelObjectReferenceHelper();
+ m_itemHandle = handle;
+ m_actionsModel->setInstanceHandle(handle);
+ emitActionChanged();
+ Q_EMIT itemChanged();
+}
+
+QString ActionView::itemIcon() const
+{
+ if (!m_itemHandle.Valid())
+ return {};
+
+ auto info = m_objRefHelper->GetInfo(m_itemHandle);
+ return CStudioObjectTypes::GetNormalIconName(info.m_Type);
+}
+
+QString ActionView::itemText() const
+{
+ if (!m_itemHandle.Valid())
+ return tr("No Object Selected");
+
+ const auto data = m_objRefHelper->GetInfo(m_itemHandle);
+ return data.m_Name.toQString();
+}
+
+QColor ActionView::itemColor() const
+{
+ if (!m_itemHandle.Valid())
+ return Qt::white;
+
+ auto info = m_objRefHelper->GetInfo(m_itemHandle);
+ if (info.m_Master)
+ return CStudioPreferences::masterColor();
+ else
+ return CStudioPreferences::textColor();
+}
+
+QAbstractItemModel *ActionView::actionsModel() const
+{
+ return m_actionsModel;
+}
+
+QAbstractItemModel *ActionView::propertyModel() const
+{
+ return m_propertyModel;
+}
+
+QString ActionView::targetObjectName() const
+{
+ if (!GetDoc()->IsValid())
+ return {};
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+
+ const auto targetInstance =
+ GetBridge()->GetInstance(actionInfo.m_Owner, actionInfo.m_TargetObject);
+
+ QString targetName = targetInstance.Valid()
+ ? GetBridge()->GetName(targetInstance).toQString()
+ : tr("[Unknown Target]");
+
+ return targetName;
+}
+
+QString ActionView::triggerObjectName() const
+{
+ if (!GetDoc()->IsValid())
+ return {};
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+
+ const auto sourceInstance =
+ GetBridge()->GetInstance(actionInfo.m_Owner, actionInfo.m_TriggerObject);
+
+ QString sourceName = sourceInstance.Valid()
+ ? GetBridge()->GetName(sourceInstance).toQString()
+ : tr("[Unknown Source]");
+
+ return sourceName;
+}
+
+QString ActionView::eventName() const
+{
+ if (!GetDoc()->IsValid())
+ return {};
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto bridge = GetBridge();
+ const auto eventHandle = bridge->ResolveEvent(actionInfo);
+ const auto eventInfo = bridge->GetEventInfo(eventHandle);
+
+ const QString formalName = QString::fromWCharArray(eventInfo.m_FormalName.wide_str());
+ return formalName.isEmpty() ? tr("[Unknown Event]") : formalName;
+}
+
+QString ActionView::handlerName() const
+{
+ if (!GetDoc()->IsValid())
+ return {};
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto bridge = GetBridge();
+ const auto handlerHandle = bridge->ResolveHandler(actionInfo);
+
+ if (handlerHandle.Valid()) {
+ const auto handlerInfo = bridge->GetHandlerInfo(handlerHandle);
+ return QString::fromWCharArray(handlerInfo.m_FormalName.wide_str());
+ }
+
+ return tr("[Unknown Handler]");
+}
+
+QVariantList ActionView::handlerArguments() const
+{
+ return m_handlerArguments;
+}
+
+PropertyInfo ActionView::property() const
+{
+ if (!m_propertyModel)
+ return {};
+ return m_propertyModel->property(m_currentPropertyIndex);
+}
+
+void ActionView::setCurrentActionIndex(int index)
+{
+ if (index == m_currentActionIndex)
+ return;
+
+ m_currentActionIndex = index;
+ emitActionChanged();
+}
+
+void ActionView::setCurrentPropertyIndex(int handle, int index)
+{
+ if (index == m_currentPropertyIndex)
+ return;
+
+ m_currentPropertyValueHandle = 0;
+ m_currentPropertyNameHandle = handle;
+ for (int i = 0; i < m_handlerArguments.size(); ++i) {
+ auto handlerArg = m_handlerArguments[i].value<HandlerArgument>();
+ if (handlerArg.m_handle.GetHandleValue() == handle && i < m_handlerArguments.size() - 1) {
+ m_currentPropertyValueHandle = m_handlerArguments[i + 1].value<HandlerArgument>().m_handle;
+ if (m_propertyModel) {
+ m_propertyModel->setNameHandle(m_currentPropertyNameHandle);
+ m_propertyModel->setValueHandle(m_currentPropertyValueHandle);
+ }
+ }
+ }
+
+ m_currentPropertyIndex = index;
+
+ // set the property for the handler
+ if (m_propertyModel && handle != 0) {
+ UICDM::SValue sValue(QVariant(m_propertyModel->property(index).m_nameId));
+ UICDM::SValue oldValue;
+ GetDoc()->GetStudioSystem()->GetActionCore()->GetHandlerArgumentValue(handle, oldValue);
+
+ if (!Equals(oldValue, sValue)) {
+ CCmd *theCmd =
+ new CCmdDataModelActionSetArgumentValue(GetDoc(), handle, sValue);
+ g_StudioApp.GetCore()->ExecuteCommand(theCmd);
+ }
+ }
+
+ Q_EMIT propertyChanged();
+}
+
+void ActionView::addAction()
+{
+ if (m_itemHandle.Valid()) {
+ // Query data model bridge to see the applicable events and actions for this instance.
+ CClientDataModelBridge *theBridge = GetBridge();
+
+ std::wstring theEventName = theBridge->GetDefaultEvent(m_itemHandle);
+ std::wstring theHandlerName = theBridge->GetDefaultHandler(m_itemHandle);
+
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Add Action"))
+ ->AddAction(GetDoc()->GetActiveSlide(), m_itemHandle, theEventName,
+ theHandlerName);
+ }
+}
+
+void ActionView::deleteAction(int index)
+{
+ const auto action = m_actionsModel->actionAt(index);
+ if (action.Valid()) {
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Delete Action"))->DeleteAction(action);
+ }
+}
+
+QObject *ActionView::showTriggerObjectBrowser(const QPoint &point)
+{
+ if (!m_objectsModel) {
+ m_objectsModel = new ObjectListModel(g_StudioApp.GetCore(),
+ GetDoc()->GetActiveRootInstance(), this);
+ }
+
+ if (!m_triggerObjectBrowser)
+ m_triggerObjectBrowser = new ObjectBrowserView(this);
+
+ m_triggerObjectBrowser->setModel(m_objectsModel);
+
+ showBrowser(m_triggerObjectBrowser, point);
+
+ connect(m_triggerObjectBrowser, &ObjectBrowserView::selectionChanged,
+ this, [this] {
+ auto selectedItem = m_triggerObjectBrowser->selectedHandle();
+ setTriggerObject(m_objRefHelper->GetAssetRefValue(selectedItem,
+ m_itemHandle,
+ (CRelativePathTools::EPathType)(m_triggerObjectBrowser->pathType())));
+ });
+
+ return m_triggerObjectBrowser;
+}
+
+QObject *ActionView::showTargetObjectBrowser(const QPoint &point)
+{
+ if (!m_objectsModel) {
+ m_objectsModel = new ObjectListModel(g_StudioApp.GetCore(),
+ GetDoc()->GetActiveRootInstance(), this);
+ }
+
+ if (!m_targetObjectBrowser)
+ m_targetObjectBrowser = new ObjectBrowserView(this);
+
+ m_targetObjectBrowser->setModel(m_objectsModel);
+
+ showBrowser(m_targetObjectBrowser, point);
+
+ connect(m_targetObjectBrowser, &ObjectBrowserView::selectionChanged,
+ this, [this] {
+ auto selectedItem = m_targetObjectBrowser->selectedHandle();
+ setTargetObject(m_objRefHelper->GetAssetRefValue(selectedItem,
+ m_itemHandle,
+ (CRelativePathTools::EPathType)(m_targetObjectBrowser->pathType())));
+ resetFiredEvent();
+ });
+
+ return m_targetObjectBrowser;
+}
+
+void ActionView::showContextMenu(int x, int y)
+{
+ CActionContextMenu contextMenu(this);
+
+ connect(&contextMenu, &CActionContextMenu::copyAction, this, &ActionView::copyAction);
+ connect(&contextMenu, &CActionContextMenu::pasteAction, this, &ActionView::pasteAction);
+ connect(&contextMenu, &CActionContextMenu::cutAction, this, &ActionView::cutAction);
+ connect(&contextMenu, &CActionContextMenu::deleteAction, this, [this] {
+ deleteAction(m_currentActionIndex);
+ });
+
+ contextMenu.exec(mapToGlobal({x, y}));
+}
+
+QObject *ActionView::showEventBrowser(const QPoint &point)
+{
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto bridge = GetBridge();
+ const auto instanceHandle = bridge->GetInstance(actionInfo.m_Owner, actionInfo.m_TriggerObject);
+
+ if (!instanceHandle.Valid())
+ return nullptr;
+
+ if (!m_eventsModel) {
+ m_eventsModel = new EventsModel(this);
+ }
+
+ UICDM::TEventHandleList eventList;
+ bridge->GetEvents(instanceHandle, eventList);
+ m_eventsModel->setEventList(eventList);
+
+ if (!m_eventsBrowser)
+ m_eventsBrowser = new EventsBrowserView(this);
+
+ m_eventsBrowser->setModel(m_eventsModel);
+
+ showBrowser(m_eventsBrowser, point);
+
+ connect(m_eventsBrowser, &EventsBrowserView::selectionChanged,
+ this, [this] {
+ setEvent(UICDM::CUICDMEventHandle(m_eventsBrowser->selectedHandle()));
+ });
+
+ return m_eventsBrowser;
+}
+
+QObject *ActionView::showHandlerBrowser(const QPoint &point)
+{
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto bridge = GetBridge();
+ const auto instanceHandle = bridge->GetInstance(actionInfo.m_Owner, actionInfo.m_TargetObject);
+
+ if (!instanceHandle.Valid())
+ return nullptr;
+
+ if (!m_handlersModel) {
+ m_handlersModel = new EventsModel(this);
+ }
+
+ UICDM::THandlerHandleList handlerList;
+ bridge->GetHandlers(instanceHandle, handlerList);
+ m_handlersModel->setHandlerList(handlerList);
+
+ if (!m_handlerBrowser)
+ m_handlerBrowser = new EventsBrowserView(this);
+
+ m_handlerBrowser->setModel(m_handlersModel);
+
+ showBrowser(m_handlerBrowser, point);
+
+ connect(m_handlerBrowser, &EventsBrowserView::selectionChanged,
+ this, [this] {
+ setHandler(UICDM::CUICDMHandlerHandle(m_handlerBrowser->selectedHandle()));
+ });
+
+ return m_handlerBrowser;
+}
+
+QObject *ActionView::showEventBrowserForArgument(int handle, const QPoint &point)
+{
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto bridge = GetBridge();
+ const auto instanceHandle = bridge->GetInstance(actionInfo.m_Owner, actionInfo.m_TargetObject);
+
+ if (!instanceHandle.Valid())
+ return nullptr;
+
+ if (!m_fireEventsModel) {
+ m_fireEventsModel = new EventsModel(this);
+ }
+
+ UICDM::TEventHandleList eventList;
+ bridge->GetEvents(instanceHandle, eventList);
+ m_fireEventsModel->setEventList(eventList);
+
+ if (!m_fireEventsBrowser)
+ m_fireEventsBrowser = new EventsBrowserView(this);
+
+ m_fireEventsBrowser->setModel(m_fireEventsModel);
+
+ showBrowser(m_fireEventsBrowser, point);
+
+ connect(m_fireEventsBrowser, &EventsBrowserView::selectionChanged,
+ this, [this, handle] {
+ setArgumentValue(handle, UICDM::CUICDMEventHandle(m_fireEventsBrowser->selectedHandle()).GetHandleValue());
+ });
+
+ return m_fireEventsBrowser;
+}
+
+void ActionView::showBrowser(QQuickWidget *browser, const QPoint &point)
+{
+ QSize popupSize = CStudioPreferences::browserPopupSize();
+ browser->disconnect();
+ browser->resize(popupSize);
+ browser->move(point - QPoint(popupSize.width(), popupSize.height()));
+
+ // Show asynchronously to avoid flashing blank window on first show
+ QTimer::singleShot(0, this, [browser] {
+ browser->show();
+ browser->activateWindow();
+ browser->setFocus();
+ });
+}
+
+void ActionView::updateFiredEvent()
+{
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ if (actionInfo.m_Handler != L"Fire Event") {
+ m_firedEvent = tr("[Unknown event]");
+ return;
+ }
+
+ const auto doc = GetDoc();
+ if (!doc->IsValid())
+ return;
+
+ const auto bridge = GetBridge();
+ const auto handlerHandle = bridge->ResolveHandler(actionInfo);
+ IActionCore *actionCore = doc->GetStudioSystem()->GetActionCore();
+
+ if (handlerHandle.Valid()) {
+ for (const auto &argHandle: actionInfo.m_HandlerArgs) {
+ const auto &argumentInfo = actionCore->GetHandlerArgumentInfo(argHandle);
+ DataModelDataType::Value theArgType(GetValueType(argumentInfo.m_Value));
+ SValue theArgValue(argumentInfo.m_Value);
+ if (argumentInfo.m_ArgType == HandlerArgumentType::Event) {
+ theArgType = DataModelDataType::String;
+ auto theEventHandle = get<qt3ds::QT3DSI32>(argumentInfo.m_Value);
+ theArgValue = SValue(std::make_shared<CDataStr>(
+ bridge->GetEventInfo(theEventHandle).m_Name.wide_str()));
+ m_firedEvent = theArgValue.toQVariant().toString();
+ Q_EMIT firedEventChanged();
+ }
+ }
+ }
+}
+
+void ActionView::updateFiredEventFromHandle(int handle)
+{
+ m_firedEvent = QString::fromWCharArray(GetBridge()->GetEventInfo(handle).m_FormalName.wide_str());
+ Q_EMIT firedEventChanged();
+}
+
+void ActionView::resetFiredEvent()
+{
+ m_firedEvent = tr("[Unknown Event]");
+ Q_EMIT firedEventChanged();
+}
+
+void ActionView::OnNewPresentation()
+{
+ // Register callback
+ UICDM::IStudioFullSystemSignalProvider *theSignalProvider =
+ g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetFullSystemSignalProvider();
+ m_connections.push_back(theSignalProvider->ConnectActionCreated(
+ std::bind(&ActionView::OnActionAdded, this, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3)));
+ m_connections.push_back(theSignalProvider->ConnectActionDeleted(
+ std::bind(&ActionView::OnActionDeleted, this, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3)));
+ m_connections.push_back(theSignalProvider->ConnectTriggerObjectSet(
+ std::bind(&ActionView::OnActionModified, this, std::placeholders::_1)));
+ m_connections.push_back(theSignalProvider->ConnectTargetObjectSet(
+ std::bind(&ActionView::OnActionModified, this, std::placeholders::_1)));
+ m_connections.push_back(theSignalProvider->ConnectEventSet(
+ std::bind(&ActionView::OnActionModified, this, std::placeholders::_1)));
+ m_connections.push_back(theSignalProvider->ConnectHandlerSet(
+ std::bind(&ActionView::OnActionModified, this, std::placeholders::_1)));
+ m_connections.push_back(theSignalProvider->ConnectHandlerArgumentValueSet(
+ std::bind(&ActionView::OnHandlerArgumentModified, this, std::placeholders::_1)));
+ m_connections.push_back(theSignalProvider->ConnectInstancePropertyValue(
+ std::bind(&ActionView::OnInstancePropertyValueChanged, this, std::placeholders::_1,
+ std::placeholders::_2)));
+ CDispatch *theDispatch = g_StudioApp.GetCore()->GetDispatch();
+ m_connections.push_back(theDispatch->ConnectSelectionChange(
+ std::bind(&ActionView::OnSelectionSet, this,
+ std::placeholders::_1)));
+}
+
+void ActionView::OnSelectionSet(Q3DStudio::SSelectedValue inSelectable)
+{
+ UICDM::CUICDMInstanceHandle theInstance;
+ std::vector<UICDM::CUICDMInstanceHandle> instances;
+
+ switch (inSelectable.getType()) {
+ case Q3DStudio::SelectedValueTypes::Instance:
+ theInstance = inSelectable.getData<UICDM::CUICDMInstanceHandle>();
+ break;
+ case Q3DStudio::SelectedValueTypes::MultipleInstances:
+ instances = inSelectable.getData<std::vector<UICDM::CUICDMInstanceHandle>>();
+ // handling only if we have one selected element.
+ if (instances.size() == 1)
+ theInstance = instances[0];
+ break;
+ case Q3DStudio::SelectedValueTypes::Slide: {
+ UICDM::CUICDMSlideHandle theSlideHandle =
+ inSelectable.getData<Q3DStudio::SSlideInstanceWrapper>().m_Slide;
+ // Get the owning component instance
+ CClientDataModelBridge *theBridge = GetBridge();
+ UICDM::SLong4 theComponentGuid = theBridge->GetComponentGuid(theSlideHandle);
+ Q_ASSERT(GuidValid(theComponentGuid));
+ theInstance = theBridge->GetInstanceByGUID(theComponentGuid);
+ Q_ASSERT(theInstance.Valid());
+ } break;
+ };
+
+ setItem(theInstance);
+}
+
+void ActionView::OnActionAdded(UICDM::CUICDMActionHandle inAction, UICDM::CUICDMSlideHandle inSlide, UICDM::CUICDMInstanceHandle inOwner)
+{
+ CDoc *theDoc = GetDoc();
+ UICDM::CStudioSystem *theStudioSystem = theDoc->GetStudioSystem();
+
+ UICDM::CUICDMSlideHandle theCurrentSlide = theDoc->GetActiveSlide();
+ UICDM::CUICDMSlideHandle theMasterSlideOfAction =
+ theStudioSystem->GetSlideSystem()->GetMasterSlide(inSlide);
+ UICDM::CUICDMSlideHandle theMasterOfCurrentSlide =
+ theStudioSystem->GetSlideSystem()->GetMasterSlide(theCurrentSlide);
+
+ if (inOwner == m_itemHandle && // the action is added to current viewed instance
+ (theCurrentSlide == inSlide || // and is added to the current viewed slide
+ (theMasterSlideOfAction == inSlide
+ && theMasterOfCurrentSlide == theMasterSlideOfAction))) // or it is added to the master of
+ // the current viewed slide
+ {
+ m_actionsModel->addAction(inAction);
+// KDAB_TODO SortActions();
+ }
+}
+
+void ActionView::OnActionDeleted(UICDM::CUICDMActionHandle inAction, UICDM::CUICDMSlideHandle inSlide, UICDM::CUICDMInstanceHandle inOwner)
+{
+ Q_UNUSED(inSlide);
+ Q_UNUSED(inOwner);
+ m_actionsModel->removeAction(inAction);
+}
+
+void ActionView::OnActionModified(UICDM::CUICDMActionHandle inAction)
+{
+ if (GetDoc()->GetStudioSystem()->GetActionCore()->HandleValid(inAction)) {
+ m_actionsModel->updateAction(inAction);
+ emitActionChanged();
+ }
+}
+
+void ActionView::OnHandlerArgumentModified(UICDM::CUICDMHandlerArgHandle inHandlerArgument)
+{
+ emitActionChanged();
+}
+
+void ActionView::OnInstancePropertyValueChanged(UICDM::CUICDMInstanceHandle inInstance, UICDM::CUICDMPropertyHandle inProperty)
+{
+ emitActionChanged();
+}
+
+void ActionView::copyAction()
+{
+ auto theTempAPFile =
+ GetDoc()->GetDocumentReader().CopyAction(m_actionsModel->actionAt(m_currentActionIndex),
+ GetDoc()->GetActiveSlide());
+ CUICFile theFile(theTempAPFile);
+ CStudioClipboard::CopyActionToClipboard(theFile);
+}
+
+void ActionView::cutAction()
+{
+ copyAction();
+ auto action = m_actionsModel->actionAt(m_currentActionIndex);
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Cut Action"))->DeleteAction(action);
+}
+
+void ActionView::pasteAction()
+{
+ CUICFile theTempAPFile = CStudioClipboard::GetActionFromClipboard();
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Paste Action"))
+ ->PasteAction(theTempAPFile.GetAbsolutePath(), m_itemHandle);
+}
+
+void ActionView::setTriggerObject(const UICDM::SObjectRefType &object)
+{
+ auto action = m_actionsModel->actionAt(m_currentActionIndex);
+ if (!action.Valid())
+ return;
+
+ auto core = g_StudioApp.GetCore();
+ auto theBridge = GetBridge();
+
+ auto theCmd = new CCmdDataModelActionSetTriggerObject(GetDoc(), action, object);
+ const SActionInfo &theActionInfo = GetDoc()->GetStudioSystem()->GetActionCore()->GetActionInfo(action);
+
+ CUICDMInstanceHandle theBaseInstance = theActionInfo.m_Owner;
+ CUICDMInstanceHandle theObjectInstance = theBridge->GetInstance(theBaseInstance, object);
+ CUICDMInstanceHandle theOldInstance = theBridge->GetInstance(theBaseInstance, theActionInfo.m_TargetObject);
+ // old instance and object instance could be the same, for example if user changes the type
+ // from Absolute to Path. In this case we don't need to reset handler or event.
+ if (theOldInstance != theObjectInstance)
+ theCmd->ResetEvent(
+ theBridge->GetDefaultEvent(theObjectInstance, theActionInfo.m_Event));
+
+ core->ExecuteCommand(theCmd);
+ emitActionChanged();
+}
+
+void ActionView::setTargetObject(const UICDM::SObjectRefType &object)
+{
+ auto action = m_actionsModel->actionAt(m_currentActionIndex);
+ if (!action.Valid())
+ return;
+
+ auto core = g_StudioApp.GetCore();
+ auto doc = GetDoc();
+ auto theBridge = GetBridge();
+
+ auto theCmd = new CCmdDataModelActionSetTargetObject(doc, action, object);
+ const SActionInfo &theActionInfo = doc->GetStudioSystem()->GetActionCore()->GetActionInfo(action);
+
+ CUICDMInstanceHandle theBaseInstance = theActionInfo.m_Owner;
+ CUICDMInstanceHandle theObjectInstance = theBridge->GetInstance(theBaseInstance, object);
+ CUICDMInstanceHandle theOldInstance = theBridge->GetInstance(theBaseInstance, theActionInfo.m_TargetObject);
+ // old instance and object instance could be the same, for example if user changes the type
+ // from Absolute to Path. In this case we don't need to reset handler or event.
+ if (theOldInstance != theObjectInstance)
+ theCmd->ResetHandler(
+ theBridge->GetDefaultHandler(theObjectInstance, theActionInfo.m_Handler));
+
+ core->ExecuteCommand(theCmd);
+ emitActionChanged();
+}
+
+void ActionView::setEvent(const CUICDMEventHandle &event)
+{
+ if (!event.Valid())
+ return;
+
+ auto doc = GetDoc();
+ const auto action = m_actionsModel->actionAt(m_currentActionIndex);
+ CCmd *theCmd = new CCmdDataModelActionSetEvent(doc, action,
+ doc->GetStudioSystem()
+ ->GetActionMetaData()
+ ->GetEventInfo(event)
+ ->m_Name.wide_str());
+ g_StudioApp.GetCore()->ExecuteCommand(theCmd);
+}
+
+void ActionView::setHandler(const CUICDMHandlerHandle &handler)
+{
+ if (!handler.Valid())
+ return;
+
+ auto doc = GetDoc();
+ const auto action = m_actionsModel->actionAt(m_currentActionIndex);
+ wstring handlerName(doc->GetStudioSystem()->GetActionMetaData()->GetHandlerInfo(handler)
+ ->m_Name.wide_str());
+ CCmdDataModelActionSetHandler *theCmd =
+ new CCmdDataModelActionSetHandler(doc, action, handlerName);
+ theCmd->ResetHandler(handlerName); // reset the handler args
+
+ g_StudioApp.GetCore()->ExecuteCommand(theCmd);
+}
+
+QVariant ActionView::handlerArgumentValue(int handle) const
+{
+ UICDM::SValue value;
+ GetDoc()->GetStudioSystem()->GetActionCore()->GetHandlerArgumentValue(handle, value);
+ return value.toQVariant();
+}
+
+void ActionView::updateHandlerArguments()
+{
+ m_currentPropertyValueHandle = 0;
+ m_currentPropertyNameHandle = 0;
+ m_handlerArguments.clear();
+ const auto doc = GetDoc();
+ if (!doc->IsValid())
+ return;
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ const auto bridge = GetBridge();
+ const auto handlerHandle = bridge->ResolveHandler(actionInfo);
+ IActionCore *actionCore = doc->GetStudioSystem()->GetActionCore();
+
+ if (handlerHandle.Valid()) {
+ auto newMetaData = doc->GetStudioSystem()->GetActionMetaData();
+
+ for (const auto &argHandle: actionInfo.m_HandlerArgs) {
+ const auto &argumentInfo = actionCore->GetHandlerArgumentInfo(argHandle);
+ Option<SMetaDataHandlerArgumentInfo> argMetaData(
+ newMetaData->FindHandlerArgumentByName(handlerHandle, argumentInfo.m_Name));
+
+
+ HandlerArgument argument;
+ argument.m_handle = argHandle;
+ argument.m_type = argMetaData->m_ArgType;
+ argument.m_name = QString::fromWCharArray(argumentInfo.m_Name.wide_str());
+ argument.m_value = argumentInfo.m_Value.toQVariant();
+ argument.m_completeType = argMetaData->m_CompleteType;
+ m_handlerArguments.append(QVariant::fromValue(argument));
+ }
+ }
+}
+
+void ActionView::emitActionChanged()
+{
+ m_actionChangedCompressionTimer.start();
+}
+
+void ActionView::setArgumentValue(int handle, const QVariant &value)
+{
+ if (handle == 0)
+ return;
+
+ UICDM::SValue sValue(value);
+ UICDM::SValue oldValue;
+ GetDoc()->GetStudioSystem()->GetActionCore()->GetHandlerArgumentValue(handle, oldValue);
+
+ if (!Equals(oldValue, sValue)) {
+ CCmd *theCmd =
+ new CCmdDataModelActionSetArgumentValue(GetDoc(), handle, sValue);
+ g_StudioApp.GetCore()->ExecuteCommand(theCmd);
+ }
+
+ const auto actionInfo = m_actionsModel->actionInfoAt(m_currentActionIndex);
+ if (actionInfo.m_Handler == L"Fire Event") {
+ if (value.toInt())
+ updateFiredEventFromHandle(value.toInt());
+ }
+}
+
+CDoc *ActionView::GetDoc()
+{
+ return g_StudioApp.GetCore()->GetDoc();
+}
+
+CClientDataModelBridge *ActionView::GetBridge()
+{
+ return GetDoc()->GetStudioSystem()->GetClientDataModelBridge();
+}
+
+void ActionView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty("_actionView"_L1, this);
+ rootContext()->setContextProperty("_resDir"_L1, resourceImageUrl());
+ rootContext()->setContextProperty("_tabOrderHandler"_L1, tabOrderHandler());
+ qmlRegisterUncreatableType<UICDM::HandlerArgumentType>("Qt3DStudio", 1, 0, "HandlerArgumentType",
+ "HandlerArgumentType is an enum container"_L1);
+ qmlRegisterUncreatableType<UICDM::DataModelDataType>("Qt3DStudio", 1, 0, "DataModelDataType",
+ "DataModelDataType is an enum container"_L1);
+ qmlRegisterUncreatableType<UICDM::AdditionalMetaDataType>("Qt3DStudio", 1, 0, "AdditionalMetaDataType",
+ "AdditionalMetaDataType is an enum container"_L1);
+ qmlRegisterUncreatableType<PropertyInfo>("Qt3DStudio", 1, 0, "PropertyInfo",
+ "PropertyInfo is anot creatable in QML"_L1);
+ qmlRegisterUncreatableType<UICDM::CompleteMetaDataType>("Qt3DStudio", 1, 0, "CompleteMetaDataType",
+ "CompleteMetaDataType is an enum container"_L1);
+ engine()->addImportPath(qmlImportPath());
+ setSource(QUrl("qrc:/Studio/Palettes/Action/ActionView.qml"_L1));
+}
+
+QStringList ActionView::slideNames()
+{
+ std::list<Q3DStudio::CString> outSlideNames;
+ QStringList slideNames;
+ CClientDataModelBridge *theBridge = GetBridge();
+ const auto action = m_actionsModel->actionAt(m_currentActionIndex);
+
+ theBridge->GetSlideNamesOfAction(action, outSlideNames);
+
+ for (auto slideName : outSlideNames) {
+ slideNames.append(slideName.toQString());
+ }
+
+ return slideNames;
+}
+
+int ActionView::slideNameToIndex(const QString &name)
+{
+ const auto slides = slideNames(); // KDAB_TODO cache it
+ return slides.indexOf(name);
+}
diff --git a/src/Authoring/Studio/Palettes/Action/ActionView.h b/src/Authoring/Studio/Palettes/Action/ActionView.h
new file mode 100644
index 00000000..dec7b078
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/ActionView.h
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ACTIONVIEW_H
+#define ACTIONVIEW_H
+
+#include <QQuickWidget>
+#include <QColor>
+#include <QPointer>
+#include <QTimer>
+
+#include "stdafx.h"
+#include "DispatchListeners.h"
+#include "EventsBrowserView.h"
+#include "EventsModel.h"
+#include "ObjectBrowserView.h"
+#include "ObjectListModel.h"
+#include "PropertyModel.h"
+#include "SelectedValueImpl.h"
+#include "UICDMHandles.h"
+#include "UICDMSignals.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMMetaDataTypes.h"
+#include "TabOrderHandler.h"
+
+class ActionModel;
+class CClientDataModelBridge;
+class CCore;
+class CDoc;
+class IObjectReferenceHelper;
+
+class QAbstractItemModel;
+
+struct HandlerArgument {
+ Q_PROPERTY(UICDM::HandlerArgumentType::Value type MEMBER m_type FINAL)
+ Q_PROPERTY(QString name MEMBER m_name FINAL)
+ Q_PROPERTY(int handle MEMBER m_handle FINAL)
+ Q_PROPERTY(QVariant value MEMBER m_value FINAL)
+ Q_PROPERTY(UICDM::CompleteMetaDataType::Enum completeType MEMBER m_completeType FINAL)
+
+ UICDM::CUICDMHandlerArgHandle m_handle;
+ UICDM::HandlerArgumentType::Value m_type;
+ UICDM::CompleteMetaDataType::Enum m_completeType;
+ QString m_name;
+ QVariant m_value;
+
+ Q_GADGET
+};
+
+Q_DECLARE_METATYPE(HandlerArgument)
+
+class ActionView : public QQuickWidget,
+ public CPresentationChangeListener,
+ public TabNavigable
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QAbstractItemModel *actionsModel READ actionsModel NOTIFY itemChanged FINAL)
+ Q_PROPERTY(QAbstractItemModel *propertyModel READ propertyModel NOTIFY propertyModelChanged FINAL)
+ Q_PROPERTY(QString itemIcon READ itemIcon NOTIFY itemChanged FINAL)
+ Q_PROPERTY(QString itemText READ itemText NOTIFY itemChanged FINAL)
+ Q_PROPERTY(QColor itemColor READ itemColor NOTIFY itemChanged FINAL)
+ Q_PROPERTY(QString triggerObjectName READ triggerObjectName NOTIFY actionChanged FINAL)
+ Q_PROPERTY(QString targetObjectName READ targetObjectName NOTIFY actionChanged FINAL)
+ Q_PROPERTY(QString eventName READ eventName NOTIFY actionChanged FINAL)
+ Q_PROPERTY(QString handlerName READ handlerName NOTIFY actionChanged FINAL)
+ Q_PROPERTY(QVariantList handlerArguments READ handlerArguments NOTIFY actionChanged FINAL)
+ Q_PROPERTY(PropertyInfo property READ property NOTIFY propertyChanged FINAL)
+ Q_PROPERTY(QString firedEvent MEMBER m_firedEvent NOTIFY firedEventChanged FINAL)
+
+public:
+ ActionView(QWidget *parent = nullptr);
+ ~ActionView();
+
+ QSize sizeHint() const override;
+
+ void setItem(const UICDM::CUICDMInstanceHandle &handle);
+ QString itemIcon() const;
+ QString itemText() const;
+ QColor itemColor() const;
+ QAbstractItemModel *actionsModel() const;
+ QAbstractItemModel *propertyModel() const;
+ QString targetObjectName() const;
+ QString triggerObjectName() const;
+ QString eventName() const;
+ QString handlerName() const;
+ QVariantList handlerArguments() const;
+ PropertyInfo property() const;
+
+ Q_INVOKABLE void setCurrentActionIndex(int index);
+ Q_INVOKABLE void setCurrentPropertyIndex(int handle, int index);
+ Q_INVOKABLE void addAction();
+ Q_INVOKABLE void deleteAction(int index);
+ Q_INVOKABLE QObject *showTriggerObjectBrowser(const QPoint &point);
+ Q_INVOKABLE QObject *showTargetObjectBrowser(const QPoint &point);
+ Q_INVOKABLE void showContextMenu(int x, int y);
+ Q_INVOKABLE QObject *showEventBrowser(const QPoint &point);
+ Q_INVOKABLE QObject *showHandlerBrowser(const QPoint &point);
+ Q_INVOKABLE QObject *showEventBrowserForArgument(int handle, const QPoint &point);
+ Q_INVOKABLE void setArgumentValue(int handle, const QVariant &value);
+ Q_INVOKABLE QStringList slideNames();
+ Q_INVOKABLE int slideNameToIndex(const QString &name);
+
+
+ // CPresentationChangeListener
+ void OnNewPresentation() override;
+
+ // ISelectionChangeListener
+ void OnSelectionSet(Q3DStudio::SSelectedValue inSelectable);
+
+ // Action callback
+ void OnActionAdded(UICDM::CUICDMActionHandle inAction, UICDM::CUICDMSlideHandle inSlide,
+ UICDM::CUICDMInstanceHandle inOwner);
+ void OnActionDeleted(UICDM::CUICDMActionHandle inAction, UICDM::CUICDMSlideHandle inSlide,
+ UICDM::CUICDMInstanceHandle inOwner);
+ void OnActionModified(UICDM::CUICDMActionHandle inAction);
+ void OnHandlerArgumentModified(UICDM::CUICDMHandlerArgHandle inHandlerArgument);
+ void OnInstancePropertyValueChanged(UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMPropertyHandle inProperty);
+
+Q_SIGNALS:
+ void itemChanged();
+ void actionChanged();
+ void propertyModelChanged();
+ void propertyChanged();
+ void firedEventChanged();
+
+private Q_SLOTS:
+ void copyAction();
+ void cutAction();
+ void pasteAction();
+
+private:
+ void setTriggerObject(const UICDM::SObjectRefType &object);
+ void setTargetObject(const UICDM::SObjectRefType &object);
+ void setEvent(const UICDM::CUICDMEventHandle &event);
+ void setHandler(const UICDM::CUICDMHandlerHandle &handler);
+ QVariant handlerArgumentValue(int handle) const;
+ void updateHandlerArguments();
+ void emitActionChanged();
+ void updateFiredEvent();
+ void resetFiredEvent();
+ void updateFiredEventFromHandle(int handle);
+ void showBrowser(QQuickWidget *browser, const QPoint &point);
+
+ static CDoc *GetDoc();
+ static CClientDataModelBridge *GetBridge();
+
+ void initialize();
+ QColor m_baseColor = QColor::fromRgb(75, 75, 75);
+ QColor m_selectColor = Qt::transparent;
+ UICDM::CUICDMInstanceHandle m_itemHandle;
+ IObjectReferenceHelper *m_objRefHelper = nullptr;
+ ActionModel *m_actionsModel = nullptr;
+ PropertyModel *m_propertyModel = nullptr;
+ std::vector<std::shared_ptr<UICDM::ISignalConnection>>
+ m_connections; /// connections to the UICDM
+ QPointer<ObjectListModel> m_objectsModel;
+ QPointer<ObjectBrowserView> m_triggerObjectBrowser;
+ QPointer<ObjectBrowserView> m_targetObjectBrowser;
+ QPointer<EventsModel> m_eventsModel;
+ QPointer<EventsModel> m_handlersModel;
+ QPointer<EventsModel> m_fireEventsModel;
+ QPointer<EventsBrowserView> m_eventsBrowser;
+ QPointer<EventsBrowserView> m_handlerBrowser;
+ QPointer<EventsBrowserView> m_fireEventsBrowser;
+ int m_currentActionIndex = -1;
+ int m_currentPropertyIndex = -1;
+ UICDM::CUICDMHandlerArgHandle m_currentPropertyNameHandle;
+ UICDM::CUICDMHandlerArgHandle m_currentPropertyValueHandle;
+ QVariantList m_handlerArguments;
+ QTimer m_actionChangedCompressionTimer;
+ QString m_firedEvent;
+};
+
+#endif // ACTIONVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Action/ActionView.qml b/src/Authoring/Studio/Palettes/Action/ActionView.qml
new file mode 100644
index 00000000..c1debc3a
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/ActionView.qml
@@ -0,0 +1,426 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import Qt3DStudio 1.0
+import "../controls"
+
+Rectangle {
+ id: root
+
+ color: _backgroundColor
+
+ Flickable {
+ id: actionFlickable
+ ScrollBar.vertical: ScrollBar {
+ id: scrollBar
+ visible: size < 1.0
+ }
+
+ anchors.fill: parent
+ contentHeight: contentColumn.height
+
+ property bool scrollToBottom: false
+
+ onContentHeightChanged: {
+ if (scrollToBottom) {
+ scrollToBottom = false;
+ if (contentHeight > height)
+ contentY = contentHeight - height;
+ }
+ }
+
+ Column {
+ id: contentColumn
+ width: parent.width
+ spacing: 4
+
+ RowLayout {
+ height: _controlBaseHeight + anchors.margins * 2
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.margins: 4
+ anchors.rightMargin: 12
+
+ Image {
+ id: headerImage
+ source: _actionView.itemIcon !== "" ? _resDir + _actionView.itemIcon : ""
+ }
+
+ StyledLabel {
+ Layout.fillWidth: true
+ text: _actionView.itemText
+ color: _actionView.itemColor
+ }
+
+ StyledToolButton {
+ enabled: actionsList.currentIndex !== -1
+ enabledImage: "Action-Trash-Normal.png"
+ disabledImage: "Action-Trash-Disabled.png"
+ toolTipText: qsTr("Delete selected action")
+
+ onClicked: _actionView.deleteAction(actionsList.currentIndex)
+ }
+
+ StyledToolButton {
+ enabledImage: "add.png"
+ toolTipText: qsTr("Add new action")
+
+ onClicked: _actionView.addAction()
+ }
+ }
+ ListView {
+ id: actionsList
+ width: parent.width
+ height: count * _controlBaseHeight
+ clip: true
+
+ boundsBehavior: Flickable.StopAtBounds
+ model: _actionView.actionsModel
+
+ delegate: Rectangle {
+ id: delegateItem
+
+ width: actionsList.width
+ height: _controlBaseHeight
+ color: model.index === actionsList.currentIndex ? _selectionColor
+ : "transparent"
+
+ Row {
+ x: 10
+ y: 5
+ height: parent.height
+ width: parent.width - x
+ spacing: 4
+
+ Image {
+ id: visibilityIcon
+
+ source: model.visible ? _resDir + "Toggle-HideShow.png"
+ : _resDir + "Toggle-HideShow-disabled.png"
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: model.visible = !model.visible
+ }
+ }
+
+ StyledLabel {
+ text: model.description
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+
+ onClicked: {
+ actionFlickable.scrollToBottom = false;
+ actionsList.currentIndex = model.index;
+ _actionView.setCurrentActionIndex(model.index);
+ if (mouse.button == Qt.LeftButton && mouse.x < visibilityIcon.width + 10)
+ model.visible = !model.visible;
+
+ if (mouse.button == Qt.RightButton) {
+ var updateMousePosition = mapToItem(actionsList, mouse.x, mouse.y)
+ _actionView.showContextMenu(updateMousePosition.x, updateMousePosition.y);
+ }
+ }
+ onDoubleClicked: {
+ actionFlickable.scrollToBottom = false;
+ if (mouse.button == Qt.LeftButton && mouse.x > visibilityIcon.width + 10) {
+ // Scroll down to bottom to show properties on double click
+ if (actionFlickable.contentHeight > actionFlickable.height) {
+ actionFlickable.contentY = (actionFlickable.contentHeight
+ - actionFlickable.height)
+ }
+ // Since loading new property fields takes a moment, we want
+ // to keep the view scrolled to bottom
+ // when the content height changes the next time.
+ actionFlickable.scrollToBottom = true;
+ }
+ }
+ }
+ }
+
+ onCountChanged: {
+ if (currentIndex >= count)
+ currentIndex = count - 1;
+ }
+
+ onCurrentIndexChanged: _actionView.setCurrentActionIndex(currentIndex);
+ }
+
+ StyledMenuSeparator {
+ leftPadding: 12
+ rightPadding: 12
+ }
+
+ Column {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ height: childrenRect.height
+ visible: actionsList.currentIndex !== -1
+ spacing: 4
+
+ RowLayout {
+ x: 12
+ StyledLabel {
+ text: qsTr("Trigger Object")
+ }
+ BrowserCombo {
+ value: _actionView.triggerObjectName
+ onShowBrowser: activeBrowser = _actionView.showTriggerObjectBrowser(
+ mapToGlobal(width, 0));
+ }
+ }
+
+ RowLayout {
+ x: 12
+ StyledLabel {
+ text: qsTr("Event")
+ }
+ BrowserCombo {
+ value: _actionView.eventName
+ onShowBrowser: activeBrowser = _actionView.showEventBrowser(
+ mapToGlobal(width, 0))
+ }
+ }
+ }
+
+ StyledMenuSeparator {
+ visible: actionsList.currentIndex !== -1
+ leftPadding: 12
+ rightPadding: 12
+ }
+
+ Column {
+ visible: actionsList.currentIndex !== -1
+ width: parent.width
+ height: childrenRect.height
+ spacing: 4
+
+ RowLayout {
+ x: 12
+ StyledLabel {
+ text: qsTr("Target Object")
+ }
+
+ BrowserCombo {
+ value: _actionView.targetObjectName
+ onShowBrowser: activeBrowser = _actionView.showTargetObjectBrowser(
+ mapToGlobal(width, 0))
+ }
+ }
+
+ RowLayout {
+ x: 12
+ StyledLabel {
+ text: qsTr("Handler")
+ }
+
+ BrowserCombo {
+ value: _actionView.handlerName
+ onShowBrowser: activeBrowser = _actionView.showHandlerBrowser(
+ mapToGlobal(width, 0))
+ }
+ }
+
+ Component {
+ id: genericHandlerComponent
+
+ HandlerGenericText {
+ label: parent && parent.argument.name ? parent.argument.name : ""
+ value: parent && parent.argument.value ? parent.argument.value : ""
+
+ onEditingFinished: {
+ if (parent)
+ _actionView.setArgumentValue(parent.argument.handle, value)
+ }
+ }
+ }
+
+ Component {
+ id: floatHandlerComponent
+
+ HandlerGenericText {
+ label: parent && parent.argument.name ? parent.argument.name : ""
+ value: parent && parent.argument.value ? parent.argument.value : 0.0
+ validator: DoubleValidator {
+ decimals: 3
+ notation: DoubleValidator.StandardNotation
+ }
+
+ onEditingFinished: {
+ if (parent)
+ _actionView.setArgumentValue(parent.argument.handle, value)
+ }
+ }
+ }
+
+ Component {
+ id: signalHandlerComponent
+
+ HandlerGenericText {
+ label: parent && parent.argument.name ? parent.argument.name : ""
+ value: parent && parent.argument.value ? parent.argument.value : ""
+
+ onEditingFinished: {
+ if (parent)
+ _actionView.setArgumentValue(parent.argument.handle, value);
+ }
+ }
+ }
+
+ Component {
+ id: eventHandlerComponent
+
+ HandlerFireEvent {
+ label: parent && parent.argument.name ? parent.argument.name : ""
+ value: _actionView.firedEvent === "" ? qsTr("[Unknown Event]")
+ : _actionView.firedEvent
+
+ onShowBrowser: {
+ if (parent && parent.argument.handle) {
+ activeBrowser = _actionView.showEventBrowserForArgument(
+ parent.argument.handle, mapToGlobal(width, 0))
+ }
+ }
+ }
+ }
+
+ Component {
+ id: slideHandlerComponent
+
+ HandlerGoToSlide {
+ slideModel: _actionView.slideNames()
+ defaultSlideIndex: parent && parent.argument.value ? _actionView.slideNameToIndex(parent.argument.value)
+ : 0
+
+ onIndexChanged: {
+ if (parent && parent.argument.handle && currentSlide)
+ _actionView.setArgumentValue(parent.argument.handle, currentSlide)
+ }
+ }
+ }
+
+ Component {
+ id: checkboxHandlerComponent
+
+ HandlerGenericCheckbox {
+ label: parent && parent.argument.name ? parent.argument.name : ""
+ checked: parent && parent.argument.value ? parent.argument.value : false
+
+ onClicked: {
+ if (parent && parent.argument.handle)
+ _actionView.setArgumentValue(parent.argument.handle, !checked)
+ }
+ }
+ }
+
+ Component {
+ id: propertyHandlerComponent
+
+ HandlerProperty {
+ propertyModel: _actionView.propertyModel
+ defaultPropertyIndex: propertyModel ? propertyModel.defaultPropertyIndex : 0
+
+ onPropertySelected: {
+ if (parent && parent.argument.handle)
+ _actionView.setCurrentPropertyIndex(parent.argument.handle, index);
+ }
+ }
+ }
+
+ Repeater {
+ model: _actionView.handlerArguments.length
+
+ Loader {
+ x: 12
+
+ readonly property var argument:_actionView.handlerArguments[model.index]
+
+ onLoaded: {
+ // HandlerProperty does its own tab order handling
+ if (argument.type !== HandlerArgumentType.Property) {
+ // Dynamic actions use group 0.
+ // We assume there is always just one tabbable argument per action,
+ // and the rest are dependent types.
+ _tabOrderHandler.clear();
+ if (item.tabItem1 !== undefined) {
+ _tabOrderHandler.addItem(0, item.tabItem1)
+ if (item.tabItem2 !== undefined) {
+ _tabOrderHandler.addItem(0, item.tabItem2)
+ if (item.tabItem3 !== undefined)
+ _tabOrderHandler.addItem(0, item.tabItem3)
+ }
+ }
+ }
+ }
+
+ sourceComponent: {
+ const handlerType = argument.type;
+ switch (handlerType) {
+ case HandlerArgumentType.None:
+ switch (argument.completeType) {
+ case CompleteMetaDataType.Boolean:
+ return checkboxHandlerComponent;
+ case CompleteMetaDataType.Float:
+ return floatHandlerComponent;
+ default:
+ return genericHandlerComponent;
+ }
+ case HandlerArgumentType.Event:
+ return eventHandlerComponent;
+ case HandlerArgumentType.Property:
+ return propertyHandlerComponent;
+ case HandlerArgumentType.Dependent:
+ return null; // no UI for Dependent type, they are the value for a property
+ case HandlerArgumentType.Signal:
+ return signalHandlerComponent;
+ case HandlerArgumentType.Slide:
+ return slideHandlerComponent
+ default: console.warn("KDAB_TODO implement handler for type: ", handlerType)
+ }
+ return null;
+ }
+ }
+ }
+ }
+
+ StyledMenuSeparator {
+ visible: actionsList.count > 0 && actionsList.currentIndex !== -1
+ leftPadding: 12
+ rightPadding: 12
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/EventsBrowser.qml b/src/Authoring/Studio/Palettes/Action/EventsBrowser.qml
new file mode 100644
index 00000000..63973ec7
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/EventsBrowser.qml
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+Rectangle {
+ id: root
+
+ color: _backgroundColor
+ border.color: _studioColor3
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ ListView {
+ id: eventsList
+
+ Layout.margins: 10
+ Layout.columnSpan: 2
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.minimumHeight: 80
+ Layout.preferredHeight: count * 20
+ Layout.preferredWidth: root.width
+
+ ScrollBar.vertical: ScrollBar {}
+
+ boundsBehavior: Flickable.StopAtBounds
+ clip: true
+
+ model: _eventsBrowserView.model
+
+ delegate: Item {
+ id: delegateItem
+
+ readonly property bool isCategory: model.isCategory
+
+ x: isCategory ? 0 : 50
+ width: parent.width
+ height: model.parentExpanded ? 30 : 0
+ visible: height > 0
+
+ Behavior on height {
+ NumberAnimation {
+ duration: 100
+ easing.type: Easing.OutQuad
+ }
+ }
+
+ Row {
+ id: row
+
+ height: categoryIcon.height
+ spacing: 5
+
+ Image {
+ source: {
+ if (!delegateItem.isCategory)
+ return "";
+ model.expanded ? _resDir + "arrow_down.png"
+ : _resDir + "arrow.png";
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: model.expanded = !model.expanded
+ }
+ }
+
+ Rectangle {
+ height: name.height
+ width: categoryIcon.width + name.width + 10
+
+ color: model.index === eventsList.currentIndex ? _selectionColor
+ : "transparent"
+
+ Row {
+ id: textRow
+
+ spacing: 10
+ Image {
+ id: categoryIcon
+
+ source: model.icon
+ }
+
+ StyledLabel {
+ id: name
+ anchors.verticalCenter: textRow.verticalCenter
+ text: model.name
+ }
+ }
+
+ MouseArea {
+ id: delegateArea
+
+ anchors.fill: parent
+ hoverEnabled: true
+ onClicked: eventsList.currentIndex = model.index
+ onEntered: itemDescription.text = model.description
+ onExited: itemDescription.text = ""
+ onDoubleClicked: {
+ eventsList.currentIndex = model.index;
+ _eventsBrowserView.close();
+ }
+ }
+ }
+ }
+
+ }
+ onCurrentIndexChanged: _eventsBrowserView.selection = currentIndex
+ }
+
+ StyledMenuSeparator {
+ bottomPadding: 0
+ }
+
+ Item {
+ Layout.fillWidth: true
+ Layout.preferredHeight: _controlBaseHeight + 4
+ Rectangle {
+ anchors.fill: parent
+ anchors.margins: 2
+
+ color: _backgroundColor
+
+ StyledLabel {
+ id: itemDescription
+ leftPadding: 6
+ anchors.fill: parent
+ }
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/EventsBrowserView.cpp b/src/Authoring/Studio/Palettes/Action/EventsBrowserView.cpp
new file mode 100644
index 00000000..047a7b82
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/EventsBrowserView.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "EventsBrowserView.h"
+
+#include "CColor.h"
+#include "EventsModel.h"
+#include "Literals.h"
+#include "StudioUtils.h"
+#include "StudioPreferences.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qtimer.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+
+EventsBrowserView::EventsBrowserView(QWidget *parent) : QQuickWidget(parent)
+{
+ setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QTimer::singleShot(0, this, &EventsBrowserView::initialize);
+}
+
+QAbstractItemModel *EventsBrowserView::model() const
+{
+ return m_model;
+}
+
+void EventsBrowserView::setModel(EventsModel *model)
+{
+ if (m_model != model) {
+ m_model = model;
+ Q_EMIT modelChanged();
+ }
+}
+
+QSize EventsBrowserView::sizeHint() const
+{
+ return {500, 500};
+}
+
+UICDM::CDataModelHandle EventsBrowserView::selectedHandle() const
+{
+ const auto handleId = m_model->handleForRow(m_selection);
+ return handleId;
+}
+
+void EventsBrowserView::setSelection(int index)
+{
+ auto handleId = m_model->handleForRow(index);
+ if (!handleId.Valid()) {
+ m_selection = -1;
+ Q_EMIT selectionChanged();
+ } else if (m_selection != index) {
+ m_selection = index;
+ Q_EMIT selectionChanged();
+ }
+}
+
+void EventsBrowserView::focusOutEvent(QFocusEvent *event)
+{
+ QQuickWidget::focusOutEvent(event);
+ QTimer::singleShot(0, this, &EventsBrowserView::close);
+}
+
+void EventsBrowserView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty("_eventsBrowserView"_L1, this);
+ rootContext()->setContextProperty("_resDir"_L1,
+ resourceImageUrl());
+ engine()->addImportPath(qmlImportPath());
+ setSource(QUrl("qrc:/Studio/Palettes/Action/EventsBrowser.qml"_L1));
+}
+
diff --git a/src/Authoring/Studio/Palettes/Action/EventsBrowserView.h b/src/Authoring/Studio/Palettes/Action/EventsBrowserView.h
new file mode 100644
index 00000000..3902ca12
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/EventsBrowserView.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef EVENTSBROWSERVIEW_H
+#define EVENTSBROWSERVIEW_H
+
+#include <QQuickWidget>
+
+#include "UICDMHandles.h"
+
+class EventsModel;
+
+class QAbstractItemModel;
+
+class EventsBrowserView : public QQuickWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(QAbstractItemModel *model READ model NOTIFY modelChanged FINAL)
+ Q_PROPERTY(int selection READ selection WRITE setSelection NOTIFY selectionChanged FINAL)
+public:
+ explicit EventsBrowserView(QWidget *parent = nullptr);
+
+ QAbstractItemModel *model() const;
+ void setModel(EventsModel *model);
+ QSize sizeHint() const override;
+ UICDM::CDataModelHandle selectedHandle() const;
+
+ int selection() const { return m_selection; }
+ void setSelection(int index);
+
+Q_SIGNALS:
+ void modelChanged();
+ void selectionChanged();
+
+protected:
+ void focusOutEvent(QFocusEvent *event) override;
+
+private:
+ void initialize();
+ EventsModel *m_model = nullptr;
+ QColor m_baseColor = QColor::fromRgb(75, 75, 75);
+ QColor m_selectColor;
+ int m_selection = -1;
+};
+
+#endif // EVENTSBROWSERVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Action/EventsModel.cpp b/src/Authoring/Studio/Palettes/Action/EventsModel.cpp
new file mode 100644
index 00000000..aa14ad81
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/EventsModel.cpp
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "EventsModel.h"
+
+#include "ClientDataModelBridge.h"
+#include "Core.h"
+#include "Doc.h"
+#include "StudioUtils.h"
+#include "StudioApp.h"
+#include "UICDMStudioSystem.h"
+
+EventsModel::EventsModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+}
+
+void EventsModel::setEventList(const UICDM::TEventHandleList &eventList)
+{
+ beginResetModel();
+
+ m_rowCount = 0;
+ m_events.clear();
+ m_categories.clear();
+
+ auto studioSystem = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem();
+ auto theBridge = studioSystem->GetClientDataModelBridge();
+ auto thePos = eventList.begin();
+ for (; thePos != eventList.end(); ++thePos) {
+ UICDM::SEventInfo theEvent = theBridge->GetEventInfo(*thePos);
+
+ CategoryInfo category;
+ category.name = QString::fromWCharArray(theEvent.m_Category.wide_str());
+ if (!m_events.contains(category.name)) {
+ UICDM::SCategoryInfo theCategoryMetaData = studioSystem->GetActionMetaData()
+ ->GetEventCategory(theEvent.m_Category);
+ category.icon = QString::fromWCharArray(theCategoryMetaData.m_Icon.wide_str());
+ category.highlightIcon = QString::fromWCharArray(theCategoryMetaData.m_HighlightIcon.wide_str());
+ category.description = QString::fromWCharArray(theCategoryMetaData.m_Description.wide_str());
+ m_categories.append(category);
+ m_rowCount++;
+ }
+
+ EventInfo eventInfo;
+ // Use the formal name to display, but if the formal name is not set, use the name instead
+ eventInfo.name = QString::fromWCharArray(theEvent.m_FormalName.wide_str());
+ if (eventInfo.name.isEmpty())
+ eventInfo.name = QString::fromWCharArray(theEvent.m_Name.wide_str());
+ eventInfo.handle = *thePos;
+
+ eventInfo.description = QString::fromWCharArray(theEvent.m_Description.wide_str());
+ m_events[category.name].append(eventInfo);
+ m_rowCount++;
+
+ //KDAB_TODO set the selection to the current event
+ }
+
+ endResetModel();
+}
+
+void EventsModel::setHandlerList(const UICDM::THandlerHandleList &handlerList)
+{
+ beginResetModel();
+ m_rowCount = 0;
+ m_events.clear();
+ m_categories.clear();
+
+ auto studioSystem = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem();
+ auto theBridge = studioSystem->GetClientDataModelBridge();
+ auto thePos = handlerList.begin();
+ for (; thePos != handlerList.end(); ++thePos) {
+ UICDM::SHandlerInfo handlerInfo = theBridge->GetHandlerInfo(*thePos);
+
+ CategoryInfo category;
+ category.name = QString::fromWCharArray(handlerInfo.m_Category.wide_str());
+ if (!m_events.contains(category.name)) {
+ UICDM::SCategoryInfo theCategoryMetaData = studioSystem->GetActionMetaData()
+ ->GetHandlerCategory(handlerInfo.m_Category);
+ category.icon = QString::fromWCharArray(theCategoryMetaData.m_Icon.wide_str());
+ category.highlightIcon = QString::fromWCharArray(theCategoryMetaData.m_HighlightIcon.wide_str());
+ category.description = QString::fromWCharArray(theCategoryMetaData.m_Description.wide_str());
+ m_categories.append(category);
+ m_rowCount++;
+ }
+
+ EventInfo eventInfo;
+ // Use the formal name to display, but if the formal name is not set, use the name instead
+ eventInfo.name = QString::fromWCharArray(handlerInfo.m_FormalName.wide_str());
+ if (eventInfo.name.isEmpty())
+ eventInfo.name = QString::fromWCharArray(handlerInfo.m_Name.wide_str());
+ eventInfo.handle = *thePos;
+
+ eventInfo.description = QString::fromWCharArray(handlerInfo.m_Description.wide_str());
+ m_events[category.name].append(eventInfo);
+ m_rowCount++;
+
+ //KDAB_TODO set the selection to the current event
+ }
+
+ endResetModel();
+}
+
+int EventsModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return m_rowCount;
+}
+
+QVariant EventsModel::data(const QModelIndex &index, int role) const
+{
+ if (!hasIndex(index.row(), index.column(), index.parent()))
+ return {};
+
+ const auto row = index.row();
+ auto category = categoryForRow(row);
+
+ bool isCategory = category.isValid();
+ EventInfo event;
+ if (!isCategory)
+ event = eventForRow(row);
+
+ switch (role) {
+ case NameRole:
+ return isCategory ? category.name : event.name;
+ case DescriptionRole:
+ return isCategory ? category.description: event.description;
+ case IconRole:
+ return isCategory ? resourceImageUrl() + category.icon : "";
+ case HighlightedIconRole:
+ return isCategory ? resourceImageUrl() + category.highlightIcon : "";
+ case ExpandedRole:
+ return isCategory ? category.expanded : false;
+ case ParentExpandedRole: {
+ if (isCategory)
+ return true;
+ for (int i = row - 1; i >= 0; i--) {
+ auto parentCategory = categoryForRow(i);
+ if (parentCategory.isValid())
+ return parentCategory.expanded;
+ }
+ return false;
+ }
+ case IsCategoryRole:
+ return isCategory;
+ }
+
+ return QVariant();
+}
+
+bool EventsModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (role == ExpandedRole) {
+ int catRow = categoryRowForRow(index.row());
+ if (catRow != -1) {
+ auto category = &m_categories[catRow];
+ category->expanded = value.toBool();
+ Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), {});
+ return true;
+ }
+ }
+ return false;
+}
+
+QHash<int, QByteArray> EventsModel::roleNames() const
+{
+ auto names = QAbstractItemModel::roleNames();
+ names.insert(NameRole, "name");
+ names.insert(DescriptionRole, "description");
+ names.insert(IconRole, "icon");
+ names.insert(HighlightedIconRole, "highlightedIcon");
+ names.insert(IsCategoryRole, "isCategory");
+ names.insert(ExpandedRole, "expanded");
+ names.insert(ParentExpandedRole, "parentExpanded");
+
+ return names;
+}
+
+UICDM::CDataModelHandle EventsModel::handleForRow(int row) const
+{
+ if (row < 0 || row >= m_rowCount)
+ return {};
+
+ auto event = eventForRow(row);
+ if (event.isValid())
+ return event.handle;
+
+ return {};
+}
+
+EventsModel::CategoryInfo EventsModel::categoryForRow(int row) const
+{
+ int i = 0;
+ for (const auto &category: m_categories) {
+ if (i == row)
+ return category;
+ i += m_events[category.name].size();
+ i++;
+ }
+
+ return {};
+}
+
+int EventsModel::categoryRowForRow(int row) const
+{
+ int i = 0;
+ int catRow = 0;
+ for (const auto &category: m_categories) {
+ if (i == row)
+ return catRow;
+ i += m_events[category.name].size();
+ i++;
+ catRow++;
+ }
+
+ return -1;
+}
+
+EventsModel::EventInfo EventsModel::eventForRow(int row) const
+{
+ if (row == 0) // first line is not an event, but a category
+ return {};
+
+ int i = 0;
+ for (const auto &category: m_categories) {
+ i++;
+ const auto events = m_events[category.name];
+ const int index = (row - i);
+ if (row < i + events.size() && (index >= 0) ) {
+ return events[index];
+ }
+ i += events.size();
+ }
+
+ return {};
+}
diff --git a/src/Authoring/Studio/Palettes/Action/EventsModel.h b/src/Authoring/Studio/Palettes/Action/EventsModel.h
new file mode 100644
index 00000000..ef458877
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/EventsModel.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef EVENTSMODEL_H
+#define EVENTSMODEL_H
+
+#include <QAbstractListModel>
+
+#include "UICDMHandles.h"
+
+/** Model for both action events and action handlers */
+class EventsModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ explicit EventsModel(QObject *parent = nullptr);
+
+ void setEventList(const UICDM::TEventHandleList &eventList);
+ void setHandlerList(const UICDM::THandlerHandleList &handlerList);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+ bool setData(const QModelIndex &index, const QVariant &value,
+ int role = Qt::EditRole) override;
+
+ enum Roles {
+ NameRole = Qt::DisplayRole,
+ DescriptionRole = Qt::UserRole + 1,
+ IconRole,
+ HighlightedIconRole,
+ ExpandedRole,
+ ParentExpandedRole,
+ IsCategoryRole
+ };
+
+ QHash<int, QByteArray> roleNames() const override;
+
+ UICDM::CDataModelHandle handleForRow(int row) const;
+
+private:
+ struct EventInfo {
+ UICDM::CDataModelHandle handle;
+ QString name;
+ QString description;
+
+ bool isValid() const { return handle.Valid(); }
+ };
+
+ struct CategoryInfo {
+ QString name;
+ QString icon;
+ QString description;
+ QString highlightIcon;
+ bool expanded = true;
+
+ bool isValid() const { return !name.isEmpty(); }
+ };
+
+ CategoryInfo categoryForRow(int row) const;
+ int categoryRowForRow(int row) const;
+ EventInfo eventForRow(int row) const;
+
+ QHash<QString, QVector<EventInfo> > m_events;
+ QVector<CategoryInfo> m_categories;
+ int m_rowCount = 0;
+};
+
+#endif // EVENTSMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerEmitSignal.qml b/src/Authoring/Studio/Palettes/Action/HandlerEmitSignal.qml
new file mode 100644
index 00000000..5917a9bd
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerEmitSignal.qml
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias value: textField.text
+ property Item tabItem1: textfield
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("Signal Name")
+ }
+
+ StyledTextField {
+ id: textField
+ Layout.preferredWidth: _valueWidth
+ }
+}
+
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerFireEvent.qml b/src/Authoring/Studio/Palettes/Action/HandlerFireEvent.qml
new file mode 100644
index 00000000..e92d2265
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerFireEvent.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias value: comboField.value
+ property alias activeBrowser: comboField.activeBrowser
+
+ signal showBrowser
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("Event")
+ }
+
+ BrowserCombo {
+ id: comboField
+ Layout.preferredWidth: _valueWidth
+ value: qsTr("[Unknown Event]")
+ onShowBrowser: root.showBrowser()
+ }
+}
+
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerGenericBaseColor.qml b/src/Authoring/Studio/Palettes/Action/HandlerGenericBaseColor.qml
new file mode 100644
index 00000000..dbe097cb
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerGenericBaseColor.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Dialogs 1.2
+import QtQuick.Layouts 1.3
+
+RowLayout {
+ id: root
+
+ property alias color: rect.color
+ property alias selectedColor: colorDialog.color
+
+ signal colorSelected()
+
+ Rectangle {
+ id: rect
+
+ width: _valueWidth / 4
+ height: _controlBaseHeight
+
+ border {
+ width: 1
+ color: _studioColor2
+ }
+
+ MouseArea {
+ id: mouseArea
+
+ anchors.fill: parent
+ onClicked: colorDialog.open()
+ }
+
+ Image {
+ id: img
+ x: parent.width - sourceSize.width - 3
+ y: (parent.height - sourceSize.height) / 2
+ source: _resDir + "arrow_down.png"
+ }
+ }
+
+
+ Item {
+ Layout.fillWidth: true
+ }
+
+ ColorDialog {
+ id: colorDialog
+
+ color: rect.color
+
+ onAccepted: root.colorSelected()
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerGenericCheckbox.qml b/src/Authoring/Studio/Palettes/Action/HandlerGenericCheckbox.qml
new file mode 100644
index 00000000..4b3b0ba4
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerGenericCheckbox.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property bool checked: false
+ property alias label: labelField.text
+
+ signal clicked()
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("Pause")
+ }
+
+ Image {
+ source: _resDir + (checked ? "checkbox-checked.png" : "checkbox-unchecked.png")
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: root.clicked()
+ }
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerGenericColor.qml b/src/Authoring/Studio/Palettes/Action/HandlerGenericColor.qml
new file mode 100644
index 00000000..378aa7b0
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerGenericColor.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias color: handlerGenericColor.color
+ property alias selectedColor: handlerGenericColor.selectedColor
+
+ signal colorSelected()
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("New Value")
+ }
+
+ HandlerGenericBaseColor {
+ id: handlerGenericColor
+
+ onColorSelected: root.colorSelected();
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerGenericText.qml b/src/Authoring/Studio/Palettes/Action/HandlerGenericText.qml
new file mode 100644
index 00000000..e33e170f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerGenericText.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias value: textField.text
+ property alias validator: textField.validator
+ property Item tabItem1: textField
+
+ signal editingFinished()
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("Argument")
+ }
+
+ StyledTextField {
+ id: textField
+ onEditingFinished: root.editingFinished()
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerGoToSlide.qml b/src/Authoring/Studio/Palettes/Action/HandlerGoToSlide.qml
new file mode 100644
index 00000000..ef76dfcb
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerGoToSlide.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias slideModel: comboSlide.model
+ property string currentSlide
+ property int defaultSlideIndex: 0
+
+ signal indexChanged()
+
+ onDefaultSlideIndexChanged: comboSlide.currentIndex = defaultSlideIndex
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("Slide")
+ }
+
+ StyledComboBox {
+ id: comboSlide
+ Layout.preferredWidth: _valueWidth
+ model: slideModel
+
+ onCurrentIndexChanged: {
+ currentSlide = comboSlide.textAt(currentIndex);
+ indexChanged();
+ }
+ }
+}
+
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerMultilineText.qml b/src/Authoring/Studio/Palettes/Action/HandlerMultilineText.qml
new file mode 100644
index 00000000..2c7704a4
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerMultilineText.qml
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias value: textArea.text
+ property Item tabItem1: textArea
+
+ signal editingFinished()
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("Argument")
+ }
+
+ Flickable {
+ Layout.preferredWidth: _valueWidth
+ Layout.preferredHeight: textArea.height
+
+ ScrollBar.vertical: ScrollBar {}
+
+ TextArea.flickable: TextArea {
+ id: textArea
+
+ horizontalAlignment: TextInput.AlignLeft
+ verticalAlignment: TextInput.AlignVCenter
+ implicitWidth: _valueWidth
+ font.pixelSize: _fontSize
+ color: _textColor
+
+ topPadding: 6
+ bottomPadding: 6
+ rightPadding: 6
+
+ wrapMode: TextArea.Wrap
+ background: Rectangle {
+ color: textArea.enabled ? _studioColor2 : "transparent"
+ border.width: textArea.activeFocus ? 1 : 0
+ border.color: textArea.activeFocus ? _selectionColor : _disabledColor
+ }
+
+ onEditingFinished: root.editingFinished()
+ }
+
+ MouseArea {
+ id: mouseArea
+
+ anchors.fill: parent
+ onPressed: parent.forceActiveFocus()
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerProperty.qml b/src/Authoring/Studio/Palettes/Action/HandlerProperty.qml
new file mode 100644
index 00000000..52d6265a
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerProperty.qml
@@ -0,0 +1,255 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import Qt3DStudio 1.0
+import "../controls"
+
+ColumnLayout {
+ id: root
+
+ property alias propertyModel: propertyCombo.model
+ property int defaultPropertyIndex: 0
+
+ signal propertySelected(int index)
+
+ onDefaultPropertyIndexChanged: propertyCombo.currentIndex = defaultPropertyIndex
+
+ RowLayout {
+
+ Layout.fillWidth: true
+
+ StyledLabel {
+ text: qsTr("Property")
+ }
+
+ StyledComboBox {
+ id: propertyCombo
+ textRole: "name"
+ onCurrentIndexChanged: root.propertySelected(currentIndex)
+ onModelChanged: currentIndex = root.defaultPropertyIndex
+ }
+ }
+
+ Component {
+ id: multiLineComponent
+
+ HandlerMultilineText {
+ readonly property var actionProperty: parent ? _actionView.property : null
+
+ label: parent ? parent.label : ""
+ value: propertyModel && actionProperty && actionProperty.type === DataModelDataType.String
+ ? propertyModel.value : ""
+ onEditingFinished: _actionView.setArgumentValue(propertyModel.valueHandle, value)
+ }
+ }
+
+ Component {
+ id: fontSizeComponent
+
+ HandlerPropertyCombo {
+ readonly property var actionProperty: parent ? _actionView.property : null
+
+ label: parent ? parent.label : ""
+ comboModel: ["8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "26", "28", "36", "48", "72", "96", "120"];
+
+ onValueChanged: _actionView.setArgumentValue(propertyModel.valueHandle, value)
+ }
+ }
+
+ Component {
+ id: xyzPropertyComponent
+
+ HandlerPropertyXYZ {
+ readonly property var propValue: propertyModel && propertyModel.value.x ?
+ propertyModel.value
+ : undefined
+ label: parent ? parent.label : ""
+ valueX: propValue !== undefined ? propValue.x : 0
+ valueY: propValue !== undefined ? propValue.y : 0
+ valueZ: propValue !== undefined ? propValue.z : 0
+
+ onEditingFinished: _actionView.setArgumentValue(propertyModel.valueHandle,
+ Qt.vector3d(valueX, valueY, valueZ))
+ }
+ }
+
+ Component {
+ id: sliderPropertyComponent
+
+ HandlerPropertySlider {
+ readonly property var actionProperty: parent ? _actionView.property : null
+
+ sliderMin: actionProperty ? actionProperty.min : 0
+ sliderMax: actionProperty ? actionProperty.max : 100
+ intSlider: actionProperty ? actionProperty.type === DataModelDataType.Long : false
+ value: propertyModel ? propertyModel.value : 0
+
+ label: parent ? parent.label : ""
+
+ onValueChanged: _actionView.setArgumentValue(propertyModel.valueHandle, value)
+ }
+ }
+
+ Component {
+ id: comboPropertyComponent
+
+ HandlerPropertyCombo {
+ readonly property var actionProperty: parent ? _actionView.property : null
+
+ label: parent ? parent.label : ""
+ comboModel: actionProperty ? actionProperty.possibleValues : null
+
+ onValueChanged: _actionView.setArgumentValue(propertyModel.valueHandle, value)
+
+ }
+ }
+
+ Component {
+ id: booleanComponent
+
+ HandlerGenericCheckbox {
+ label: parent ? parent.label : ""
+ checked: propertyModel ? propertyModel.value : false
+
+ onClicked: {
+ _actionView.setArgumentValue(propertyModel.valueHandle, !checked)
+ }
+ }
+ }
+
+ Component {
+ id: colorBox
+
+ HandlerGenericColor {
+ readonly property var propValue: propertyModel ? propertyModel.value : undefined
+
+ label: parent ? parent.label : ""
+ color: propValue ? Qt.rgba(propValue.x, propValue.y, propValue.z, 1) : "black"
+ onColorSelected: {
+ _actionView.setArgumentValue(propertyModel.valueHandle, selectedColor)
+ }
+ }
+ }
+
+ Component {
+ id: genericTextComponent
+
+ HandlerGenericText {
+ label: parent ? parent.label : ""
+ value: propertyModel ? propertyModel.value : ""
+ onEditingFinished: _actionView.setArgumentValue(propertyModel.valueHandle, value)
+ }
+ }
+
+ Component {
+ id: floatPropertyComponent
+
+ HandlerGenericText {
+ label: parent ? parent.label : ""
+ value: propertyModel ? propertyModel.value : ""
+ validator: DoubleValidator {
+ decimals: 3
+ notation: DoubleValidator.StandardNotation
+ }
+
+ onEditingFinished: _actionView.setArgumentValue(propertyModel.valueHandle, value)
+ }
+ }
+
+ Loader {
+ readonly property string label: qsTr("New Value")
+ readonly property var actionProperty: _actionView.property
+
+ Layout.fillWidth: true
+
+ onLoaded: {
+ _tabOrderHandler.clear();
+ if (item.tabItem1 !== undefined) {
+ _tabOrderHandler.addItem(0, item.tabItem1)
+ if (item.tabItem2 !== undefined) {
+ _tabOrderHandler.addItem(0, item.tabItem2)
+ if (item.tabItem3 !== undefined)
+ _tabOrderHandler.addItem(0, item.tabItem3)
+ }
+ }
+ }
+
+ sourceComponent: {
+ // KDAB_TODO Handle additionaltype
+ switch (actionProperty.type) {
+ case DataModelDataType.Float:
+ switch (actionProperty.additionalType) {
+ case AdditionalMetaDataType.FontSize:
+ return fontSizeComponent;
+ case AdditionalMetaDataType.Range:
+ return sliderPropertyComponent;
+ default:
+ return floatPropertyComponent;
+ }
+ case DataModelDataType.Long:
+ return sliderPropertyComponent;
+ case DataModelDataType.Float3:
+ switch (actionProperty.additionalType) {
+ case AdditionalMetaDataType.None:
+ case AdditionalMetaDataType.Rotation:
+ return xyzPropertyComponent;
+ case AdditionalMetaDataType.Color:
+ return colorBox;
+ default:
+ console.warn("KDAB_TODO implement property handler for additional typeDataModelDataType.Float3: ", actionProperty.additionalType);
+ return xyzPropertyComponent;
+ }
+ case DataModelDataType.String:
+ switch (actionProperty.additionalType) {
+ case AdditionalMetaDataType.StringList:
+ return comboPropertyComponent;
+ case AdditionalMetaDataType.MultiLine:
+ return multiLineComponent;
+ case AdditionalMetaDataType.Font:
+ return comboPropertyComponent;
+ case AdditionalMetaDataType.Import:
+ case AdditionalMetaDataType.Renderable:
+ return genericTextComponent;
+ default:
+ console.warn("KDAB_TODO implement property handler for additional type: ", actionProperty.additionalType)
+ return null;
+ }
+ case DataModelDataType.Bool:
+ return booleanComponent;
+ case DataModelDataType.None:
+ return null;
+ default: console.warn("KDAB_TODO implement property handler for type: ", actionProperty.type)
+
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseSlider.qml b/src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseSlider.qml
new file mode 100644
index 00000000..8fcf3511
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseSlider.qml
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+/*
+* Use for: Opacity, Edge Tesselation Value, Inner Tesselation Value ...
+* For the latter two set sliderMax to 64
+*/
+
+Row {
+ id: root
+
+ property alias value: slider.value
+ property int intValue: slider.value
+ property alias sliderMin: slider.from
+ property alias sliderMax: slider.to
+ property bool intSlider: false
+ property int decimalSlider: 3
+ property Item tabItem1: textField
+
+ signal editingFinished
+ signal sliderMoved
+ signal editingStarted
+
+ spacing: 5
+ width: _valueWidth
+
+ Slider {
+ id: slider
+
+ leftPadding: 0
+
+ background: Rectangle {
+ x: slider.leftPadding
+ y: slider.topPadding + slider.availableHeight / 2 - height / 2
+ implicitWidth: _valueWidth / 2 - 5
+ implicitHeight: 6
+ height: implicitHeight
+ radius: 2
+ color: _studioColor2
+ }
+ handle: Rectangle {
+ x: slider.leftPadding + slider.visualPosition * slider.availableWidth
+ y: slider.topPadding + slider.availableHeight / 2 - height / 2
+ implicitWidth: 6
+ implicitHeight: 12
+ color: _studioColor3
+ radius: 2
+ }
+
+ from: 0
+ to: 100
+ stepSize: 2
+
+ onMoved: {
+ if (!rateLimiter.running) {
+ rateLimiter.start();
+ }
+ }
+
+ onPressedChanged: {
+ if (pressed)
+ root.editingStarted();
+ else
+ root.editingFinished();
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.NoButton
+
+ onWheel: {
+ var delta = (wheel.angleDelta.x != 0) ? wheel.angleDelta.x
+ : wheel.angleDelta.y;
+
+ if (delta > 0) {
+ slider.increase();
+ } else {
+ slider.decrease();
+ }
+ if (!rateLimiter.running) {
+ rateLimiter.start();
+ }
+ }
+ }
+ }
+
+ Timer {
+ id: rateLimiter
+ interval: 50
+ onTriggered: {
+ root.sliderMoved();
+ }
+ }
+
+ DoubleValidator {
+ id: doubleValidator
+
+ decimals: decimalSlider
+ bottom: slider.from
+ top: slider.to
+ locale: "C"
+ }
+
+ IntValidator {
+ id: intValidator
+
+ bottom: slider.from
+ top: slider.to
+ }
+
+ StyledTextField {
+ id: textField
+
+ height: _controlBaseHeight
+ width: _valueWidth / 2
+ text: intSlider ? slider.value.toFixed(0) : slider.value.toFixed(decimalSlider)
+
+ validator: intSlider ? intValidator : doubleValidator
+
+ onActiveFocusChanged: {
+ if (activeFocus)
+ root.editingStarted();
+ }
+
+ onEditingFinished: {
+ if (textField.text > sliderMax)
+ textField.text = sliderMax
+ else if (textField.text < sliderMin)
+ textField.text = sliderMin
+ slider.value = textField.text
+ root.editingFinished()
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseXYZ.qml b/src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseXYZ.qml
new file mode 100644
index 00000000..fcabf271
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseXYZ.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+/* Use for: Position, Rotation, Scale, Pivot ... */
+
+GridLayout {
+ id: root
+
+ property alias valueX: textFieldX.text
+ property alias valueY: textFieldY.text
+ property alias valueZ: textFieldZ.text
+ property int numberOfDecimal: 3
+ property Item tabItem1: textFieldX
+ property Item tabItem2: textFieldY
+ property Item tabItem3: textFieldZ
+
+ columns: 2
+ rowSpacing: 1
+
+ signal editingFinished
+
+ StyledLabel {
+ Layout.preferredWidth: 10
+ text: qsTr("X")
+ }
+
+ FloatTextField {
+ id: textFieldX
+
+ decimalValue: numberOfDecimal
+ onEditingFinished: root.editingFinished()
+ onWheelEventFinished: root.editingFinished()
+ }
+
+ StyledLabel {
+ Layout.preferredWidth: 10
+ text: qsTr("Y")
+ }
+
+ FloatTextField {
+ id: textFieldY
+
+ decimalValue: numberOfDecimal
+ onEditingFinished: root.editingFinished()
+ onWheelEventFinished: root.editingFinished()
+ }
+
+ StyledLabel {
+ Layout.preferredWidth: 10
+ text: qsTr("Z")
+ }
+
+ FloatTextField {
+ id: textFieldZ
+
+ decimalValue: numberOfDecimal
+ onEditingFinished: root.editingFinished()
+ onWheelEventFinished: root.editingFinished()
+ }
+}
+
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerPropertyCombo.qml b/src/Authoring/Studio/Palettes/Action/HandlerPropertyCombo.qml
new file mode 100644
index 00000000..1e60cf44
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerPropertyCombo.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+/* Use for Tesselation mode, Horizontal alignment, Vertical alignment ... */
+
+RowLayout {
+ id: root
+
+ property alias label: labelField.text
+ property alias comboModel : comboBox.model
+ property alias comboTextRole: comboBox.textRole
+ property string value
+
+ StyledLabel {
+ id: labelField
+ text: qsTr("New Value")
+ }
+
+ StyledComboBox {
+ id: comboBox
+
+ Layout.fillWidth: true
+ onCurrentIndexChanged: value = comboBox.textAt(currentIndex)
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerPropertySlider.qml b/src/Authoring/Studio/Palettes/Action/HandlerPropertySlider.qml
new file mode 100644
index 00000000..aecdcfd4
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerPropertySlider.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+/*
+* Use for: Opacity, Edge Tesselation Value, Inner Tesselation Value ...
+* For the latter two set sliderMax to 64
+*/
+
+GridLayout {
+ id: root
+
+ property alias value: propertySlider.value
+ property alias sliderMin: propertySlider.sliderMin
+ property alias sliderMax: propertySlider.sliderMax
+ property alias label: labelItem.text
+ property bool intSlider: propertySlider.intSlider
+ property int decimalSlider: propertySlider.decimalSlider
+ property alias tabItem1: propertySlider.tabItem1
+
+ signal editingFinished
+
+ columns: 3
+
+ StyledLabel {
+ id: labelItem
+ text: label
+ }
+
+ HandlerPropertyBaseSlider {
+ id: propertySlider
+ // proxy the signal upwards
+ onEditingFinished: root.editingFinished()
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/HandlerPropertyXYZ.qml b/src/Authoring/Studio/Palettes/Action/HandlerPropertyXYZ.qml
new file mode 100644
index 00000000..eef611ce
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/HandlerPropertyXYZ.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+/* Use for: Position, Rotation, Scale, Pivot ... */
+
+RowLayout {
+ id: root
+
+ property alias valueX: propertyXYZ.valueX
+ property alias valueY: propertyXYZ.valueY
+ property alias valueZ: propertyXYZ.valueZ
+ property alias label: labelItem.text
+ property alias tabItem1: propertyXYZ.tabItem1
+ property alias tabItem2: propertyXYZ.tabItem2
+ property alias tabItem3: propertyXYZ.tabItem3
+
+ signal editingFinished
+
+ StyledLabel {
+ id: labelItem
+ Layout.alignment: Qt.AlignTop | Qt.AlignLeft
+ text: qsTr("New Value")
+ }
+
+ HandlerPropertyBaseXYZ {
+ id: propertyXYZ
+ Layout.alignment: Qt.AlignRight
+
+ onEditingFinished: {
+ root.editingFinished();
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/PropertyModel.cpp b/src/Authoring/Studio/Palettes/Action/PropertyModel.cpp
new file mode 100644
index 00000000..5ee896c8
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/PropertyModel.cpp
@@ -0,0 +1,219 @@
+#include "PropertyModel.h"
+
+#include "ClientDataModelBridge.h"
+#include "Core.h"
+#include "Doc.h"
+#include "StudioApp.h"
+
+#include "UICDMActionCore.h"
+#include "UICDMActionInfo.h"
+#include "UICDMDataCore.h"
+#include "UICDMMetaData.h"
+#include "UICDMStudioSystem.h"
+
+
+PropertyModel::PropertyModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+}
+
+void PropertyModel::setAction(const UICDM::CUICDMActionHandle &action)
+{
+ beginResetModel();
+ m_action = action;
+ m_valueHandle = 0;
+ m_nameHandle = 0;
+ m_properties.clear();
+
+ if (action.Valid()) {
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ auto studioSystem = doc->GetStudioSystem();
+ auto propertySystem = studioSystem->GetPropertySystem();
+ auto bridge = studioSystem->GetClientDataModelBridge();
+
+ auto actionInfo = studioSystem->GetActionCore()->GetActionInfo(action);
+
+ UICDM::IMetaData &metaData(*studioSystem->GetActionMetaData());
+ UICDM::TMetaDataPropertyHandleList metaProperties;
+ const auto instance = bridge->GetInstance(actionInfo.m_Owner, actionInfo.m_TargetObject);
+ metaData.GetMetaDataProperties(instance, metaProperties);
+
+ for (const auto &metaProperty: metaProperties) {
+ auto propertyMetaInfo = metaData.GetMetaDataPropertyInfo(metaProperty);
+ if (propertyMetaInfo->m_IsHidden == false) {
+ PropertyInfo property;
+ property.m_handle = propertyMetaInfo->m_Property;
+ property.m_name = QString::fromWCharArray(propertySystem->GetFormalName(instance, property.m_handle).wide_str());
+ property.m_nameId = QString::fromWCharArray(propertySystem->GetName(property.m_handle).wide_str());
+ property.m_type = propertyMetaInfo->GetDataType();
+ property.m_additionalType = propertyMetaInfo->GetAdditionalType();
+
+ const auto additionalMetaDataType = propertySystem->GetAdditionalMetaDataType(instance, property.m_handle);
+ switch (additionalMetaDataType) {
+ case UICDM::AdditionalMetaDataType::Range: {
+ const UICDM::TMetaDataData &metaDataData =
+ propertySystem->GetAdditionalMetaDataData(instance, property.m_handle);
+ UICDM::SMetaDataRange minMax = UICDM::get<UICDM::SMetaDataRange>(metaDataData);
+ property.m_min = minMax.m_Min;
+ property.m_max = minMax.m_Max;
+ break;
+ }
+ case UICDM::AdditionalMetaDataType::StringList: {
+ const UICDM::TMetaDataData &metaDataData =
+ propertySystem->GetAdditionalMetaDataData(instance, property.m_handle);
+ auto values = UICDM::get<UICDM::TMetaDataStringList>(metaDataData);
+ QStringList possibleValues;
+ for (const auto &value: values) {
+ possibleValues.append(QString::fromWCharArray(value.wide_str()));
+ }
+ property.m_possibleValues = possibleValues;
+ break;
+ }
+ case UICDM::AdditionalMetaDataType::Font: {
+ std::vector<Q3DStudio::CString> fontNames;
+ doc->GetProjectFonts(fontNames);
+ QStringList possibleValues;
+ for (const auto &fontName: fontNames) {
+ possibleValues.append(fontName.toQString());
+ }
+ property.m_possibleValues = possibleValues;
+ break;
+ }
+ default:;
+ }
+ m_properties.append(property);
+ }
+ }
+ }
+ endResetModel();
+
+ Q_EMIT valueHandleChanged();
+}
+
+void PropertyModel::setNameHandle(const UICDM::CUICDMHandlerArgHandle &handle)
+{
+ m_nameHandle = handle;
+}
+
+void PropertyModel::setValueHandle(const UICDM::CUICDMHandlerArgHandle &handle)
+{
+ m_valueHandle = handle;
+
+ updateDefaultPropertyIndex();
+ updateValue();
+ if (m_valueHandle != handle)
+ Q_EMIT valueHandleChanged();
+}
+
+int PropertyModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return m_properties.size();
+}
+
+
+QVariant PropertyModel::data(const QModelIndex &index, int role) const
+{
+ if (!hasIndex(index.row(), index.column(), index.parent()))
+ return {};
+
+ const auto property = m_properties.at(index.row());
+
+ switch (role)
+ {
+ case NameRole:
+ return property.m_name;
+ case HandleRole:
+ return property.m_handle.GetHandleValue();
+
+ default:
+ return {};
+ }
+
+ return QVariant();
+}
+
+QHash<int, QByteArray> PropertyModel::roleNames() const
+{
+ auto names = QAbstractItemModel::roleNames();
+ names.insert(NameRole, "name");
+ names.insert(HandleRole, "handle");
+
+ return names;
+}
+
+PropertyInfo PropertyModel::property(int index) const
+{
+ if (index < 0 || index >= m_properties.size() )
+ return {};
+ return m_properties[index];
+}
+
+int PropertyModel::valueHandle() const
+{
+ return m_valueHandle;
+}
+
+QVariant PropertyModel::value() const
+{
+ return m_value;
+}
+
+void PropertyModel::updateDefaultPropertyIndex()
+{
+ if (!m_nameHandle.Valid()) {
+ m_defaultPropertyIndex = -1;
+ Q_EMIT defaultPropertyIndexChanged();
+ return;
+ }
+
+ UICDM::SValue sValue;
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ auto studioSystem = doc->GetStudioSystem();
+ studioSystem->GetActionCore()->GetHandlerArgumentValue(m_nameHandle, sValue);
+
+ if (sValue.getType() != UICDM::DataModelDataType::String) {
+ m_defaultPropertyIndex = -1;
+ Q_EMIT defaultPropertyIndexChanged();
+ return;
+ }
+
+ auto propertyName = UICDM::get<QString>(sValue);
+ auto iter = std::find_if(m_properties.constBegin(), m_properties.constEnd(),
+ [&propertyName](const PropertyInfo &info)
+ {
+ return (info.m_nameId == propertyName);
+ });
+
+ auto index = std::distance(m_properties.constBegin(), iter);
+
+ if (m_defaultPropertyIndex != index) {
+ m_defaultPropertyIndex = index;
+ Q_EMIT defaultPropertyIndexChanged();
+ }
+}
+
+int PropertyModel::defaultPropertyIndex() const
+{
+ return m_defaultPropertyIndex;
+}
+
+void PropertyModel::updateValue()
+{
+ const auto oldValue = m_value;
+ if (!m_valueHandle.Valid()) {
+ m_value.clear();
+ } else {
+ UICDM::SValue sValue;
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ auto studioSystem = doc->GetStudioSystem();
+ studioSystem->GetActionCore()->GetHandlerArgumentValue(m_valueHandle, sValue);
+ m_value = sValue.toQVariant();
+ }
+ if (oldValue != m_value) {
+
+ Q_EMIT valueChanged();
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Action/PropertyModel.h b/src/Authoring/Studio/Palettes/Action/PropertyModel.h
new file mode 100644
index 00000000..293e682e
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Action/PropertyModel.h
@@ -0,0 +1,80 @@
+#ifndef PROPERTYMODEL_H
+#define PROPERTYMODEL_H
+
+#include <QAbstractListModel>
+
+#include "UICDMHandles.h"
+#include "UICDMDataTypes.h"
+#include "UICDMMetaDataTypes.h"
+
+struct PropertyInfo {
+ Q_PROPERTY(QString name MEMBER m_name CONSTANT FINAL)
+ Q_PROPERTY(float min MEMBER m_min CONSTANT FINAL)
+ Q_PROPERTY(float max MEMBER m_max CONSTANT FINAL)
+ Q_PROPERTY(UICDM::DataModelDataType::Value type MEMBER m_type CONSTANT FINAL)
+ Q_PROPERTY(UICDM::AdditionalMetaDataType::Value additionalType MEMBER m_additionalType CONSTANT FINAL)
+ Q_PROPERTY(QStringList possibleValues MEMBER m_possibleValues CONSTANT FINAL)
+
+ UICDM::CUICDMPropertyHandle m_handle;
+ QString m_name;
+ QString m_nameId;
+ UICDM::DataModelDataType::Value m_type;
+ UICDM::AdditionalMetaDataType::Value m_additionalType;
+ QStringList m_possibleValues;
+ float m_min = 0.0f;
+ float m_max = 0.0f;
+
+ Q_GADGET
+};
+
+class PropertyModel : public QAbstractListModel
+{
+ Q_PROPERTY(int valueHandle READ valueHandle NOTIFY valueHandleChanged FINAL)
+ Q_PROPERTY(QVariant value READ value NOTIFY valueChanged FINAL)
+ Q_PROPERTY(int defaultPropertyIndex READ defaultPropertyIndex NOTIFY defaultPropertyIndexChanged FINAL)
+ Q_OBJECT
+
+public:
+ explicit PropertyModel(QObject *parent = nullptr);
+
+ enum Roles {
+ NameRole = Qt::DisplayRole,
+ HandleRole = Qt::UserRole + 1
+ };
+
+ void setAction(const UICDM::CUICDMActionHandle &action);
+ void setNameHandle(const UICDM::CUICDMHandlerArgHandle &valueHandle);
+ void setValueHandle(const UICDM::CUICDMHandlerArgHandle &valueHandle);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ QHash<int, QByteArray> roleNames() const override;
+
+ PropertyInfo property(int index) const;
+ UICDM::CUICDMActionHandle action() const { return m_action; }
+ int valueHandle() const;
+
+ QVariant value() const;
+ int defaultPropertyIndex() const;
+
+Q_SIGNALS:
+ void valueHandleChanged();
+ void valueChanged();
+ void defaultPropertyIndexChanged();
+
+private:
+ void updateValue();
+ void updateDefaultPropertyIndex();
+
+ QVector<PropertyInfo> m_properties;
+ UICDM::CUICDMActionHandle m_action;
+ UICDM::CUICDMHandlerArgHandle m_nameHandle;
+ UICDM::CUICDMHandlerArgHandle m_valueHandle;
+ int m_defaultPropertyIndex = -1;
+ QVariant m_value;
+};
+
+Q_DECLARE_METATYPE(PropertyInfo)
+
+#endif // PROPERTYMODEL_H
diff --git a/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.cpp b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.cpp
new file mode 100644
index 00000000..9ceee2d2
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.cpp
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "BasicObjectsModel.h"
+#include "DropSource.h"
+#include "Literals.h"
+#include "StudioUtils.h"
+
+#include <QCoreApplication>
+#include <QDataStream>
+#include <QMimeData>
+
+BasicObjectsModel::BasicObjectsModel(QObject *parent) : QAbstractListModel(parent)
+{
+ initialize();
+}
+
+void BasicObjectsModel::initialize()
+{
+ m_ObjectItems = {
+ {tr("Rectangle"), "Asset-Rectangle-Normal.png"_L1, OBJTYPE_MODEL, PRIMITIVETYPE_RECT},
+ {tr("Sphere"), "Asset-Sphere-Normal.png"_L1, OBJTYPE_MODEL, PRIMITIVETYPE_SPHERE},
+ {tr("Cube"), "Asset-Cube-Normal.png"_L1, OBJTYPE_MODEL, PRIMITIVETYPE_BOX},
+ {tr("Cylinder"), "Asset-Cylinder-Normal.png"_L1, OBJTYPE_MODEL, PRIMITIVETYPE_CYLINDER},
+ {tr("Cone"), "Asset-Cone-Normal.png"_L1, OBJTYPE_MODEL, PRIMITIVETYPE_CONE},
+ {tr("Component"), "Asset-Component-Normal.png"_L1, OBJTYPE_COMPONENT, PRIMITIVETYPE_UNKNOWN},
+ {tr("Group"), "Asset-Group-Normal.png"_L1, OBJTYPE_GROUP, PRIMITIVETYPE_UNKNOWN},
+ {tr("Text"), "Asset-Text-Normal.png"_L1, OBJTYPE_TEXT, PRIMITIVETYPE_UNKNOWN},
+ {tr("Layer"), "Asset-Layer-Normal.png"_L1, OBJTYPE_LAYER, PRIMITIVETYPE_UNKNOWN},
+ {tr("Camera"), "Asset-Camera-Normal.png"_L1, OBJTYPE_CAMERA, PRIMITIVETYPE_UNKNOWN},
+ {tr("Light"), "Asset-Light-Normal.png"_L1, OBJTYPE_LIGHT, PRIMITIVETYPE_UNKNOWN},
+ {tr("Alias"), "Asset-Alias-Normal.png"_L1, OBJTYPE_ALIAS, PRIMITIVETYPE_UNKNOWN}
+ };
+}
+
+QVariant BasicObjectsModel::data(const QModelIndex &index, int role) const
+{
+ if (!hasIndex(index.row(), index.column(),index.parent()))
+ return {};
+
+ const auto row = index.row();
+
+ switch (role) {
+ case NameRole: return m_ObjectItems.at(row).name();
+ case IconRole: return resourceImageUrl() +
+ m_ObjectItems.at(row).icon();
+ case ObjectTypeRole: return m_ObjectItems.at(row).objectType();
+ case PrimitiveTypeRole: return m_ObjectItems.at(row).primitiveType();
+ }
+
+ return {};
+}
+
+int BasicObjectsModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+ return m_ObjectItems.count();
+}
+
+QHash<int, QByteArray> BasicObjectsModel::roleNames() const
+{
+ auto names = QAbstractListModel::roleNames();
+ names.insert(NameRole, "name");
+ names.insert(IconRole, "icon");
+
+ return names;
+}
+
+Qt::ItemFlags BasicObjectsModel::flags(const QModelIndex &index) const {
+ if (index.isValid())
+ return Qt::ItemIsDragEnabled;
+
+ return QAbstractListModel::flags(index);
+}
+
+QStringList BasicObjectsModel::mimeTypes() const
+{
+ return { m_MimeType };
+}
+
+QMimeData *BasicObjectsModel::mimeData(const QModelIndexList &indexes) const
+{
+
+ const auto row = indexes.first().row(); // we support only one item for D&D
+ auto object = m_ObjectItems.at(row);
+
+ auto *data = CDropSourceFactory::Create(object.GetFlavor(), &object);
+ return data;
+}
+
+BasicObjectItem::~BasicObjectItem()
+{
+}
diff --git a/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.h b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.h
new file mode 100644
index 00000000..ccaf07d6
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BASICOBJECTSMODEL_H
+#define BASICOBJECTSMODEL_H
+
+#include <QAbstractListModel>
+
+#include "IDragable.h"
+#include "StudioObjectTypes.h"
+
+class BasicObjectItem : public IDragable {
+
+public:
+ BasicObjectItem() {}
+ BasicObjectItem(const QString &name, const QString &icon,
+ EStudioObjectType objectType, EPrimitiveType primitiveType)
+ : m_name(name), m_icon(icon)
+ , m_objectType(objectType), m_primitiveType(primitiveType)
+ { }
+
+ virtual ~BasicObjectItem();
+
+ QString name() const { return m_name; }
+ QString icon() const { return m_icon; }
+
+ EStudioObjectType objectType() const { return m_objectType; }
+ EPrimitiveType primitiveType() const { return m_primitiveType; }
+
+ void setName(const QString &name) { m_name = name; }
+ void setIcon(const QString &icon) { m_icon = icon; }
+ void setObjectType(EStudioObjectType type) { m_objectType = type; }
+ void setPrimitveType(EPrimitiveType type) { m_primitiveType = type; }
+
+ long GetFlavor() const override {return EUIC_FLAVOR_BASIC_OBJECTS;}
+
+private:
+ QString m_name;
+ QString m_icon;
+ EStudioObjectType m_objectType;
+ EPrimitiveType m_primitiveType;
+};
+
+class BasicObjectsModel : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ BasicObjectsModel(QObject *parent = nullptr);
+
+ enum Roles {
+ NameRole = Qt::DisplayRole,
+ IconRole = Qt::DecorationRole,
+ ObjectTypeRole = Qt::UserRole + 1,
+ PrimitiveTypeRole
+ };
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QHash<int, QByteArray> roleNames() const override;
+
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
+ QStringList mimeTypes() const override;
+ QMimeData *mimeData(const QModelIndexList &indexes) const override;
+
+private:
+ void initialize();
+
+ QVector<BasicObjectItem> m_ObjectItems;
+
+ const QString m_MimeType = QLatin1String("application/x-basic-object");
+};
+
+#endif // BASICOBJECTSMODEL_H
diff --git a/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.cpp b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.cpp
new file mode 100644
index 00000000..6834352a
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "BasicObjectsView.h"
+#include "BasicObjectsModel.h"
+#include "CColor.h"
+#include "Literals.h"
+#include "StudioPreferences.h"
+#include "StudioUtils.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qtimer.h>
+#include <QtGui/qdrag.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+
+BasicObjectsView::BasicObjectsView(QWidget *parent) : QQuickWidget(parent)
+ , m_ObjectsModel(new BasicObjectsModel(this))
+
+{
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QTimer::singleShot(0, this, &BasicObjectsView::initialize);
+}
+
+QSize BasicObjectsView::sizeHint() const
+{
+ return {120, 600};
+}
+
+void BasicObjectsView::startDrag(int row)
+{
+ const auto index = m_ObjectsModel->index(row);
+
+ QDrag drag(this);
+ drag.setMimeData(m_ObjectsModel->mimeData({index}));
+ drag.setPixmap(QPixmap(index.data(BasicObjectsModel::IconRole).toUrl().toLocalFile()));
+ drag.exec(Qt::CopyAction);
+}
+
+void BasicObjectsView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty("_basicObjectsModel"_L1, m_ObjectsModel);
+ rootContext()->setContextProperty("_basicObjectsView"_L1, this);
+ rootContext()->setContextProperty("_resDir"_L1, resourceImageUrl());
+
+ engine()->addImportPath(qmlImportPath());
+ setSource(QUrl("qrc:/Studio/Palettes/BasicObjects/BasicObjectsView.qml"_L1));
+}
diff --git a/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.h b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.h
new file mode 100644
index 00000000..9317fc8f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef BASICOBJECTSVIEW_H
+#define BASICOBJECTSVIEW_H
+
+#include <QQuickWidget>
+
+class BasicObjectsModel;
+
+class BasicObjectsView : public QQuickWidget
+{
+ Q_OBJECT
+public:
+ explicit BasicObjectsView(QWidget *parent = nullptr);
+
+ QSize sizeHint() const override;
+
+ Q_INVOKABLE void startDrag(int row);
+private:
+ void initialize();
+
+ BasicObjectsModel *m_ObjectsModel = nullptr;
+ QColor m_BaseColor = QColor::fromRgb(75, 75, 75);
+};
+
+#endif // BASICOBJECTSVIEW_H
diff --git a/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.qml b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.qml
new file mode 100644
index 00000000..ec2a0f6e
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.1
+import "../controls"
+
+Rectangle {
+
+ color: _backgroundColor
+
+ ListView {
+ anchors {
+ fill: parent
+ leftMargin: 8
+ }
+ boundsBehavior: Flickable.StopAtBounds
+
+ model: _basicObjectsModel
+ spacing: 2
+
+ ScrollBar.vertical: ScrollBar {}
+
+ delegate: Item {
+ height: contentRow.height
+ width: contentRow.width
+ Item {
+ id: dragItem
+ anchors.fill: parent
+
+ Drag.active: dragArea.drag.active
+ Drag.hotSpot.x: width / 2
+ Drag.hotSpot.y: height / 2
+ Drag.dragType: Drag.Automatic
+ Drag.supportedActions: Qt.CopyAction
+
+ MouseArea {
+ id: dragArea
+ property bool dragging: false
+ anchors.fill: parent
+ drag.target: dragItem
+ }
+
+ Drag.onDragStarted: _basicObjectsView.startDrag(model.index)
+ }
+ Row {
+ id: contentRow
+ spacing: 4
+ Image {
+ id: assetIcon
+ width: 24
+ height: 24
+ fillMode: Image.Pad
+ source: model.icon
+ }
+ StyledLabel {
+ y: (assetIcon.height - height) / 2
+ text: model.name
+ }
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ChooserDelegate.qml b/src/Authoring/Studio/Palettes/Inspector/ChooserDelegate.qml
new file mode 100644
index 00000000..6ee4445c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ChooserDelegate.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+Rectangle {
+ id: item
+
+ signal clicked(string filePath)
+ signal doubleClicked(string filePath)
+
+ width: parent.width
+ height: 20
+ color: isCurrentFile ? _selectionColor : "transparent"
+
+ Row {
+ x: depth*28
+ anchors.verticalCenter: item.verticalCenter
+
+ Image {
+ source: _resDir + (expanded ? "arrow_down.png" : "arrow.png")
+ opacity: isExpandable ? 1 : 0
+
+ MouseArea {
+ visible: isExpandable
+ anchors.fill: parent
+ onClicked: {
+ if (expanded)
+ listView.model.collapse(index)
+ else
+ listView.model.expand(index)
+ }
+ }
+ }
+
+ Image {
+ source: fileIcon
+ }
+
+ StyledLabel {
+ text: fileName
+ color: _textColor
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.LeftButton
+ visible: isSelectable
+ onClicked: item.clicked(filePath)
+ onDoubleClicked: item.doubleClicked(filePath)
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp b/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp
new file mode 100644
index 00000000..87df1b45
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp
@@ -0,0 +1,592 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QSet>
+
+#include "stdafx.h"
+
+#include "ChooserModelBase.h"
+#include "Core.h"
+#include "Dispatch.h"
+#include "Doc.h"
+#include "StudioUtils.h"
+#include "UICFileTools.h"
+#include "ImportUtils.h"
+#include "StudioApp.h"
+
+ChooserModelBase::ChooserModelBase(QObject *parent) : QAbstractListModel(parent)
+ , m_model(new QFileSystemModel(this))
+{
+ connect(m_model, &QAbstractItemModel::rowsInserted, this, &ChooserModelBase::modelRowsInserted);
+ connect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved, this, &ChooserModelBase::modelRowsRemoved);
+ connect(m_model, &QAbstractItemModel::layoutChanged, this, &ChooserModelBase::modelLayoutChanged);
+
+ g_StudioApp.GetCore()->GetDispatch()->AddPresentationChangeListener(this);
+
+ rebuild();
+}
+
+ChooserModelBase::~ChooserModelBase()
+{
+ g_StudioApp.GetCore()->GetDispatch()->RemovePresentationChangeListener(this);
+}
+
+QHash<int, QByteArray> ChooserModelBase::roleNames() const
+{
+ auto modelRoleNames = m_model->roleNames();
+ modelRoleNames.insert(IsExpandableRole, "isExpandable");
+ modelRoleNames.insert(DepthRole, "depth");
+ modelRoleNames.insert(ExpandedRole, "expanded");
+ modelRoleNames.insert(IsSelectableRole, "isSelectable");
+ modelRoleNames.insert(IsCurrentFile, "isCurrentFile");
+ return modelRoleNames;
+}
+
+int ChooserModelBase::rowCount(const QModelIndex &) const
+{
+ return getFixedItems().count() + m_items.count();
+}
+
+QVariant ChooserModelBase::data(const QModelIndex &index, int role) const
+{
+ const int row = index.row();
+
+ const auto fixedItems = getFixedItems();
+ const int fixedItemCount = fixedItems.count();
+
+ if (row < fixedItemCount) {
+ const auto &item = fixedItems.at(row);
+
+ switch (role) {
+ case Qt::DecorationRole:
+ return resourceImageUrl() + CStudioObjectTypes::GetNormalIconName(item.iconType);
+
+ case IsExpandableRole:
+ return false;
+
+ case DepthRole:
+ return 0;
+
+ case ExpandedRole:
+ return false;
+
+ case IsSelectableRole:
+ return true;
+
+ case IsCurrentFile:
+ return item.name == m_currentFile;
+
+ default:
+ return item.name;
+ }
+ } else {
+ const auto &item = m_items.at(row - fixedItemCount);
+
+ switch (role) {
+ case Qt::DecorationRole: {
+ QString path = item.index.data(QFileSystemModel::FilePathRole).toString();
+ return resourceImageUrl() + getIconName(path);
+ }
+
+ case IsExpandableRole: {
+ QFileInfo fileInfo(item.index.data(QFileSystemModel::FilePathRole).toString());
+ return fileInfo.isDir();
+ }
+
+ case DepthRole:
+ return item.depth;
+
+ case ExpandedRole:
+ return item.expanded;
+
+ case IsSelectableRole: {
+ QFileInfo fileInfo(item.index.data(QFileSystemModel::FilePathRole).toString());
+ return fileInfo.isFile();
+ }
+
+ case IsCurrentFile: {
+ QString path = item.index.data(QFileSystemModel::FilePathRole).toString();
+ return path == m_currentFile;
+ }
+
+ default:
+ return m_model->data(item.index, role);
+ }
+ }
+}
+
+void ChooserModelBase::setCurrentFile(const QString &path)
+{
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ const QDir documentDir(doc->GetDocumentDirectory().toQString());
+ const QString fullPath = QDir::cleanPath(documentDir.filePath(path));
+
+ if (fullPath != m_currentFile) {
+ const auto fixedItems = getFixedItems();
+
+ const auto fileRow = [this, &fixedItems](const QString &path)
+ {
+ const int fixedItemCount = fixedItems.count();
+
+ for (int i = 0; i < fixedItemCount; ++i) {
+ const auto &item = fixedItems.at(i);
+
+ if (item.name == path)
+ return i;
+ }
+
+ const int itemCount = m_items.count();
+
+ for (int i = 0; i < itemCount; ++i) {
+ const auto &item = m_items.at(i);
+
+ if (item.index.data(QFileSystemModel::FilePathRole).toString() == path)
+ return fixedItemCount + i;
+ }
+
+ return -1;
+ };
+
+ int previousRow = fileRow(m_currentFile);
+ int currentRow = fileRow(fullPath);
+
+ m_currentFile = fullPath;
+
+ const int fixedItemCount = fixedItems.count();
+
+ if (previousRow != -1)
+ Q_EMIT dataChanged(index(previousRow), index(previousRow));
+
+ if (currentRow != -1)
+ Q_EMIT dataChanged(index(currentRow), index(currentRow));
+ }
+
+ // expand parent folder if current file is hidden
+ auto matched = m_model->match(m_rootIndex, QFileSystemModel::FilePathRole, path, 1,
+ Qt::MatchExactly|Qt::MatchRecursive);
+ if (!matched.isEmpty()) {
+ auto modelIndex = matched.first();
+ if (modelIndexRow(modelIndex) == -1)
+ expand(m_model->parent(modelIndex));
+ }
+}
+
+void ChooserModelBase::expand(const QModelIndex &modelIndex)
+{
+ if (modelIndex == m_rootIndex)
+ return;
+
+ int row = modelIndexRow(modelIndex);
+ if (row == -1) {
+ QModelIndex parentIndex = m_model->parent(modelIndex);
+ expand(parentIndex);
+
+ row = modelIndexRow(modelIndex);
+ Q_ASSERT(row != -1);
+ }
+
+ if (!m_items.at(row).expanded)
+ expand(row + getFixedItems().count());
+}
+
+void ChooserModelBase::setRootPath(const QString &path)
+{
+ setRootIndex(m_model->setRootPath(path));
+}
+
+void ChooserModelBase::setRootIndex(const QModelIndex &rootIndex)
+{
+ if (rootIndex != m_rootIndex) {
+ clearModelData();
+ m_rootIndex = rootIndex;
+ showModelTopLevelItems();
+ }
+}
+
+void ChooserModelBase::clearModelData()
+{
+ if (!m_items.isEmpty()) {
+ const auto fixedItemCount = getFixedItems().count();
+ beginRemoveRows({}, fixedItemCount, fixedItemCount + m_items.count() - 1);
+ m_items.clear();
+ endRemoveRows();
+ }
+}
+
+void ChooserModelBase::showModelTopLevelItems()
+{
+ int rowCount = m_model->rowCount(m_rootIndex);
+
+ if (rowCount == 0) {
+ if (m_model->hasChildren(m_rootIndex) && m_model->canFetchMore(m_rootIndex))
+ m_model->fetchMore(m_rootIndex);
+ } else {
+ showModelChildItems(m_rootIndex, 0, rowCount - 1);
+
+ for (int i = 0; i < rowCount; ++i) {
+ const auto &childIndex = m_model->index(i, 0, m_rootIndex);
+ if (m_model->hasChildren(childIndex) && m_model->canFetchMore(childIndex))
+ m_model->fetchMore(childIndex);
+ }
+ }
+}
+
+void ChooserModelBase::showModelChildItems(const QModelIndex &parentIndex, int start, int end)
+{
+ QVector<QModelIndex> rowsToInsert;
+ for (int i = start; i <= end; ++i) {
+ const auto &childIndex = m_model->index(i, 0, parentIndex);
+ if (isVisible(childIndex))
+ rowsToInsert.append(childIndex);
+ }
+
+ const int insertCount = rowsToInsert.count();
+
+ if (insertCount != 0) {
+ TreeItem *parent;
+ int depth, startRow;
+
+ if (parentIndex == m_rootIndex) {
+ parent = nullptr;
+ depth = 0;
+ startRow = 0;
+ } else {
+ const int parentRow = modelIndexRow(parentIndex);
+ Q_ASSERT(parentRow != -1 && isVisible(parentIndex));
+ parent = &m_items[parentRow];
+ depth = parent->depth + 1;
+ startRow = parentRow + parent->childCount + 1;
+ }
+
+ const int fixedItemCount = getFixedItems().count();
+ beginInsertRows({}, startRow + fixedItemCount, startRow + fixedItemCount + insertCount - 1);
+
+ for (auto it = rowsToInsert.rbegin(); it != rowsToInsert.rend(); ++it)
+ m_items.insert(startRow, { *it, depth, false, parent, 0 });
+
+ for (; parent != nullptr; parent = parent->parent)
+ parent->childCount += insertCount;
+
+ endInsertRows();
+ }
+}
+
+void ChooserModelBase::expand(int row)
+{
+ const int fixedItemCount = getFixedItems().count();
+ Q_ASSERT(row >= fixedItemCount && row < fixedItemCount + m_items.count());
+
+ auto &item = m_items[row - fixedItemCount];
+ Q_ASSERT(item.expanded == false);
+
+ const auto &modelIndex = item.index;
+
+ const int rowCount = m_model->rowCount(modelIndex);
+ if (rowCount == 0) {
+ if (m_model->hasChildren(modelIndex) && m_model->canFetchMore(modelIndex))
+ m_model->fetchMore(modelIndex);
+ } else {
+ showModelChildItems(modelIndex, 0, rowCount - 1);
+ }
+
+ item.expanded = true;
+ Q_EMIT dataChanged(index(row), index(row));
+}
+
+void ChooserModelBase::collapse(int row)
+{
+ const int fixedItemCount = getFixedItems().count();
+ Q_ASSERT(row >= fixedItemCount && row < fixedItemCount + m_items.count());
+
+ auto &item = m_items[row - fixedItemCount];
+ Q_ASSERT(item.expanded == true);
+
+ const int childCount = item.childCount;
+
+ if (childCount > 0) {
+ beginRemoveRows({}, row + 1, row + childCount);
+
+ auto first = std::begin(m_items) + row - fixedItemCount + 1;
+ m_items.erase(first, first + childCount);
+
+ for (auto parent = &item; parent != nullptr; parent = parent->parent)
+ parent->childCount -= childCount;
+
+ endRemoveRows();
+ }
+
+ item.expanded = false;
+ Q_EMIT dataChanged(index(row), index(row));
+}
+
+void ChooserModelBase::OnNewPresentation()
+{
+ rebuild();
+}
+
+int ChooserModelBase::modelIndexRow(const QModelIndex &modelIndex) const
+{
+ auto it = std::find_if(std::begin(m_items), std::end(m_items),
+ [&modelIndex](const TreeItem &item)
+ {
+ return item.index == modelIndex;
+ });
+
+ return it != std::end(m_items) ? std::distance(std::begin(m_items), it) : -1;
+}
+
+bool ChooserModelBase::isExpanded(const QModelIndex &modelIndex) const
+{
+ if (modelIndex == m_rootIndex) {
+ return true;
+ } else {
+ const int row = modelIndexRow(modelIndex);
+ return row != -1 && m_items.at(row).expanded;
+ }
+}
+
+EStudioObjectType ChooserModelBase::getIconType(const QString &path) const
+{
+ return Q3DStudio::ImportUtils::GetObjectFileTypeForFile(Q3DStudio::CFilePath::fromQString(path)).m_IconType;
+}
+
+QString ChooserModelBase::getIconName(const QString &path) const
+{
+ QString iconName;
+
+ QFileInfo fileInfo(path);
+ if (fileInfo.isFile()) {
+ EStudioObjectType type = getIconType(path);
+ if (type != OBJTYPE_UNKNOWN)
+ iconName = CStudioObjectTypes::GetNormalIconName(type);
+ else
+ iconName = QStringLiteral("Objects-Layer-Normal.png");
+ } else {
+ iconName = QStringLiteral("Objects-Folder-Normal.png");
+ }
+
+ return iconName;
+}
+
+bool ChooserModelBase::isVisible(const QModelIndex &modelIndex) const
+{
+ QString path = modelIndex.data(QFileSystemModel::FilePathRole).toString();
+ QFileInfo fileInfo(path);
+
+ if (fileInfo.isFile()) {
+ return isVisible(path);
+ } else {
+ return hasVisibleChildren(modelIndex);
+ }
+}
+
+bool ChooserModelBase::hasVisibleChildren(const QModelIndex &modelIndex) const
+{
+ int rowCount = m_model->rowCount(modelIndex);
+
+ for (int i = 0; i < rowCount; ++i) {
+ const auto &childIndex = m_model->index(i, 0, modelIndex);
+
+ if (m_model->hasChildren(childIndex)) {
+ if (hasVisibleChildren(childIndex))
+ return true;
+ } else {
+ QString path = childIndex.data(QFileSystemModel::FilePathRole).toString();
+ QFileInfo fileInfo(path);
+ if (fileInfo.isFile() && isVisible(path))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ChooserModelBase::modelRowsInserted(const QModelIndex &parentIndex, int start, int end)
+{
+ if (!m_rootIndex.isValid())
+ return;
+
+ if (isExpanded(parentIndex)) {
+ showModelChildItems(parentIndex, start, end);
+ } else {
+ if (modelIndexRow(parentIndex) == -1) {
+ // parent wasn't inserted in model yet, check if any of the new rows is visible
+
+ bool visible = false;
+
+ for (int i = start; i <= end; ++i) {
+ const auto &childIndex = m_model->index(i, 0, parentIndex);
+ QString path = childIndex.data(QFileSystemModel::FilePathRole).toString();
+ QFileInfo fileInfo(path);
+ if (fileInfo.isFile() && isVisible(path)) {
+ visible = true;
+ break;
+ }
+ }
+
+ // if any of the new rows is visible, insert parent folder index into model
+
+ if (visible) {
+ QModelIndex index = parentIndex, parent = m_model->parent(parentIndex);
+
+ while (parent != m_rootIndex && modelIndexRow(parent) == -1) {
+ index = parent;
+ parent = m_model->parent(parent);
+ }
+
+ if (isExpanded(parent) && modelIndexRow(index) == -1) {
+ const int row = index.row();
+ showModelChildItems(parent, row, row);
+ }
+ }
+ }
+
+ // if one of the new rows is the current file expand parent folder
+
+ bool containsCurrent = false;
+
+ for (int i = start; i <= end; ++i) {
+ const auto &childIndex = m_model->index(i, 0, parentIndex);
+ if (childIndex.data(QFileSystemModel::FilePathRole).toString() == m_currentFile) {
+ containsCurrent = true;
+ break;
+ }
+ }
+
+ if (containsCurrent)
+ expand(parentIndex);
+ }
+
+ // fetch children so we're notified when files are added or removed
+
+ for (int i = start; i <= end; ++i) {
+ const auto &childIndex = m_model->index(i, 0, parentIndex);
+ if (m_model->hasChildren(childIndex) && m_model->canFetchMore(childIndex))
+ m_model->fetchMore(childIndex);
+ }
+}
+
+void ChooserModelBase::modelRowsRemoved(const QModelIndex &parentIndex, int start, int end)
+{
+ if (!m_rootIndex.isValid())
+ return;
+
+ if (isExpanded(parentIndex)) {
+ const auto fixedItems = getFixedItems();
+
+ const auto removeRow = [this, &fixedItems](int row)
+ {
+ const auto &item = m_items.at(row);
+
+ const int fixedItemCount = fixedItems.count();
+ beginRemoveRows({}, row + fixedItemCount, row + fixedItemCount + item.childCount);
+
+ for (auto parent = item.parent; parent != nullptr; parent = parent->parent)
+ parent->childCount -= 1 + item.childCount;
+
+ m_items.erase(std::begin(m_items) + row, std::begin(m_items) + row + item.childCount + 1);
+
+ endRemoveRows();
+ };
+
+ // remove rows
+
+ for (int i = start; i <= end; ++i) {
+ const int row = modelIndexRow(m_model->index(i, 0, parentIndex));
+ if (row != -1)
+ removeRow(row);
+ }
+
+ // also remove folder row if there are no more visible children
+
+ QModelIndex index = parentIndex;
+
+ while (index != m_rootIndex && !hasVisibleChildren(index)) {
+ const int row = modelIndexRow(index);
+ Q_ASSERT(row != -1);
+ removeRow(row);
+ index = m_model->parent(index);
+ }
+ }
+}
+
+void ChooserModelBase::modelLayoutChanged()
+{
+ if (!m_rootIndex.isValid())
+ return;
+
+ QSet<QPersistentModelIndex> expandedItems;
+ for (const auto &item : m_items) {
+ if (item.expanded)
+ expandedItems.insert(item.index);
+ }
+
+ const std::function<int(const QModelIndex &, TreeItem *)> insertChildren =
+ [this, &expandedItems, &insertChildren](const QModelIndex &parentIndex, TreeItem *parent)
+ {
+ Q_ASSERT(parentIndex == m_rootIndex || isVisible(parentIndex));
+
+ const int rowCount = m_model->rowCount(parentIndex);
+ const int depth = parent == nullptr ? 0 : parent->depth + 1;
+
+ int childCount = 0;
+
+ for (int i = 0; i < rowCount; ++i) {
+ const auto &childIndex = m_model->index(i, 0, parentIndex);
+ if (isVisible(childIndex)) {
+ const bool expanded = expandedItems.contains(childIndex);
+ m_items.append({ childIndex, depth, expanded, parent, 0 });
+ auto &item = m_items.last();
+ if (expanded) {
+ item.childCount = insertChildren(childIndex, &item);
+ childCount += item.childCount;
+ }
+ ++childCount;
+ }
+ }
+
+ return childCount;
+ };
+
+ const int itemCount = m_items.count();
+
+ m_items.clear();
+ m_items.reserve(itemCount);
+
+ insertChildren(m_rootIndex, nullptr);
+ Q_ASSERT(m_items.count() == itemCount);
+
+ const int fixedItemCount = getFixedItems().count();
+ Q_EMIT dataChanged(index(fixedItemCount), index(fixedItemCount + itemCount - 1));
+}
+
+void ChooserModelBase::rebuild()
+{
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ const Q3DStudio::CFilePath path(doc->GetDocumentPath().GetAbsolutePath());
+ setRootPath(path.GetDirectory().toQString());
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.h b/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.h
new file mode 100644
index 00000000..547822ea
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef CHOOSERMODELBASE_H
+#define CHOOSERMODELBASE_H
+
+#include "DispatchListeners.h"
+#include "StudioObjectTypes.h"
+
+#include <QFileSystemModel>
+#include <QAbstractListModel>
+#include <QList>
+#include <QVector>
+
+class QFileSystemModel;
+
+class ChooserModelBase : public QAbstractListModel, public CPresentationChangeListener
+{
+ Q_OBJECT
+
+public:
+ explicit ChooserModelBase(QObject *parent = nullptr);
+ ~ChooserModelBase();
+
+ enum {
+ IsExpandableRole = QFileSystemModel::FilePermissions + 1,
+ DepthRole,
+ ExpandedRole,
+ IsSelectableRole,
+ IsCurrentFile
+ };
+
+ QHash<int, QByteArray> roleNames() const override;
+ int rowCount(const QModelIndex &parent = {}) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+
+ Q_INVOKABLE void expand(int row);
+ Q_INVOKABLE void collapse(int row);
+
+ void setCurrentFile(const QString &path);
+
+ // CPresentationChangeListener
+ void OnNewPresentation() override;
+
+Q_SIGNALS:
+ void modelChanged(QAbstractItemModel *model);
+
+protected:
+ EStudioObjectType getIconType(const QString &path) const;
+
+ virtual bool isVisible(const QString &path) const = 0;
+
+ struct FixedItem
+ {
+ EStudioObjectType iconType;
+ QString name;
+ };
+
+ virtual const QVector<FixedItem> getFixedItems() const = 0;
+
+private:
+ void setRootPath(const QString &path);
+ void setRootIndex(const QModelIndex &rootIndex);
+ void clearModelData();
+ void showModelTopLevelItems();
+ void showModelChildItems(const QModelIndex &parentItem, int start, int end);
+ int modelIndexRow(const QModelIndex &modelIndex) const;
+ bool isExpanded(const QModelIndex &modelIndex) const;
+ QString getIconName(const QString &path) const;
+ bool isVisible(const QModelIndex &modelIndex) const;
+ bool hasVisibleChildren(const QModelIndex &modelIndex) const;
+ void expand(const QModelIndex &modelIndex);
+
+ void modelRowsInserted(const QModelIndex &parent, int start, int end);
+ void modelRowsRemoved(const QModelIndex &parent, int start, int end);
+ void modelRowsMoved(const QModelIndex &parent, int start, int end);
+ void modelLayoutChanged();
+
+ void rebuild();
+
+ struct TreeItem {
+ QPersistentModelIndex index;
+ int depth;
+ bool expanded;
+ TreeItem *parent;
+ int childCount;
+ };
+
+ QFileSystemModel *m_model;
+ QPersistentModelIndex m_rootIndex;
+ QList<TreeItem> m_items;
+ QString m_currentFile;
+};
+
+#endif // CHOOSERMODELBASE_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.cpp b/src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.cpp
new file mode 100644
index 00000000..44b89904
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "EasyInspectorGroup.h"
+
+//==============================================================================
+/**
+ * Constructor
+ */
+CEasyInspectorGroup::CEasyInspectorGroup(const QString &inName)
+ : CInspectorGroup()
+{
+ SetName(inName);
+}
+
+//==============================================================================
+/**
+ *
+ */
+CEasyInspectorGroup::~CEasyInspectorGroup()
+{
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.h b/src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.h
new file mode 100644
index 00000000..62cc35a5
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_EASYINSPECTORGROUP_H
+#define INCLUDED_EASYINSPECTORGROUP_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "InspectorGroup.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+
+//==============================================================================
+/**
+ * Simplest possible inspector group
+ */
+class CEasyInspectorGroup : public CInspectorGroup
+{
+public: // Construction
+ CEasyInspectorGroup(const QString &inName);
+ ~CEasyInspectorGroup();
+};
+
+#endif
diff --git a/src/Authoring/Studio/Palettes/Inspector/FileChooser.qml b/src/Authoring/Studio/Palettes/Inspector/FileChooser.qml
new file mode 100644
index 00000000..2762af3a
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/FileChooser.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+Rectangle {
+ id: root
+
+ color: _backgroundColor
+ border.color: _studioColor3
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ spacing: 10
+ ListView {
+ id: listView
+
+ anchors {
+ fill: parent
+ leftMargin: 8
+ }
+
+ boundsBehavior: Flickable.StopAtBounds
+ spacing: 4
+ clip: true
+
+ ScrollBar.vertical: ScrollBar {}
+
+ model: _fileChooserModel
+
+ delegate: ChooserDelegate {
+ onClicked: _fileChooserView.fileSelected(_fileChooserView.handle, _fileChooserView.instance, filePath)
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/FileChooserModel.cpp b/src/Authoring/Studio/Palettes/Inspector/FileChooserModel.cpp
new file mode 100644
index 00000000..6c57635b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/FileChooserModel.cpp
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "FileChooserModel.h"
+
+FileChooserModel::FileChooserModel(QObject *parent)
+ : ChooserModelBase(parent)
+{
+
+}
+
+FileChooserModel::~FileChooserModel()
+{
+}
+
+bool FileChooserModel::isVisible(const QString &path) const
+{
+ return getIconType(path) == OBJTYPE_GROUP;
+}
+
+const QVector<ChooserModelBase::FixedItem> FileChooserModel::getFixedItems() const
+{
+ static const QVector<FixedItem> items = { { OBJTYPE_GROUP, tr("[None]") } };
+ return items;
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/FileChooserModel.h b/src/Authoring/Studio/Palettes/Inspector/FileChooserModel.h
new file mode 100644
index 00000000..c019c4a1
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/FileChooserModel.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FILECHOOSERMODEL_H
+#define FILECHOOSERMODEL_H
+
+#include "ChooserModelBase.h"
+
+class FileChooserModel : public ChooserModelBase
+{
+ Q_OBJECT
+
+public:
+ explicit FileChooserModel(QObject *parent = nullptr);
+ virtual ~FileChooserModel();
+private:
+ bool isVisible(const QString &path) const override;
+ const QVector<FixedItem> getFixedItems() const override;
+};
+
+#endif // IMAGECHOOSERMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/FileChooserView.cpp b/src/Authoring/Studio/Palettes/Inspector/FileChooserView.cpp
new file mode 100644
index 00000000..d5951e7c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/FileChooserView.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "FileChooserView.h"
+#include "FileChooserModel.h"
+#include "Literals.h"
+#include "StudioUtils.h"
+#include "IDocumentEditor.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMValue.h"
+#include "Core.h"
+#include "Doc.h"
+#include "StudioApp.h"
+#include "StudioPreferences.h"
+
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+#include <QtCore/qtimer.h>
+
+FileChooserView::FileChooserView(QWidget *parent)
+ : QQuickWidget(parent)
+ , m_model(new FileChooserModel(this))
+{
+ setWindowTitle(tr("Imports"));
+ setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QTimer::singleShot(0, this, &FileChooserView::initialize);
+}
+
+void FileChooserView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty("_resDir"_L1,
+ resourceImageUrl());
+ rootContext()->setContextProperty("_fileChooserView"_L1, this);
+ rootContext()->setContextProperty("_fileChooserModel"_L1, m_model);
+ engine()->addImportPath(qmlImportPath());
+ setSource(QUrl("qrc:/Studio/Palettes/Inspector/FileChooser.qml"_L1));
+}
+
+QSize FileChooserView::sizeHint() const
+{
+ return {500, 500};
+}
+
+void FileChooserView::setHandle(int handle)
+{
+ m_handle = handle;
+}
+
+int FileChooserView::handle() const
+{
+ return m_handle;
+}
+
+void FileChooserView::setInstance(int instance)
+{
+ m_instance = instance;
+}
+
+int FileChooserView::instance() const
+{
+ return m_instance;
+}
+
+void FileChooserView::focusOutEvent(QFocusEvent *event)
+{
+ QQuickWidget::focusOutEvent(event);
+ QTimer::singleShot(0, this, &FileChooserView::close);
+}
+
+void FileChooserView::showEvent(QShowEvent *event)
+{
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+
+ UICDM::SValue value;
+ propertySystem->GetInstancePropertyValue(m_instance, m_handle, value);
+
+ m_model->setCurrentFile(UICDM::get<QString>(value));
+
+ QQuickWidget::showEvent(event);
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/FileChooserView.h b/src/Authoring/Studio/Palettes/Inspector/FileChooserView.h
new file mode 100644
index 00000000..400f9f1e
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/FileChooserView.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FILECHOOSERVIEW_H
+#define FILECHOOSERVIEW_H
+
+#include <QtQuickWidgets/qquickwidget.h>
+
+class FileChooserModel;
+
+class FileChooserView : public QQuickWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(int instance READ instance)
+ Q_PROPERTY(int handle READ handle)
+
+public:
+ explicit FileChooserView(QWidget *parent = nullptr);
+
+ QSize sizeHint() const override;
+
+ void setHandle(int handle);
+ int handle() const;
+
+ void setInstance(int instance);
+ int instance() const;
+
+Q_SIGNALS:
+ void fileSelected(int handle, int instance, const QString &name);
+
+protected:
+ void focusOutEvent(QFocusEvent *event) override;
+
+private:
+ void showEvent(QShowEvent *event) override;
+ void initialize();
+ int m_handle = -1;
+ int m_instance = -1;
+ FileChooserModel *m_model = nullptr;
+};
+
+#endif // IMAGECHOOSERVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.cpp b/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.cpp
new file mode 100644
index 00000000..f840d92f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.cpp
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** Copyright (C) 1999-2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "stdafx.h"
+#include "GuideInspectable.h"
+#include "InspectableBase.h"
+#include "Core.h"
+#include "Doc.h"
+#include "UICDMGuides.h"
+#include "EasyInspectorGroup.h"
+#include "IDocumentEditor.h"
+#include "UICDMDataTypes.h"
+#include "IInspectableItem.h"
+#include "UICDMValue.h"
+
+typedef std::function<UICDM::SValue()> TGetterFunc;
+typedef std::function<void(UICDM::SValue)> TSetterFunc;
+typedef std::function<void()> TCommitFunc;
+typedef std::function<void()> TCancelFunc;
+
+struct SInspectableDataInfo
+{
+ Q3DStudio::CString m_Name;
+ Q3DStudio::CString m_FormalName;
+ Q3DStudio::CString m_Description;
+ TGetterFunc m_Getter;
+ TSetterFunc m_Setter;
+ TCommitFunc m_Commit;
+ TCancelFunc m_Cancel;
+
+ SInspectableDataInfo(const Q3DStudio::CString &name, const Q3DStudio::CString &formalName,
+ const Q3DStudio::CString &description, TGetterFunc getter, TSetterFunc setter,
+ TCommitFunc commit, TCancelFunc inCancel)
+ : m_Name(name)
+ , m_FormalName(formalName)
+ , m_Description(description)
+ , m_Getter(getter)
+ , m_Setter(setter)
+ , m_Commit(commit)
+ , m_Cancel(inCancel)
+ {
+ }
+};
+
+struct SComboAttItem : public IInspectableAttributeItem
+{
+ SInspectableDataInfo m_BaseInspectableInfo;
+ UICDM::TMetaDataStringList m_MetaDataTypes;
+ SComboAttItem(const SInspectableDataInfo &inInfo, const UICDM::TMetaDataStringList &inTypes)
+ : m_BaseInspectableInfo(inInfo)
+ , m_MetaDataTypes(inTypes)
+ {
+ }
+ UICDM::HandlerArgumentType::Value GetInspectableSubType() const override
+ {
+ return UICDM::HandlerArgumentType::Property;
+ }
+ Q3DStudio::CString GetInspectableName() const override { return m_BaseInspectableInfo.m_Name; }
+ Q3DStudio::CString GetInspectableFormalName() const override
+ {
+ return m_BaseInspectableInfo.m_FormalName;
+ }
+ Q3DStudio::CString GetInspectableDescription() const override
+ {
+ return m_BaseInspectableInfo.m_Description;
+ }
+
+ UICDM::SValue GetInspectableData() const override { return m_BaseInspectableInfo.m_Getter(); }
+ void SetInspectableData(const UICDM::SValue &inValue) override
+ {
+ m_BaseInspectableInfo.m_Setter(inValue);
+ m_BaseInspectableInfo.m_Commit();
+ }
+
+ float GetInspectableMin() const override { return 0; }
+ float GetInspectableMax() const override { return 0; }
+ UICDM::TMetaDataStringList GetInspectableList() const override { return m_MetaDataTypes; }
+ UICDM::DataModelDataType::Value GetInspectableType() const override
+ {
+ return UICDM::DataModelDataType::String;
+ }
+ UICDM::AdditionalMetaDataType::Value GetInspectableAdditionalType() const override
+ {
+ return UICDM::AdditionalMetaDataType::StringList;
+ }
+};
+
+struct SFloatIntItem : public IInspectableAttributeItem
+{
+ SInspectableDataInfo m_BaseInspectableInfo;
+ UICDM::DataModelDataType::Value m_DataType;
+ float m_Min;
+ float m_Max;
+ SFloatIntItem(const SInspectableDataInfo &inInfo, UICDM::DataModelDataType::Value inType,
+ float inMin = 0, float inMax = 0)
+ : m_BaseInspectableInfo(inInfo)
+ , m_DataType(inType)
+ , m_Min(inMin)
+ , m_Max(inMax)
+ {
+ }
+ UICDM::HandlerArgumentType::Value GetInspectableSubType() const override
+ {
+ return UICDM::HandlerArgumentType::Property;
+ }
+ Q3DStudio::CString GetInspectableName() const override { return m_BaseInspectableInfo.m_Name; }
+ Q3DStudio::CString GetInspectableFormalName() const override
+ {
+ return m_BaseInspectableInfo.m_FormalName;
+ }
+ Q3DStudio::CString GetInspectableDescription() const override
+ {
+ return m_BaseInspectableInfo.m_Description;
+ }
+
+ UICDM::SValue GetInspectableData() const override { return m_BaseInspectableInfo.m_Getter(); }
+ void SetInspectableData(const UICDM::SValue &inValue) override
+ {
+ m_BaseInspectableInfo.m_Setter(inValue);
+ m_BaseInspectableInfo.m_Commit();
+ }
+
+ void ChangeInspectableData(const UICDM::SValue &inValue) override
+ {
+ m_BaseInspectableInfo.m_Setter(inValue);
+ }
+ void CancelInspectableData() override { m_BaseInspectableInfo.m_Cancel(); }
+
+ float GetInspectableMin() const override { return m_Min; }
+ float GetInspectableMax() const override { return m_Max; }
+ UICDM::TMetaDataStringList GetInspectableList() const override
+ {
+ return UICDM::TMetaDataStringList();
+ }
+ UICDM::DataModelDataType::Value GetInspectableType() const override { return m_DataType; }
+ UICDM::AdditionalMetaDataType::Value GetInspectableAdditionalType() const override
+ {
+ return UICDM::AdditionalMetaDataType::None;
+ }
+};
+
+
+CInspectableBase *CGuideInspectable::CreateInspectable(CCore &inCore,
+ UICDM::CUICDMGuideHandle inGuide)
+{
+ return new SGuideInspectableImpl(inCore, inGuide);
+}
+
+SGuideInspectableImpl::SGuideInspectableImpl(CCore &inCore, UICDM::CUICDMGuideHandle inGuide)
+ : CInspectableBase(&inCore)
+ , m_Guide(inGuide)
+ , m_Editor(*inCore.GetDoc())
+{
+}
+
+Q3DStudio::IDocumentReader &SGuideInspectableImpl::Reader() const
+{
+ return m_Core->GetDoc()->GetDocumentReader();
+}
+
+EStudioObjectType SGuideInspectableImpl::GetObjectType()
+{
+ return OBJTYPE_GUIDE;
+}
+
+Q3DStudio::CString SGuideInspectableImpl::GetName()
+{
+ return L"Guide";
+}
+
+long SGuideInspectableImpl::GetGroupCount()
+{
+ return 1;
+}
+
+CInspectorGroup *SGuideInspectableImpl::GetGroup(long)
+{
+ CDoc *theDoc = m_Core->GetDoc();
+ TCommitFunc theCommiter = std::bind(&SGuideInspectableImpl::Commit, this);
+ TCancelFunc theCanceler = std::bind(&SGuideInspectableImpl::Rollback, this);
+ m_Properties.push_back(std::make_shared<SFloatIntItem>(
+ SInspectableDataInfo("Position", "Position", "Position of the guide",
+ std::bind(&SGuideInspectableImpl::GetPosition, this),
+ std::bind(&SGuideInspectableImpl::SetPosition, this,
+ std::placeholders::_1),
+ theCommiter, theCanceler),
+ UICDM::DataModelDataType::Float));
+ UICDM::TMetaDataStringList theComboItems;
+ theComboItems.push_back(L"Horizontal");
+ theComboItems.push_back(L"Vertical");
+
+ m_Properties.push_back(std::make_shared<SComboAttItem>(
+ SInspectableDataInfo("Direction", "Direction", "Direction of the guide",
+ std::bind(&SGuideInspectableImpl::GetDirection, this),
+ std::bind(&SGuideInspectableImpl::SetDirection, this,
+ std::placeholders::_1),
+ theCommiter, theCanceler),
+ theComboItems));
+
+ m_Properties.push_back(std::make_shared<SFloatIntItem>(
+ SInspectableDataInfo("Width", "Width", "Width of the guide",
+ std::bind(&SGuideInspectableImpl::GetWidth, this),
+ std::bind(&SGuideInspectableImpl::SetWidth, this, std::placeholders::_1),
+ theCommiter, theCanceler),
+ UICDM::DataModelDataType::Long, 1.0f, 50.0f));
+
+ CEasyInspectorGroup *theNewGroup = new CEasyInspectorGroup(QObject::tr("Basic"));
+ return theNewGroup;
+}
+
+bool SGuideInspectableImpl::IsValid() const
+{
+ return Reader().IsGuideValid(m_Guide);
+}
+
+bool SGuideInspectableImpl::IsMaster()
+{
+ return true;
+}
+
+void SGuideInspectableImpl::SetDirection(const UICDM::SValue &inValue)
+{
+ UICDM::TDataStrPtr theData = inValue.getData<UICDM::TDataStrPtr>();
+ UICDM::SGuideInfo theSetter(Reader().GetGuideInfo(m_Guide));
+ if (theData) {
+ if (UICDM::AreEqual(theData->GetData(), L"Horizontal"))
+ theSetter.m_Direction = UICDM::GuideDirections::Horizontal;
+ else if (UICDM::AreEqual(theData->GetData(), L"Vertical"))
+ theSetter.m_Direction = UICDM::GuideDirections::Vertical;
+ }
+ Editor().UpdateGuide(m_Guide, theSetter);
+ FireRefresh();
+}
+
+UICDM::SValue SGuideInspectableImpl::GetDirection()
+{
+ switch (Reader().GetGuideInfo(m_Guide).m_Direction) {
+ case UICDM::GuideDirections::Horizontal:
+ return std::make_shared<UICDM::CDataStr>(L"Horizontal");
+ case UICDM::GuideDirections::Vertical:
+ return std::make_shared<UICDM::CDataStr>(L"Vertical");
+ default:
+ return std::make_shared<UICDM::CDataStr>(L"");
+ }
+}
+
+void SGuideInspectableImpl::SetPosition(const UICDM::SValue &inValue)
+{
+ float thePos = inValue.getData<float>();
+ UICDM::SGuideInfo theSetter(Reader().GetGuideInfo(m_Guide));
+ theSetter.m_Position = thePos;
+ Editor().UpdateGuide(m_Guide, theSetter);
+ FireRefresh();
+}
+
+UICDM::SValue SGuideInspectableImpl::GetPosition()
+{
+ UICDM::SGuideInfo theSetter(Reader().GetGuideInfo(m_Guide));
+ return theSetter.m_Position;
+}
+
+void SGuideInspectableImpl::SetWidth(const UICDM::SValue &inValue)
+{
+ auto theData = inValue.getData<qt3ds::QT3DSI32>();
+
+ UICDM::SGuideInfo theSetter(Reader().GetGuideInfo(m_Guide));
+ theSetter.m_Width = theData;
+ Editor().UpdateGuide(m_Guide, theSetter);
+ FireRefresh();
+
+}
+
+UICDM::SValue SGuideInspectableImpl::GetWidth()
+{
+ UICDM::SGuideInfo theSetter(Reader().GetGuideInfo(m_Guide));
+ return theSetter.m_Width;
+}
+
+Q3DStudio::IDocumentEditor &SGuideInspectableImpl::Editor()
+{
+ return m_Editor.EnsureEditor(L"Set Property", __FILE__, __LINE__);
+}
+
+void SGuideInspectableImpl::Commit()
+{
+ m_Editor.CommitEditor();
+}
+
+void SGuideInspectableImpl::Rollback()
+{
+ m_Editor.RollbackEditor();
+}
+
+void SGuideInspectableImpl::FireRefresh()
+{
+ m_Editor.FireImmediateRefresh(UICDM::CUICDMInstanceHandle());
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.h b/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.h
new file mode 100644
index 00000000..77ff7a62
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/GuideInspectable.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 1999-2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#ifndef __GUIDEINSPECTABLE_H__
+#define __GUIDEINSPECTABLE_H__
+#include "UICDMHandles.h"
+#include "Core.h"
+#include "InspectableBase.h"
+#include "Doc.h"
+#include "IDocumentEditor.h"
+#include "IInspectableItem.h"
+
+class CInspectableBase;
+
+class CGuideInspectable
+{
+public:
+ static CInspectableBase *CreateInspectable(CCore &inCore, UICDM::CUICDMGuideHandle inGuide);
+};
+
+class SGuideInspectableImpl : public CInspectableBase
+{
+public:
+ SGuideInspectableImpl(CCore &inCore, UICDM::CUICDMGuideHandle inGuide);
+
+ Q3DStudio::IDocumentReader &Reader() const;
+ // Interface
+ EStudioObjectType GetObjectType() override;
+ Q3DStudio::CString GetName() override;
+ long GetGroupCount() override;
+ CInspectorGroup *GetGroup(long) override;
+ bool IsValid() const override;
+ bool IsMaster() override;
+
+ // Implementation to get/set properties
+
+ void SetDirection(const UICDM::SValue &inValue);
+
+ UICDM::SValue GetDirection();
+
+ void SetPosition(const UICDM::SValue &inValue);
+
+ UICDM::SValue GetPosition();
+
+ void SetWidth(const UICDM::SValue &inValue);
+
+ UICDM::SValue GetWidth();
+
+ Q3DStudio::IDocumentEditor &Editor();
+ void Commit();
+ void Rollback();
+ void FireRefresh();
+private:
+ UICDM::CUICDMGuideHandle m_Guide;
+ Q3DStudio::CUpdateableDocumentEditor m_Editor;
+ std::vector<std::shared_ptr<IInspectableAttributeItem>> m_Properties;
+};
+
+
+#endif
diff --git a/src/Authoring/Studio/Palettes/Inspector/HandlerFilesChooser.qml b/src/Authoring/Studio/Palettes/Inspector/HandlerFilesChooser.qml
new file mode 100644
index 00000000..65e0d6be
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/HandlerFilesChooser.qml
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 2.1
+import "../controls"
+
+RowLayout {
+ id: root
+
+ signal showBrowser
+ property string value: ""
+ property alias activeBrowser: browser.activeBrowser
+
+ BrowserCombo {
+ id: browser
+ Layout.preferredWidth: _valueWidth
+ Layout.fillWidth: true
+ value: root.value === "" ? qsTr("Select...") : root.value
+ onShowBrowser: root.showBrowser()
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/HandlerGenericChooser.qml b/src/Authoring/Studio/Palettes/Inspector/HandlerGenericChooser.qml
new file mode 100644
index 00000000..9a8f1688
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/HandlerGenericChooser.qml
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 2.1
+import "../controls"
+
+RowLayout {
+ id: root
+
+ signal showBrowser
+ property alias value: browser.value
+ property alias activeBrowser: browser.activeBrowser
+
+ BrowserCombo {
+ id: browser
+ Layout.preferredWidth: _valueWidth
+ Layout.fillWidth: true
+ onShowBrowser: root.showBrowser()
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/IEasyInspectorRowListener.h b/src/Authoring/Studio/Palettes/Inspector/IEasyInspectorRowListener.h
new file mode 100644
index 00000000..ced2099b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/IEasyInspectorRowListener.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#include "ToggleButton.h"
+
+//==============================================================================
+// Namespace
+//==============================================================================
+namespace Q3DStudio {
+
+//==============================================================================
+/**
+ * Interface for getting callbacks from the EasyInspectorRow
+ */
+class IEasyInspectorRowListener
+{
+public: // IEasyInspectorRowListener
+ virtual void OnAnimateToggle(CToggleButton::EButtonState inState) = 0;
+ virtual void OnLinkToggle() = 0;
+};
+
+} // namespace Q3DStudio
diff --git a/src/Authoring/Studio/Palettes/Inspector/IInspectableItem.h b/src/Authoring/Studio/Palettes/Inspector/IInspectableItem.h
new file mode 100644
index 00000000..341e46f0
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/IInspectableItem.h
@@ -0,0 +1,211 @@
+/****************************************************************************
+**
+** Copyright (C) 1999-2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef __IINSPECTABLEITEM_H__
+#define __IINSPECTABLEITEM_H__
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "UICDMDataTypes.h"
+#include "UICDMHandles.h"
+#include "UICDMActionInfo.h"
+#include "UICDMMetaData.h"
+#include "UICString.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CStudioApp;
+class IInspectableItem;
+
+//==============================================================================
+// Abstract Base Classes
+//==============================================================================
+
+enum EInspectableItemTypes {
+ INSPECTABLEITEMTYPE_VANILLA = 1,
+ INSPECTABLEITEMTYPE_PROPERTY,
+ INSPECTABLEITEMTYPE_DEPENDENT,
+ INSPECTABLEITEMTYPE_SLIDE,
+ INSPECTABLEITEMTYPE_OBJECTREFERENCE,
+ INSPECTABLEITEMTYPE_EVENTSOURCE,
+ INSPECTABLEITEMTYPE_ACTION,
+ INSPECTABLEITEMTYPE_CONDITIONS,
+};
+
+//==============================================================================
+/**
+ * @class IInspectableItemChangeListener
+ * @brief Listener class for inspectable item changes.
+ */
+class IInspectableItemChangeListener
+{
+public:
+ virtual void OnInspectablePropertyChanged(IInspectableItem *inProperty) = 0;
+};
+
+class IInspectableObject
+{
+public:
+ virtual UICDM::CUICDMInstanceHandle GetInspectableBaseInstance() = 0;
+ virtual void SetInspectableObject(const UICDM::SObjectRefType &) = 0;
+ virtual UICDM::SObjectRefType GetInspectableObject() = 0;
+};
+
+class IInspectableEvent
+{
+public:
+ virtual UICDM::CUICDMInstanceHandle GetInspectableInstance() = 0;
+ virtual UICDM::CUICDMEventHandle GetInspectableEvent() = 0;
+ virtual void SetInspectableEvent(const UICDM::CUICDMEventHandle &inEventHandle) = 0;
+};
+
+class IInspectableTargetSection : public IInspectableObject
+{
+public:
+ virtual UICDM::CUICDMActionHandle GetInspectableAction() const = 0;
+};
+
+class IInspectableEventSection : public IInspectableObject, public IInspectableEvent
+{
+public:
+ virtual UICDM::CUICDMActionHandle GetInspectableAction() const = 0;
+};
+
+class IInspectableHandlerSection
+{
+public:
+ virtual UICDM::CUICDMActionHandle GetInspectableAction() const = 0;
+ virtual UICDM::CUICDMHandlerHandle GetInspectableHandler() = 0;
+ virtual void SetInspectableHandler(const UICDM::CUICDMHandlerHandle &inHandlerHandle) = 0;
+
+ virtual UICDM::THandlerHandleList GetInspectableHandlerList() = 0;
+ virtual long GetArgumentCount() = 0;
+ virtual IInspectableItem *GetArgument(long inIndex) = 0;
+ virtual Q3DStudio::CString GetInspectableDescription() = 0;
+};
+
+//==============================================================================
+/**
+ * @class IInspectableItem
+ * @brief Abstract base class for inspectable items.
+ */
+class IInspectableItem
+{
+public:
+ virtual ~IInspectableItem() {}
+ virtual EInspectableItemTypes GetInspectableKind() { return INSPECTABLEITEMTYPE_VANILLA; }
+
+ virtual UICDM::HandlerArgumentType::Value
+ GetInspectableSubType() const = 0; // TODO : Make this method name correct
+ virtual Q3DStudio::CString GetInspectableName() const = 0;
+ virtual Q3DStudio::CString GetInspectableFormalName() const = 0;
+ virtual Q3DStudio::CString GetInspectableDescription() const = 0;
+
+ virtual UICDM::SValue GetInspectableData() const = 0;
+ virtual void SetInspectableData(const UICDM::SValue &) = 0;
+
+ // TODO: Remove from here onwards after cleaning up the rest of the UI classes
+ // This is the non-commital version of SetInspectableData, which must be called
+ // after ChangeInspectableData to commit the action.
+ virtual bool GetInspectableReadOnly() const { return false; }
+
+ virtual void ChangeInspectableData(const UICDM::SValue & /*inAttr*/){};
+ virtual void CancelInspectableData(){}
+
+ virtual void AddInspectableChangeListener(IInspectableItemChangeListener * /*inListener*/){};
+ virtual void RemoveInspectableChangeListener(IInspectableItemChangeListener * /*inListener*/){};
+};
+
+//==============================================================================
+/**
+ * Property specialization
+ */
+class IInspectablePropertyItem : public IInspectableItem
+{
+public:
+ EInspectableItemTypes GetInspectableKind() override { return INSPECTABLEITEMTYPE_PROPERTY; }
+ virtual void GetInspectablePropertyList(UICDM::TPropertyHandleList &outList) = 0;
+ virtual UICDM::CUICDMInstanceHandle GetInspectableInstance() = 0;
+};
+
+//==============================================================================
+/**
+ * Attribute specialization
+ */
+class IInspectableAttributeItem : public IInspectableItem
+{
+public:
+ EInspectableItemTypes GetInspectableKind() override { return INSPECTABLEITEMTYPE_DEPENDENT; }
+ virtual float GetInspectableMin() const = 0;
+ virtual float GetInspectableMax() const = 0;
+ virtual UICDM::TMetaDataStringList GetInspectableList() const = 0;
+ virtual UICDM::DataModelDataType::Value GetInspectableType() const = 0;
+ virtual UICDM::AdditionalMetaDataType::Value GetInspectableAdditionalType() const = 0;
+};
+
+//==============================================================================
+/**
+ * Slide specialization
+ */
+class IInspectableSlideItem : public IInspectableItem
+{
+public:
+ EInspectableItemTypes GetInspectableKind() override { return INSPECTABLEITEMTYPE_SLIDE; }
+ virtual void GetSlideNames(std::list<Q3DStudio::CString> &outSlideNames) = 0;
+};
+
+//==============================================================================
+/**
+ * ObjectReference specialiaztion
+ */
+class IInspectableObjectRefItem : public IInspectableObject, public IInspectableItem
+{
+public:
+ EInspectableItemTypes GetInspectableKind() override
+ {
+ return INSPECTABLEITEMTYPE_OBJECTREFERENCE;
+ }
+};
+
+//==============================================================================
+/**
+ * Event specialization
+ */
+class IInspectableEventItem : public IInspectableEvent, public IInspectableItem
+{
+public:
+ EInspectableItemTypes GetInspectableKind() override { return INSPECTABLEITEMTYPE_EVENTSOURCE; }
+};
+
+#endif // #ifndef __IINSPECTABLEITEM_H__
diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooser.qml b/src/Authoring/Studio/Palettes/Inspector/ImageChooser.qml
new file mode 100644
index 00000000..7621c5ef
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooser.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+Rectangle {
+ id: root
+
+ color: _backgroundColor
+ border.color: _studioColor3
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ spacing: 10
+ ListView {
+ id: listView
+
+ anchors {
+ fill: parent
+ leftMargin: 8
+ }
+
+ boundsBehavior: Flickable.StopAtBounds
+ spacing: 4
+ clip: true
+
+ ScrollBar.vertical: ScrollBar {}
+
+ model: _imageChooserModel
+
+ delegate: ChooserDelegate {
+ onClicked: _imageChooserView.imageSelected(_imageChooserView.handle, _imageChooserView.instance, filePath);
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.cpp b/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.cpp
new file mode 100644
index 00000000..98732f74
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ImageChooserModel.h"
+
+ImageChooserModel::ImageChooserModel(QObject *parent)
+ : ChooserModelBase(parent)
+{
+}
+
+ImageChooserModel::~ImageChooserModel()
+{
+}
+
+bool ImageChooserModel::isVisible(const QString &path) const
+{
+ return getIconType(path) == OBJTYPE_IMAGE;
+}
+
+const QVector<ChooserModelBase::FixedItem> ImageChooserModel::getFixedItems() const
+{
+ static const QVector<FixedItem> items = { { OBJTYPE_IMAGE, tr("[None]") } };
+ return items;
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.h b/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.h
new file mode 100644
index 00000000..288846fd
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef IMAGECHOOSERMODEL_H
+#define IMAGECHOOSERMODEL_H
+
+#include "ChooserModelBase.h"
+
+class ImageChooserModel : public ChooserModelBase
+{
+ Q_OBJECT
+
+public:
+ explicit ImageChooserModel(QObject *parent = nullptr);
+ virtual ~ImageChooserModel();
+
+private:
+ bool isVisible(const QString &path) const override;
+ const QVector<FixedItem> getFixedItems() const override;
+};
+
+#endif // IMAGECHOOSERMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.cpp b/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.cpp
new file mode 100644
index 00000000..a3a35217
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ImageChooserView.h"
+#include "ImageChooserModel.h"
+#include "StudioPreferences.h"
+#include "Literals.h"
+#include "StudioUtils.h"
+#include "IDocumentEditor.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMValue.h"
+#include "Core.h"
+#include "Doc.h"
+#include "StudioApp.h"
+#include "StudioPreferences.h"
+
+#include <QtCore/qtimer.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+
+ImageChooserView::ImageChooserView(QWidget *parent)
+ : QQuickWidget(parent)
+ , m_model(new ImageChooserModel(this))
+{
+ setWindowTitle(tr("Images"));
+ setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QTimer::singleShot(0, this, &ImageChooserView::initialize);
+}
+
+void ImageChooserView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty("_resDir"_L1,
+ resourceImageUrl());
+ rootContext()->setContextProperty("_imageChooserView"_L1, this);
+ rootContext()->setContextProperty("_imageChooserModel"_L1, m_model);
+ engine()->addImportPath(qmlImportPath());
+ setSource(QUrl("qrc:/Studio/Palettes/Inspector/ImageChooser.qml"_L1));
+}
+
+QSize ImageChooserView::sizeHint() const
+{
+ return {500, 500};
+}
+
+void ImageChooserView::setHandle(int handle)
+{
+ m_handle = handle;
+}
+
+int ImageChooserView::handle() const
+{
+ return m_handle;
+}
+
+void ImageChooserView::setInstance(int instance)
+{
+ m_instance = instance;
+}
+
+int ImageChooserView::instance() const
+{
+ return m_instance;
+}
+
+void ImageChooserView::focusOutEvent(QFocusEvent *event)
+{
+ QQuickWidget::focusOutEvent(event);
+ QTimer::singleShot(0, this, &ImageChooserView::close);
+}
+
+void ImageChooserView::showEvent(QShowEvent *event)
+{
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+
+ UICDM::SValue value;
+ propertySystem->GetInstancePropertyValue(m_instance, m_handle, value);
+
+ const auto guid = UICDM::get<UICDM::SLong4>(value);
+
+ const auto imageInstance = doc->GetDocumentReader().GetInstanceForGuid(guid);
+ if (imageInstance.Valid()) {
+ const QString path = doc->GetDocumentReader().GetSourcePath(imageInstance).toQString();
+ m_model->setCurrentFile(path);
+ } else {
+ m_model->setCurrentFile(tr("[None]"));
+ }
+
+ QQuickWidget::showEvent(event);
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.h b/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.h
new file mode 100644
index 00000000..f1738aa9
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ImageChooserView.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef IMAGECHOOSERVIEW_H
+#define IMAGECHOOSERVIEW_H
+
+#include <QQuickWidget>
+
+class ImageChooserModel;
+
+class ImageChooserView : public QQuickWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(int instance READ instance)
+ Q_PROPERTY(int handle READ handle)
+
+public:
+ explicit ImageChooserView(QWidget *parent = nullptr);
+
+ QSize sizeHint() const override;
+
+ void setHandle(int handle);
+ int handle() const;
+
+ void setInstance(int instance);
+ int instance() const;
+
+Q_SIGNALS:
+ void imageSelected(int handle, int instance, const QString &name);
+
+protected:
+ void focusOutEvent(QFocusEvent *event) override;
+
+private:
+ void showEvent(QShowEvent *event) override;
+ void initialize();
+ int m_handle = -1;
+ int m_instance = -1;
+ ImageChooserModel *m_model = nullptr;
+};
+
+#endif // IMAGECHOOSERVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectableBase.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectableBase.cpp
new file mode 100644
index 00000000..1c33eb23
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectableBase.cpp
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 1999-2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "InspectableBase.h"
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectableBase.h b/src/Authoring/Studio/Palettes/Inspector/InspectableBase.h
new file mode 100644
index 00000000..34973393
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectableBase.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 1999-2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#ifndef __INSPECTABLEBASE_H__
+#define __INSPECTABLEBASE_H__
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CInspectorGroup;
+
+#include "Core.h"
+#include "StudioObjectTypes.h"
+
+//==============================================================================
+/**
+ * Parent class of Inspectable types that will appear in the Inspector Palette.
+ */
+class CInspectableBase
+{
+protected:
+ CCore *m_Core; ///<
+
+public:
+ CInspectableBase(CCore *inCore)
+ : m_Core(inCore)
+ {
+ }
+ virtual ~CInspectableBase() {}
+
+ // Interface
+ virtual EStudioObjectType GetObjectType() = 0;
+ // virtual std::wstring GetTypeString() const { return L""; }
+ virtual Q3DStudio::CString GetName() = 0;
+ virtual long GetGroupCount() = 0;
+ virtual CInspectorGroup *GetGroup(long inIndex) = 0;
+ virtual bool IsValid() const = 0;
+ virtual bool IsMaster() = 0;
+};
+
+#endif // #ifndef __INSPECTABLEBASE_H__
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp
new file mode 100644
index 00000000..474fc3e4
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp
@@ -0,0 +1,862 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <QFileInfo>
+
+#include <functional>
+
+#include "InspectorControlModel.h"
+#include "Core.h"
+#include "Doc.h"
+#include "ControlGraphIterators.h"
+#include "InspectorGroup.h"
+#include "UICDMInspectorGroup.h"
+#include "UICDMInspectorRow.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMInspectable.h"
+#include "UICDMDataCore.h"
+#include "StudioApp.h"
+#include "IDocumentEditor.h"
+#include "Control.h"
+#include "ControlData.h"
+#include "UICDMMetaData.h"
+#include "UICDMSignals.h"
+#include "CmdDataModelDeanimate.h"
+#include "GuideInspectable.h"
+#include "UICDMDataTypes.h"
+#include "IObjectReferenceHelper.h"
+#include "UICDMXML.h"
+#include "UICDMStringTable.h"
+#include "UICFileTools.h"
+#include "UICDMSlideCore.h"
+#include "SlideSystem.h"
+#include "UICDMMaterialInspectable.h"
+#include "ClientDataModelBridge.h"
+#include "IDocumentReader.h"
+#include "IStudioRenderer.h"
+
+static QStringList renderableItems()
+{
+ QStringList renderables;
+ renderables.push_back(QObject::tr("No renderable item"));
+ const CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ Q3DStudio::CString docDir = doc->GetDocumentDirectory();
+ Q3DStudio::CFilePath fullDocPath = doc->GetDocumentPath().GetAbsolutePath();
+ Q3DStudio::CString docFilename = fullDocPath.GetFileName();
+ // First step, find uia file, parse and pull out renderable asset id's but ignoring the
+ // current presentation.
+ std::vector<Q3DStudio::CFilePath> dirFiles;
+ Q3DStudio::CFilePath thePath(docDir);
+ thePath.ListFilesAndDirectories(dirFiles);
+ for (size_t idx = 0, end = dirFiles.size(); idx < end; ++idx) {
+ if (!dirFiles[idx].IsFile())
+ continue;
+
+ Q3DStudio::CString ext = dirFiles[idx].GetExtension();
+ if (!ext.CompareNoCase("uia"))
+ continue;
+
+ UICDM::TStringTablePtr theStringTable
+ = UICDM::IStringTable::CreateStringTable();
+ std::shared_ptr<UICDM::IDOMFactory> theDomFact =
+ UICDM::IDOMFactory::CreateDOMFactory(theStringTable);
+ Q3DStudio::CString fullFile = dirFiles[idx];
+ qt3ds::foundation::CFileSeekableIOStream theStream(
+ fullFile, qt3ds::foundation::FileReadFlags());
+
+ UICDM::SDOMElement *theElem
+ = UICDM::CDOMSerializer::Read(*theDomFact, theStream);
+ if (theElem) {
+ std::shared_ptr<UICDM::IDOMReader> theReader =
+ UICDM::IDOMReader::CreateDOMReader(*theElem, theStringTable,
+ theDomFact);
+ if (theReader->MoveToFirstChild("assets")) {
+ for (bool success = theReader->MoveToFirstChild(); success;
+ success = theReader->MoveToNextSibling()) {
+ if (UICDM::AreEqual(theReader->GetElementName(), L"presentation") ||
+ UICDM::AreEqual(theReader->GetElementName(), L"presentation-qml")) {
+ UICDM::TXMLStr src = nullptr;
+ UICDM::TXMLStr id = nullptr;
+ theReader->Att("src", src);
+ theReader->Att("id", id);
+ if (docFilename != src.c_str())
+ renderables.push_back(QString::fromLatin1(id.c_str()));
+ } else if (UICDM::AreEqual(theReader->GetElementName(),
+ L"renderplugin")) {
+ const wchar_t *id = nullptr;
+ theReader->UnregisteredAtt(L"id", id);
+ renderables.push_back(QString::fromWCharArray(id));
+ }
+ }
+ }
+ }
+ }
+ // second step, find the renderable plugins.
+ {
+ Q3DStudio::CFilePath pluginDir
+ = Q3DStudio::CFilePath::CombineBaseAndRelative(docDir, "plugins");
+ if (pluginDir.Exists() && pluginDir.IsDirectory()) {
+ std::vector<Q3DStudio::CFilePath> dirFiles;
+ pluginDir.ListFilesAndDirectories(dirFiles);
+ for (size_t idx = 0, end = dirFiles.size(); idx < end; ++idx) {
+ if (dirFiles[idx].IsFile()) {
+ Q3DStudio::CFilePath relPath =
+ Q3DStudio::CFilePath::GetRelativePathFromBase(docDir, dirFiles[idx]);
+ renderables.push_back(relPath.toQString());
+ }
+ }
+ }
+ }
+ std::sort(renderables.begin() + 1, renderables.end());
+ return renderables;
+}
+
+static std::pair<bool, bool> getSlideCharacteristics(UICDM::CUICDMInstanceHandle instance,
+ const UICDM::ISlideCore &slideCore,
+ const UICDM::ISlideSystem &slideSystem)
+{
+ // Get the slide from the instance.
+ UICDM::CUICDMSlideHandle slide = slideCore.GetSlideByInstance(instance);
+ UICDM::CUICDMSlideHandle master = slideSystem.GetMasterSlide(slide);
+ int index = (int)slideSystem.GetSlideIndex(slide);
+ int count = (int)slideSystem.GetSlideCount(master);
+ bool hasNextSlide = index > 0 && index < count - 1;
+ bool hasPreviousSlide = index > 1;
+ return std::make_pair(hasNextSlide, hasPreviousSlide);
+}
+
+InspectorControlModel::InspectorControlModel(QObject *parent)
+ : QAbstractListModel(parent)
+ , m_UpdatableEditor(*g_StudioApp.GetCore()->GetDoc())
+{
+}
+
+void InspectorControlModel::setInspectable(CInspectableBase *inInspectable)
+{
+ const auto signalProvider
+ = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetFullSystemSignalProvider();
+
+ if (m_notifier.get() == nullptr) {
+ m_notifier = signalProvider->ConnectInstancePropertyValue(
+ std::bind(&InspectorControlModel::notifyInstancePropertyValue,
+ this, std::placeholders::_1, std::placeholders::_2));
+ }
+ if (m_slideNotifier.get() == nullptr) {
+ m_slideNotifier = signalProvider->ConnectSlideRearranged(
+ std::bind(&InspectorControlModel::onSlideRearranged, this,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+ }
+
+ if (m_inspectableBase != inInspectable) {
+ m_inspectableBase = inInspectable;
+ rebuildTree();
+ }
+}
+
+void InspectorControlModel::notifyInstancePropertyValue(UICDM::CUICDMInstanceHandle inHandle,
+ UICDM::CUICDMPropertyHandle inProperty)
+{
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ bool changed = false;
+ for (int row = 0; row < m_groupElements.count(); ++row) {
+ auto group = m_groupElements[row];
+ for (int p = 0; p < group.controlElements.count(); ++p) {
+ QVariant& element = group.controlElements[p];
+ InspectorControlBase *property = element.value<InspectorControlBase *>();
+ UICDM::CUICDMInstanceHandle imageInstance;
+ if (property->m_dataType == UICDM::DataModelDataType::Long4
+ && property->m_property.Valid()) {
+ imageInstance = doc->GetDocumentReader().GetImageInstanceForProperty(
+ property->m_instance, property->m_property);
+ }
+ if (property->m_property == inProperty || imageInstance == inHandle) {
+ updatePropertyValue(property);
+ changed = true;
+ }
+ }
+ }
+ if (changed)
+ Q_EMIT dataChanged(index(0), index(rowCount() - 1));
+}
+
+QVariant InspectorControlModel::getPropertyValue(long instance, int handle)
+{
+ for (int row = 0; row < m_groupElements.count(); ++row) {
+ auto group = m_groupElements[row];
+ for (int p = 0; p < group.controlElements.count(); ++p) {
+ QVariant& element = group.controlElements[p];
+ InspectorControlBase *property = element.value<InspectorControlBase *>();
+ if (property->m_property == UICDM::CDataModelHandle(handle))
+ return property->m_value;
+ }
+ }
+ return {};
+}
+
+void InspectorControlModel::setMaterials(std::vector<Q3DStudio::CFilePath> &materials)
+{
+ m_materials.clear();
+ const Q3DStudio::CString base = g_StudioApp.GetCore()->GetDoc()->GetDocumentDirectory();
+
+ for (Q3DStudio::CFilePath path : materials) {
+
+ const QString relativePath = path.toQString();
+ const Q3DStudio::CFilePath absolutePath
+ = Q3DStudio::CFilePath::CombineBaseAndRelative(base, path);
+
+ const QString name = g_StudioApp.GetCore()->GetDoc()->GetDocumentReader()
+ .GetCustomMaterialName(absolutePath).toQString();
+
+ m_materials.push_back({name, relativePath});
+ }
+}
+
+InspectorControlBase* InspectorControlModel::createMaterialItem(CUICDMInspectable *inspectable,
+ int groupIndex)
+{
+ const auto studio = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem();
+ InspectorControlBase *item = new InspectorControlBase;
+ item->m_instance = inspectable->GetGroupInstance(groupIndex);
+
+ item->m_title = tr("Material Type");
+
+ CClientDataModelBridge *theBridge = studio->GetClientDataModelBridge();
+ EStudioObjectType theType = theBridge->GetObjectType(item->m_instance);
+ item->m_dataType = UICDM::DataModelDataType::StringRef;
+ item->m_propertyType = UICDM::AdditionalMetaDataType::None;
+ item->m_tooltip = tr("Type of material being used or custom material");
+
+ item->m_animatable = false;
+
+ QStringList values;
+ values.push_back(tr("Standard Material"));
+ values.push_back(tr("Referenced Material"));
+
+ const QString sourcePath = theBridge->GetSourcePath(item->m_instance).toQString();
+
+ switch (theType) {
+
+ case OBJTYPE_MATERIAL:
+ item->m_value = tr("Standard Material");
+ break;
+
+ case OBJTYPE_REFERENCEDMATERIAL:
+ item->m_value = tr("Referenced Material");
+ break;
+ }
+
+ for (size_t matIdx = 0, end = m_materials.size(); matIdx < end; ++matIdx) {
+ values.push_back(m_materials[matIdx].m_name);
+ if (m_materials[matIdx].m_relativePath == sourcePath)
+ item->m_value = values.last();
+ }
+
+ item->m_values = values;
+
+ return item;
+}
+
+InspectorControlBase* InspectorControlModel::createItem(CUICDMInspectable *inspectable,
+ Q3DStudio::CUICDMInspectorRow *row,
+ int groupIndex)
+{
+ return createItem(inspectable, row->GetMetaDataPropertyInfo(), groupIndex);
+}
+
+InspectorControlBase* InspectorControlModel::createItem(CUICDMInspectable *inspectable,
+ const UICDM::SMetaDataPropertyInfo &metaProperty,
+ int groupIndex)
+{
+ const auto studio = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem();
+ if (metaProperty.m_IsHidden)
+ return nullptr;
+
+ InspectorControlBase *item = new InspectorControlBase;
+ item->m_property = metaProperty.m_Property;
+ item->m_instance = inspectable->GetGroupInstance(groupIndex);
+
+ Q3DStudio::CString title;
+ title.Assign(metaProperty.m_FormalName.c_str());
+ if (title.IsEmpty())
+ title.Assign(metaProperty.m_Name.c_str());
+ item->m_title = title.toQString();
+
+ const auto propertySystem = studio->GetPropertySystem();
+ item->m_dataType = propertySystem->GetDataType(metaProperty.m_Property);
+ item->m_propertyType = static_cast<UICDM::AdditionalMetaDataType::Value>
+ (propertySystem->GetAdditionalMetaDataType(item->m_instance, metaProperty.m_Property));
+ item->m_tooltip = Q3DStudio::CString(metaProperty.m_Description.c_str()).toQString();
+
+ item->m_animatable = metaProperty.m_Animatable &&
+ studio->GetAnimationSystem()->IsPropertyAnimatable(item->m_instance,
+ metaProperty.m_Property);
+ if (item->m_animatable) {
+ item->m_animated = studio->GetAnimationSystem()->IsPropertyAnimated(item->m_instance,
+ metaProperty.m_Property);
+
+ // Update the Animate Toggle on undo/redo
+ auto signalProvider = studio->GetFullSystemSignalProvider();
+ item->m_connections.push_back(signalProvider->ConnectAnimationCreated(
+ std::bind(&InspectorControlModel::updateAnimateToggleState,
+ this, item)));
+
+ item->m_connections.push_back(signalProvider->ConnectAnimationDeleted(
+ std::bind(&InspectorControlModel::updateAnimateToggleState,
+ this, item)));
+ }
+
+ // synchronize the value itself
+ updatePropertyValue(item);
+ return item;
+}
+
+UICDM::SValue InspectorControlModel::currentPropertyValue(long instance, int handle)
+{
+ UICDM::SValue value;
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ auto studioSystem = doc->GetStudioSystem();
+ const auto propertySystem = studioSystem->GetPropertySystem();
+ propertySystem->GetInstancePropertyValue(instance, handle, value);
+
+ return value;
+}
+
+void InspectorControlModel::updateAnimateToggleState(InspectorControlBase* inItem)
+{
+ const auto studio = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem();
+ bool animated = studio->GetAnimationSystem()->IsPropertyAnimated(inItem->m_instance,
+ inItem->m_property);
+ if (animated != inItem->m_animated) {
+ inItem->m_animated = animated;
+ Q_EMIT inItem->animatedChanged();
+ }
+}
+
+bool InspectorControlModel::isTreeRebuildRequired(CInspectableBase* inspectBase) const
+{
+ if (inspectBase != m_inspectableBase)
+ return true;
+
+ long theCount = m_inspectableBase->GetGroupCount();
+ if (m_groupElements.size() != theCount)
+ return true;
+
+ for (long theIndex = 0; theIndex < theCount; ++theIndex) {
+ const CInspectorGroup *theInspectorGroup = m_inspectableBase->GetGroup(theIndex);
+ if (m_groupElements.at(theIndex).groupTitle != theInspectorGroup->GetName())
+ return true;
+ }
+
+ return false;
+}
+
+bool InspectorControlModel::isGroupRebuildRequired(CInspectableBase* inspectable, int theIndex) const
+{
+ Q_ASSERT(theIndex < m_groupElements.size());
+ const CInspectorGroup *theInspectorGroup = inspectable->GetGroup(theIndex);
+ const auto existingGroup = m_groupElements.at(theIndex);
+ if (existingGroup.groupTitle != theInspectorGroup->GetName())
+ return true;
+
+ if (const auto cdmInspectable = dynamic_cast<CUICDMInspectable *>(inspectable)) {
+ int existingIndex = 0;
+ if (const auto group = dynamic_cast<const CUICDMInspectorGroup *>(theInspectorGroup)) {
+ const auto materialGroup
+ = dynamic_cast<const UICDMMaterialInspectorGroup *>(group);
+ if (materialGroup && materialGroup->isMaterialGroup()) {
+ auto i = existingGroup.controlElements.at(existingIndex++).value<InspectorControlBase*>();
+ if (i->m_instance != cdmInspectable->GetGroupInstance(theIndex))
+ return true;
+ }
+
+ if ((existingGroup.controlElements.size() - existingIndex) != group->GetRows().size())
+ return true;
+
+ for (const auto row : group->GetRows()) {
+ auto i = existingGroup.controlElements.at(existingIndex++).value<InspectorControlBase*>();
+ if (i->m_instance != cdmInspectable->GetGroupInstance(theIndex))
+ return true;
+
+ if (i->m_property != row->GetMetaDataPropertyInfo().m_Property)
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+auto InspectorControlModel::computeTree(CInspectableBase* inspectBase)
+ -> QVector<GroupInspectorControl>
+{
+ QVector<GroupInspectorControl> result;
+
+ if (inspectBase) {
+ long theCount = inspectBase->GetGroupCount();
+ for (long theIndex = 0; theIndex < theCount; ++theIndex) {
+ result.append(computeGroup(inspectBase, theIndex));
+ }
+ }
+
+ return result;
+}
+
+auto InspectorControlModel::computeGroup(CInspectableBase* inspectable,
+ int theIndex)
+ -> GroupInspectorControl
+{
+ CInspectorGroup* theInspectorGroup = inspectable->GetGroup(theIndex);
+ GroupInspectorControl result;
+ result.groupTitle = theInspectorGroup->GetName();
+
+ if (const auto cdmInspectable = dynamic_cast<CUICDMInspectable *>(inspectable)) {
+ if (const auto group = dynamic_cast<CUICDMInspectorGroup *>(theInspectorGroup)) {
+ const auto materialGroup
+ = dynamic_cast<UICDMMaterialInspectorGroup *>(group);
+ if (materialGroup && materialGroup->isMaterialGroup()) {
+ InspectorControlBase *item = createMaterialItem(cdmInspectable, theIndex);
+ if (item) {
+ result.controlElements.push_back(QVariant::fromValue(item));
+ }
+ }
+ for (const auto row : group->GetRows()) {
+ InspectorControlBase *item = createItem(cdmInspectable, row, theIndex);
+ if (!item)
+ continue;
+
+ result.controlElements.push_back(QVariant::fromValue(item));
+ }
+ }
+ } else if (dynamic_cast<SGuideInspectableImpl *>(inspectable)) {
+ //KDAB_FIXME: load row element (How ?)
+ }
+
+ return result;
+}
+
+void InspectorControlModel::rebuildTree()
+{
+ beginResetModel();
+ m_groupElements = computeTree(m_inspectableBase);
+ endResetModel();
+}
+
+int InspectorControlModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return m_groupElements.count();
+}
+
+void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) const
+{
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ auto studioSystem = doc->GetStudioSystem();
+ const auto propertySystem = studioSystem->GetPropertySystem();
+ UICDM::SValue value;
+ const auto instance = element->m_instance;
+ propertySystem->GetInstancePropertyValue(instance, element->m_property, value);
+
+ const auto metaDataProvider = doc->GetStudioSystem()->GetActionMetaData();
+ const auto info = metaDataProvider->GetMetaDataPropertyInfo(
+ metaDataProvider->GetMetaDataProperty(instance, element->m_property));
+ switch (element->m_dataType) {
+ case UICDM::DataModelDataType::String:
+ element->m_value = UICDM::get<QString>(value);
+ //intentional fall-through
+ case UICDM::DataModelDataType::StringOrInt:
+ if (element->m_propertyType == UICDM::AdditionalMetaDataType::StringList) {
+ QStringList stringlist = UICDM::get<QStringList>(info->m_MetaDataData);
+ auto slideSystem = studioSystem->GetSlideSystem();
+
+ if (element->m_title == QStringLiteral("Play Mode")) {
+ std::pair<bool, bool> slideData(
+ getSlideCharacteristics(element->m_instance, *studioSystem->GetSlideCore(),
+ *slideSystem));
+ bool hasNextSlide(slideData.first);
+ bool hasPreviousSlide(slideData.second);
+ if (!hasNextSlide && !hasPreviousSlide)
+ stringlist.removeAll("Play Through To...");
+ } else if (element->m_title == QStringLiteral("Play Through To")) {
+ // the code duplication is intentional as we may ask for slide characteristics
+ // only if the property refers to slides
+ std::pair<bool, bool> slideData(
+ getSlideCharacteristics(element->m_instance, *studioSystem->GetSlideCore(),
+ *slideSystem));
+ bool hasNextSlide(slideData.first);
+ bool hasPreviousSlide(slideData.second);
+ if (!hasNextSlide)
+ stringlist.removeAll("Next");
+ if (!hasPreviousSlide)
+ stringlist.removeAll("Previous");
+
+ auto itemCount = stringlist.count();
+ QString listOpt;
+ int selectedSlideHandle = 0;
+ int selectedIndex = -1;
+ UICDM::SStringOrInt stringOrInt = UICDM::get<UICDM::SStringOrInt>(value);
+ if (stringOrInt.GetType() == UICDM::SStringOrIntTypes::String)
+ listOpt = QString::fromWCharArray(UICDM::get<UICDM::TDataStrPtr>
+ (stringOrInt.m_Value)->GetData());
+ else
+ selectedSlideHandle = UICDM::get<long>(stringOrInt.m_Value);
+
+ selectedIndex = stringlist.indexOf(listOpt);
+ // Add the slide names (exclude the master slide)
+ auto bridge = studioSystem->GetClientDataModelBridge();
+ auto slideHandle = slideSystem->GetSlideByInstance(instance);
+ auto masterSlide = slideSystem->GetMasterSlide(slideHandle);
+ long slideCount = (long)slideSystem->GetSlideCount(masterSlide);
+ for (long slideIndex = 1; slideIndex < slideCount; ++slideIndex) {
+ auto currentSlide = slideSystem->GetSlideByIndex(masterSlide, slideIndex);
+ auto currentInstance = slideSystem->GetSlideInstance(currentSlide);
+
+ QString slideName = bridge->GetName(currentInstance).toQString();
+ //hack to add a separator before the item
+ if (slideIndex == 1 && itemCount > 0)
+ slideName += "|separator";
+ stringlist.append(slideName);
+
+ if (currentSlide.GetHandleValue() == selectedSlideHandle)
+ selectedIndex = slideIndex + itemCount - 1;
+ }
+
+ element->m_value = QString(selectedIndex > 0 ? stringlist[selectedIndex]
+ : stringlist.first()).replace("|separator", "");
+ }
+ element->m_values = stringlist;
+ } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Import) {
+ QStringList stringlist = UICDM::get<QStringList>(info->m_MetaDataData);
+ element->m_values = stringlist;
+ } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Renderable) {
+ element->m_values = renderableItems();
+ if (element->m_value.toString().isEmpty())
+ element->m_value = element->m_values.toStringList().at(0);
+ } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::MultiLine) {
+ element->m_value = UICDM::get<QString>(value);
+ } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Font) {
+ std::vector<Q3DStudio::CString> fontNames;
+ g_StudioApp.GetCore()->GetDoc()->GetProjectFonts(fontNames);
+ QStringList possibleValues;
+ for (const auto &fontName: fontNames)
+ possibleValues.append(fontName.toQString());
+ element->m_values = possibleValues;
+ element->m_value = UICDM::get<QString>(value);
+ } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Mesh) {
+ QString meshValue = UICDM::get<QString>(value);
+ Q3DStudio::CFilePath theSelectionItem(Q3DStudio::CString::fromQString(meshValue));
+ Q3DStudio::CFilePath theSelectionWithoutId(theSelectionItem.GetPathWithoutIdentifier());
+ if (theSelectionWithoutId.size())
+ element->m_value = theSelectionWithoutId.GetFileName().toQString();
+ else
+ element->m_value = theSelectionItem.GetIdentifier().toQString();
+ } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Texture) {
+ QFileInfo fileInfo(UICDM::get<QString>(value));
+ element->m_value = fileInfo.fileName();
+ } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::PathBuffer) {
+ element->m_value = UICDM::get<QString>(value);
+ } else {
+ qWarning() << "KDAB_TODO: InspectorControlModel::updatePropertyValue: need to implement:"
+ << element->m_dataType << " element->m_propertyType : "
+ << element->m_propertyType;
+ }
+ break;
+ case UICDM::DataModelDataType::StringRef:
+ if (element->m_propertyType == UICDM::AdditionalMetaDataType::None) {
+ element->m_value = UICDM::get<QString>(value);
+ }
+ break;
+ case UICDM::DataModelDataType::Bool:
+ element->m_value = UICDM::get<bool>(value);
+ break;
+ case UICDM::DataModelDataType::Long4:
+ if (element->m_propertyType == UICDM::AdditionalMetaDataType::Image) {
+ UICDM::Option<UICDM::SLong4> guid = UICDM::get<UICDM::SLong4>(value);
+ UICDM::CUICDMInstanceHandle imageInstance = doc->GetDocumentReader()
+ .GetInstanceForGuid(guid);
+ if (imageInstance.Valid()) {
+ Q3DStudio::CString path = doc->GetDocumentReader().GetSourcePath(imageInstance);
+ Q3DStudio::CFilePath relPath(path);
+ element->m_value = QVariant(relPath.GetFileName().toQString());
+ } else {
+ element->m_value = QVariant(QString(""));
+ }
+ } else {
+ qWarning() << "KDAB_TODO: InspectorControlModel::updatePropertyValue: need to implement:"
+ << element->m_dataType << " " << element->m_title;
+ }
+ break;
+ case UICDM::DataModelDataType::Long:
+ if (element->m_propertyType == UICDM::AdditionalMetaDataType::Range) {
+ element->m_value = UICDM::get<int>(value);
+ const UICDM::SMetaDataRange ranges = UICDM::get<UICDM::SMetaDataRange>(info->m_MetaDataData);
+ const QList<double> rangesValues{ranges.m_Min, ranges.m_Max};
+ element->m_values = QVariant::fromValue<QList<double> >(rangesValues);
+ }
+ else if (element->m_propertyType == UICDM::AdditionalMetaDataType::ShadowMapResolution) {
+ element->m_value = UICDM::get<int>(value);
+ } else {
+ qWarning() << "KDAB_TODO: InspectorControlModel::updatePropertyValue: need to implement:"
+ << element->m_dataType;
+ }
+ break;
+ case UICDM::DataModelDataType::Float3:
+ if (element->m_propertyType == UICDM::AdditionalMetaDataType::Color) {
+ element->m_value = UICDM::get<QColor>(value);
+ } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Rotation) {
+ const QVector3D theFloat3 = UICDM::get<QVector3D>(value);
+ const QList<double> float3Values{theFloat3.x(), theFloat3.y(), theFloat3.z()};
+ element->m_values = QVariant::fromValue<QList<double> >(float3Values);
+ } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::None) {
+ const QVector3D theFloat3 = UICDM::get<QVector3D>(value);
+ const QList<double> float3Values{theFloat3.x(), theFloat3.y(), theFloat3.z()};
+ element->m_values = QVariant::fromValue<QList<double> >(float3Values);
+ }
+ break;
+ case UICDM::DataModelDataType::Float:
+ if (element->m_propertyType == UICDM::AdditionalMetaDataType::None) {
+ element->m_value = UICDM::get<float>(value);
+ } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Range) {
+ element->m_value = UICDM::get<float>(value);
+ const UICDM::SMetaDataRange ranges = UICDM::get<UICDM::SMetaDataRange>(info->m_MetaDataData);
+ const QList<double> rangesValues{ranges.m_Min, ranges.m_Max};
+ element->m_values = QVariant::fromValue<QList<double> >(rangesValues);
+ } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::FontSize) {
+ element->m_value = UICDM::get<float>(value);
+ }
+ break;
+ case UICDM::DataModelDataType::ObjectRef:
+ if (element->m_propertyType == UICDM::AdditionalMetaDataType::ObjectRef) {
+ IObjectReferenceHelper *objRefHelper = doc->GetDataModelObjectReferenceHelper();
+ if (objRefHelper) {
+ UICDM::CUICDMInstanceHandle refInstance = objRefHelper->Resolve(value, instance);
+ element->m_value = objRefHelper->LookupObjectFormalName(refInstance).toQString();
+ }
+ }
+ break;
+ default:
+ qWarning() << "TODO: InspectorControlModel::updatePropertyValue: I've no idea how to handle this datatype"
+ << element->m_dataType;
+ break;
+ }
+ Q_EMIT element->valueChanged();
+ Q_EMIT element->valuesChanged();
+}
+
+void InspectorControlModel::refreshRenderables()
+{
+ for (int row = 0; row < m_groupElements.count(); ++row) {
+ auto group = m_groupElements[row];
+ for (int p = 0; p < group.controlElements.count(); ++p) {
+ QVariant& element = group.controlElements[p];
+ InspectorControlBase *property = element.value<InspectorControlBase *>();
+ if (property->m_propertyType == UICDM::AdditionalMetaDataType::Renderable)
+ updatePropertyValue(property);
+ }
+ }
+}
+
+void InspectorControlModel::refresh()
+{
+ for (int row = 0; row < m_groupElements.count(); ++row) {
+ auto group = m_groupElements[row];
+ for (int p = 0; p < group.controlElements.count(); ++p) {
+ QVariant& element = group.controlElements[p];
+ InspectorControlBase *property = element.value<InspectorControlBase *>();
+ if (property->m_property.Valid())
+ updatePropertyValue(property);
+ }
+ }
+ Q_EMIT dataChanged(index(0), index(rowCount() - 1));
+}
+
+void InspectorControlModel::setMaterialTypeValue(long instance, int handle, const QVariant &value)
+{
+ Q_UNUSED(handle);
+ const QString typeValue = value.toString();
+ Q3DStudio::CString v;
+
+ if (typeValue == tr("Standard Material")) {
+ v = Q3DStudio::CString("Standard Material");
+ } else if (typeValue == tr("Referenced Material")) {
+ v = Q3DStudio::CString("Referenced Material");
+ } else {
+ for (size_t matIdx = 0, end = m_materials.size(); matIdx < end; ++matIdx) {
+ if (m_materials[matIdx].m_name == typeValue) {
+ v = Q3DStudio::CString::fromQString(m_materials[matIdx].m_relativePath);
+ break;
+ }
+ }
+ }
+
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*g_StudioApp.GetCore()->GetDoc(),
+ QObject::tr("Set Property"))->SetMaterialType(instance, v);
+}
+
+void InspectorControlModel::setRenderableValue(long instance, int handle, const QVariant &value)
+{
+ UICDM::SValue oldValue = currentPropertyValue(instance, handle);
+
+ QString v = value.toString();
+ if (v == QObject::tr("No renderable item"))
+ v = QString();
+
+ if (v == UICDM::get<QString>(oldValue))
+ return;
+
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*g_StudioApp.GetCore()->GetDoc(), QObject::tr("Set Property"))
+ ->SetInstancePropertyValueAsRenderable(instance, handle,
+ Q3DStudio::CString::fromQString(v));
+}
+
+void InspectorControlModel::setPropertyValue(long instance, int handle, const QVariant &value, bool commit)
+{
+ UICDM::SValue oldValue = currentPropertyValue(instance, handle);
+ UICDM::SValue v = value;
+
+ if (v == oldValue)
+ return;
+
+ // some properties may initialize OpenGL resources (e.g. loading meshes will
+ // initialize vertex buffers), so the renderer's OpenGL context must be current
+ Q3DStudio::IStudioRenderer &theRenderer(g_StudioApp.GetRenderer());
+ theRenderer.MakeContextCurrent();
+
+ m_UpdatableEditor.EnsureEditor(L"Set Property", __FILE__, __LINE__)
+ .SetInstancePropertyValue(instance, handle, v);
+
+ theRenderer.ReleaseContext();
+
+ m_UpdatableEditor.FireImmediateRefresh(instance);
+
+ if (commit) {
+ m_UpdatableEditor.CommitEditor();
+
+ if (isTreeRebuildRequired(m_inspectableBase)) {
+ rebuildTree();
+ } else {
+ // group strucutre is intact, let's walk to see which rows changed
+ long theCount = m_inspectableBase->GetGroupCount();
+ for (long theIndex = 0; theIndex < theCount; ++theIndex) {
+ if (isGroupRebuildRequired(m_inspectableBase, theIndex)) {
+ m_groupElements[theIndex] = computeGroup(m_inspectableBase, theIndex);
+ Q_EMIT dataChanged(index(theIndex), index(theIndex));
+ }
+ }
+ }
+
+ } // of commit
+}
+
+void InspectorControlModel::setSlideSelection(long instance, int handle, int index,
+ const QStringList &list)
+{
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ auto studioSystem = doc->GetStudioSystem();
+ const auto metaDataProvider = doc->GetStudioSystem()->GetActionMetaData();
+ const auto info = metaDataProvider->GetMetaDataPropertyInfo(
+ metaDataProvider->GetMetaDataProperty(instance, handle));
+ QStringList stringlist = UICDM::get<QStringList>(info->m_MetaDataData);
+
+ auto slideSystem = studioSystem->GetSlideSystem();
+ std::pair<bool, bool> slideData(
+ getSlideCharacteristics(instance, *studioSystem->GetSlideCore(),
+ *slideSystem));
+ bool hasNextSlide(slideData.first);
+ bool hasPreviousSlide(slideData.second);
+ UICDM::SStringOrInt newSelectedData;
+ if (!hasNextSlide)
+ stringlist.removeAll("Next");
+ if (!hasPreviousSlide)
+ stringlist.removeAll("Previous");
+
+ auto itemCount = stringlist.count();
+ if (index < itemCount) {
+ newSelectedData = UICDM::SStringOrInt(std::make_shared<UICDM::CDataStr>
+ (Q3DStudio::CString::fromQString(list[index]).c_str()));
+ } else {
+ auto slideHandle = slideSystem->GetSlideByInstance(instance);
+ auto masterSlide = slideSystem->GetMasterSlide(slideHandle);
+ long slideIndex = index - itemCount + 1;
+ auto newSelectedSlide = slideSystem->GetSlideByIndex(masterSlide, slideIndex);
+ newSelectedData = UICDM::SStringOrInt((long)newSelectedSlide);
+ }
+
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*g_StudioApp.GetCore()->GetDoc(), QObject::tr("Set Property"))
+ ->SetInstancePropertyValue(instance, handle, newSelectedData);
+}
+
+void InspectorControlModel::setPropertyAnimated(long instance, int handle, bool animated)
+{
+ CCmd* cmd = nullptr;
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ if (animated)
+ cmd = new CCmdDataModelAnimate(doc, instance, handle);
+ else
+ cmd = new CCmdDataModelDeanimate(doc, instance, handle);
+
+ g_StudioApp.GetCore()->ExecuteCommand(cmd);
+}
+
+void InspectorControlModel::onSlideRearranged(const UICDM::CUICDMSlideHandle &inMaster,
+ int inOldIndex, int inNewIndex)
+{
+ Q_UNUSED(inMaster);
+ Q_UNUSED(inOldIndex);
+ Q_UNUSED(inNewIndex);
+ rebuildTree();
+}
+
+QVariant InspectorControlModel::data(const QModelIndex &index, int role) const
+{
+ if (!hasIndex(index.row(), index.column(),index.parent()))
+ return {};
+
+ const auto row = index.row();
+
+ switch (role) {
+ case GroupValuesRole:
+ return m_groupElements.at(row).controlElements;
+ case GroupTitleRole:
+ return m_groupElements.at(row).groupTitle;
+ }
+ return {};
+}
+
+QHash<int, QByteArray> InspectorControlModel::roleNames() const
+{
+ auto names = QAbstractListModel::roleNames();
+ names.insert(GroupValuesRole, "values");
+ names.insert(GroupTitleRole, "title");
+ return names;
+}
+
+InspectorControlBase::~InspectorControlBase()
+{
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h
new file mode 100644
index 00000000..20718039
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INSPECTORCONTROLMODEL_H
+#define INSPECTORCONTROLMODEL_H
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qvector.h>
+
+#include "UICDMValue.h"
+#include "UICDMMetaDataValue.h"
+#include "UICDMMetaDataTypes.h"
+#include "UICFileTools.h"
+
+#include "IDocumentEditor.h"
+
+class CInspectableBase;
+class CUICDMInspectable;
+class SGuideInspectableImpl;
+
+namespace UICDM {
+class ISignalConnection;
+typedef std::shared_ptr<ISignalConnection> TSignalConnectionPtr;
+}
+
+namespace Q3DStudio
+{
+class CUICDMInspectorRow;
+}
+
+class InspectorControlBase : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(UICDM::DataModelDataType::Value dataType MEMBER m_dataType CONSTANT)
+ Q_PROPERTY(UICDM::AdditionalMetaDataType::Value propertyType MEMBER m_propertyType CONSTANT)
+ Q_PROPERTY(QVariant value MEMBER m_value NOTIFY valueChanged)
+ Q_PROPERTY(QVariant values MEMBER m_values NOTIFY valuesChanged)
+ Q_PROPERTY(QString title MEMBER m_title CONSTANT)
+ Q_PROPERTY(QString toolTip MEMBER m_tooltip CONSTANT)
+ Q_PROPERTY(int instance MEMBER m_instance CONSTANT)
+ Q_PROPERTY(int handle MEMBER m_property CONSTANT)
+
+ Q_PROPERTY(bool animatable MEMBER m_animatable CONSTANT)
+ Q_PROPERTY(bool animated MEMBER m_animated NOTIFY animatedChanged)
+
+public:
+ virtual ~InspectorControlBase();
+
+Q_SIGNALS:
+ void valueChanged();
+ void valuesChanged();
+ void animatedChanged();
+
+public:
+ UICDM::DataModelDataType::Value m_dataType;
+ UICDM::AdditionalMetaDataType::Value m_propertyType;
+ QVariant m_value;
+ QVariant m_values;
+ QString m_title;
+ QString m_tooltip;
+
+ UICDM::CUICDMInstanceHandle m_instance;
+ UICDM::CUICDMPropertyHandle m_property;
+
+ bool m_animatable = false;
+ bool m_animated = false;
+
+ std::vector<UICDM::TSignalConnectionPtr> m_connections;
+};
+
+class InspectorControlModel : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ explicit InspectorControlModel(QObject *parent);
+ ~InspectorControlModel() = default;
+
+ enum Roles {
+ GroupValuesRole = Qt::UserRole + 1,
+ GroupTitleRole
+ };
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+
+ QHash<int, QByteArray> roleNames() const override;
+
+ void setInspectable(CInspectableBase *inInspectable);
+ void setMaterials(std::vector<Q3DStudio::CFilePath> &materials);
+ void refreshRenderables();
+ void refresh();
+
+ QVariant getPropertyValue(long instance, int handle);
+
+ Q_INVOKABLE void setMaterialTypeValue(long instance, int handle, const QVariant &value);
+ Q_INVOKABLE void setRenderableValue(long instance, int handle, const QVariant &value);
+ Q_INVOKABLE void setPropertyValue(long instance, int handle, const QVariant &value, bool commit = true);
+ Q_INVOKABLE void setSlideSelection(long instance, int handle, int index,
+ const QStringList &list);
+ Q_INVOKABLE void setPropertyAnimated(long instance, int handle, bool animated);
+
+private:
+ void onSlideRearranged(const UICDM::CUICDMSlideHandle &inMaster, int inOldIndex,
+ int inNewIndex);
+
+
+ struct GroupInspectorControl {
+ QString groupTitle;
+ QVariantList controlElements;
+
+ ~GroupInspectorControl() {
+ //for (auto element : controlElements)
+ // element.value<QObject *>()->deleteLater();
+ }
+ };
+
+ mutable QVector<GroupInspectorControl> m_groupElements;
+ CInspectableBase *m_inspectableBase = nullptr;
+
+ struct MaterialEntry
+ {
+ QString m_name;
+ QString m_relativePath;
+ };
+
+ std::vector<MaterialEntry> m_materials;
+
+ Q3DStudio::CUpdateableDocumentEditor m_UpdatableEditor;
+
+ void updatePropertyValue(InspectorControlBase *element) const;
+ void rebuildTree();
+ void notifyInstancePropertyValue(UICDM::CUICDMInstanceHandle, UICDM::CUICDMPropertyHandle inProperty);
+ void updateAnimateToggleState(InspectorControlBase* inItem);
+
+ std::shared_ptr<UICDM::ISignalConnection> m_notifier;
+ std::shared_ptr<UICDM::ISignalConnection> m_slideNotifier;
+
+ InspectorControlBase *createMaterialItem(CUICDMInspectable *inspectable, int groupIndex);
+ InspectorControlBase *createItem(CUICDMInspectable *inspectable,
+ Q3DStudio::CUICDMInspectorRow *row, int groupIndex);
+ InspectorControlBase *createItem(CUICDMInspectable *inspectable,
+ const UICDM::SMetaDataPropertyInfo &metaProperty,
+ int groupIndex);
+
+ UICDM::SValue currentPropertyValue(long instance, int handle);
+
+ QVector<GroupInspectorControl> computeTree(CInspectableBase *inspectBase);
+ bool isTreeRebuildRequired(CInspectableBase *inspectBase) const;
+
+ GroupInspectorControl computeGroup(CInspectableBase* inspectBase, int theIndex);
+ bool isGroupRebuildRequired(CInspectableBase *inspectable, int theIndex) const;
+
+};
+
+#endif // INSPECTORCONTROLMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp
new file mode 100644
index 00000000..3079c02a
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp
@@ -0,0 +1,429 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "InspectorControlView.h"
+#include "Literals.h"
+#include "CColor.h"
+#include "UICDMValue.h"
+#include "StudioUtils.h"
+#include "InspectorControlModel.h"
+#include "StudioPreferences.h"
+#include <QtCore/qtimer.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+#include <QtWidgets/qmenu.h>
+#include "Core.h"
+#include "Doc.h"
+#include "IDocumentEditor.h"
+#include "ImageChooserModel.h"
+#include "ImageChooserView.h"
+#include "MeshChooserView.h"
+#include "TextureChooserView.h"
+#include "InspectableBase.h"
+#include "StudioApp.h"
+#include "ObjectListModel.h"
+#include "ObjectBrowserView.h"
+#include "IDirectoryWatchingSystem.h"
+#include "StandardExtensions.h"
+#include "FileChooserView.h"
+#include "IObjectReferenceHelper.h"
+#include "UICDMStudioSystem.h"
+#include "StudioFullSystem.h"
+
+InspectorControlView::InspectorControlView(QWidget *parent)
+ : QQuickWidget(parent),
+ TabNavigable(),
+ m_inspectorControlModel(new InspectorControlModel(this)),
+ m_instance(0),
+ m_handle(0)
+{
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QTimer::singleShot(0, this, &InspectorControlView::initialize);
+ auto dispatch = g_StudioApp.GetCore()->GetDispatch();
+ dispatch->AddPresentationChangeListener(this);
+ dispatch->AddDataModelListener(this);
+
+ m_selectionChangedConnection = g_StudioApp.GetCore()->GetDispatch()->ConnectSelectionChange(
+ std::bind(&InspectorControlView::OnSelectionSet, this, std::placeholders::_1));
+}
+
+const wchar_t **AllSupportedExtensionsList()
+{
+ static const wchar_t *extensions[] = {
+ L"png", L"jpg", L"jpeg", L"dds", L"hdr",
+ L"mesh", L"import", L"path",
+ L"material",
+ nullptr
+ };
+ return extensions;
+}
+
+static bool isInList(const wchar_t **list, const Q3DStudio::CString &inStr)
+{
+ for (const wchar_t **item = list; item && *item; ++item) {
+ if (inStr.Compare(*item, Q3DStudio::CString::ENDOFSTRING, false))
+ return true;
+ }
+ return false;
+}
+
+void InspectorControlView::filterMaterials(std::vector<Q3DStudio::CFilePath> &materials)
+{
+ static const wchar_t *extensions[] = {
+ L"material",
+ nullptr
+ };
+ for (size_t i = 0; i < m_fileList.size(); ++i) {
+ if (isInList(extensions, m_fileList[i].GetExtension()))
+ materials.push_back(m_fileList[i]);
+ }
+}
+
+void InspectorControlView::OnNewPresentation()
+{
+ m_DirectoryConnection = g_StudioApp.GetDirectoryWatchingSystem().AddDirectory(
+ g_StudioApp.GetCore()->GetDoc()->GetDocumentDirectory().toQString(),
+ std::bind(&InspectorControlView::onFilesChanged, this, std::placeholders::_1));
+}
+
+void InspectorControlView::OnClosingPresentation()
+{
+ m_fileList.clear();
+}
+
+void InspectorControlView::OnLoadedSubPresentation()
+{
+ m_DirectoryConnection = g_StudioApp.GetDirectoryWatchingSystem().AddDirectory(
+ g_StudioApp.GetCore()->GetDoc()->GetDocumentDirectory().toQString(),
+ std::bind(&InspectorControlView::onFilesChanged, this, std::placeholders::_1));
+}
+
+void InspectorControlView::onFilesChanged(
+ const Q3DStudio::TFileModificationList &inFileModificationList)
+{
+ const wchar_t **extensions = AllSupportedExtensionsList();
+ for (size_t idx = 0, end = inFileModificationList.size(); idx < end; ++idx) {
+ const Q3DStudio::SFileModificationRecord &record(inFileModificationList[idx]);
+ if (record.m_FileInfo.IsFile()
+ && isInList(extensions, record.m_File.GetExtension())) {
+ Q3DStudio::CFilePath relativePath(
+ Q3DStudio::CFilePath::GetRelativePathFromBase(
+ g_StudioApp.GetCore()->GetDoc()->GetDocumentDirectory(),
+ record.m_File));
+
+ if (record.m_ModificationType == Q3DStudio::FileModificationType::Created)
+ UICDM::binary_sort_insert_unique(m_fileList, relativePath);
+ else if (record.m_ModificationType == Q3DStudio::FileModificationType::Destroyed)
+ UICDM::binary_sort_erase(m_fileList, relativePath);
+ }
+ if (record.m_FileInfo.IsFile()
+ && record.m_ModificationType == Q3DStudio::FileModificationType::Modified) {
+ if (record.m_File.toQString() == g_StudioApp.GetCore()->GetDoc()
+ ->GetDocumentUIAFile()) {
+ m_inspectorControlModel->refreshRenderables();
+ }
+ }
+ }
+ std::vector<Q3DStudio::CFilePath> materials;
+ filterMaterials(materials);
+ m_inspectorControlModel->setMaterials(materials);
+}
+
+InspectorControlView::~InspectorControlView()
+{
+ g_StudioApp.GetCore()->GetDispatch()->RemovePresentationChangeListener(this);
+}
+
+QSize InspectorControlView::sizeHint() const
+{
+ return {120, 600};
+}
+
+void InspectorControlView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty("_inspectorView"_L1, this);
+ rootContext()->setContextProperty("_inspectorModel"_L1, m_inspectorControlModel);
+ rootContext()->setContextProperty("_resDir"_L1, resourceImageUrl());
+ rootContext()->setContextProperty("_tabOrderHandler"_L1, tabOrderHandler());
+ qmlRegisterUncreatableType<UICDM::DataModelDataType>("Qt3DStudio", 1, 0, "DataModelDataType",
+ "DataModelDataType is an enum container");
+ qmlRegisterUncreatableType<UICDM::AdditionalMetaDataType>(
+ "Qt3DStudio", 1, 0, "AdditionalMetaDataType",
+ "AdditionalMetaDataType is an enum container");
+ engine()->addImportPath(qmlImportPath());
+ setSource(QUrl("qrc:/Studio/Palettes/Inspector/InspectorControlView.qml"_L1));
+}
+
+QAbstractItemModel *InspectorControlView::inspectorControlModel() const
+{
+ return m_inspectorControlModel;
+}
+
+QString InspectorControlView::titleText() const
+{
+ if (m_inspectableBase) {
+ Q3DStudio::CString theName = m_inspectableBase->GetName();
+ if (theName == L"PathAnchorPoint")
+ return tr("Anchor Point");
+ else
+ return theName.toQString();
+ }
+ return tr("No Object Selected");
+}
+
+QColor InspectorControlView::titleColor(int instance, int handle) const
+{
+ if (instance != 0 && handle != 0) {
+ if (g_StudioApp.GetCore()->GetDoc()->GetDocumentReader().IsPropertyLinked(instance, handle))
+ return CStudioPreferences::masterColor();
+ else
+ return CStudioPreferences::textColor();
+ } else {
+ return CStudioPreferences::textColor();
+ }
+}
+
+QString InspectorControlView::titleIcon() const
+{
+ if (m_inspectableBase)
+ return CStudioObjectTypes::GetNormalIconName(m_inspectableBase->GetObjectType());
+ return {};
+}
+
+void InspectorControlView::OnSelectionSet(Q3DStudio::SSelectedValue inSelectable)
+{
+ updateInspectable(g_StudioApp.GetInspectableFromSelectable(inSelectable));
+}
+
+void InspectorControlView::updateInspectable(CInspectableBase *inInspectable)
+{
+ if (inInspectable != nullptr) {
+ if (inInspectable->IsValid() == false)
+ inInspectable = nullptr;
+ }
+ setInspectable(inInspectable);
+}
+
+void InspectorControlView::setInspectable(CInspectableBase *inInspectable)
+{
+ if (m_inspectableBase != inInspectable) {
+ m_inspectableBase = inInspectable;
+ m_inspectorControlModel->setInspectable(inInspectable);
+ Q_EMIT titleChanged();
+ auto sp = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetFullSystem()->GetSignalProvider();
+ m_PropertyChangeConnection = sp->ConnectInstancePropertyValue(
+ std::bind(&InspectorControlView::titleChanged, this));
+ }
+}
+
+void InspectorControlView::showContextMenu(int x, int y, int handle, int instance)
+{
+ m_instance = instance;
+ m_handle = handle;
+
+ QMenu theContextMenu;
+
+ auto doc = g_StudioApp.GetCore()->GetDoc();
+ bool isLinkedFlag = doc->GetDocumentReader().IsPropertyLinked(instance, handle);
+ bool canBeLinkedFlag = doc->GetDocumentReader().CanPropertyBeLinked(instance, handle);
+ if (isLinkedFlag) {
+ auto action = theContextMenu.addAction(QObject::tr("Unlink Property from Master Slide"));
+ action->setEnabled(canBeLinkedFlag);
+ connect(action, &QAction::triggered, this, &InspectorControlView::toggleMasterLink);
+ } else {
+ auto action = theContextMenu.addAction(QObject::tr("Link Property from Master Slide"));
+ action->setEnabled(canBeLinkedFlag);
+ connect(action, &QAction::triggered, this, &InspectorControlView::toggleMasterLink);
+ }
+ theContextMenu.exec(mapToGlobal({x, y}));
+
+ m_instance = 0;
+ m_handle = 0;
+}
+
+void InspectorControlView::toggleMasterLink()
+{
+ Q3DStudio::ScopedDocumentEditor editor(*g_StudioApp.GetCore()->GetDoc(),
+ L"Link Property", __FILE__, __LINE__);
+ bool wasLinked = editor->IsPropertyLinked(m_instance, m_handle);
+
+ if (wasLinked)
+ editor->UnlinkProperty(m_instance, m_handle);
+ else
+ editor->LinkProperty(m_instance, m_handle);
+}
+
+void InspectorControlView::setPropertyValueFromFilename(long instance, int handle,
+ const QString &name)
+{
+ if (m_inspectorControlModel) {
+ QString value;
+ if (name != tr("[None]"))
+ value = name;
+ m_inspectorControlModel->setPropertyValue(instance, handle, value);
+ }
+}
+
+QObject *InspectorControlView::showImageChooser(int handle, int instance, const QPoint &point)
+{
+ if (!m_imageChooserView) {
+ m_imageChooserView = new ImageChooserView(this);
+ connect(m_imageChooserView, &ImageChooserView::imageSelected, this,
+ [this] (int handle, int instance, const QString &imageName){
+ setPropertyValueFromFilename(instance, handle, imageName);
+ m_imageChooserView->hide();
+ });
+ }
+
+ m_imageChooserView->setHandle(handle);
+ m_imageChooserView->setInstance(instance);
+
+ showBrowser(m_imageChooserView, point);
+
+ return m_imageChooserView;
+}
+
+QObject *InspectorControlView::showFilesChooser(int handle, int instance, const QPoint &point)
+{
+ if (!m_fileChooserView) {
+ m_fileChooserView = new FileChooserView(this);
+ connect(m_fileChooserView, &FileChooserView::fileSelected, this,
+ [this] (int handle, int instance, const QString &fileName){
+ setPropertyValueFromFilename(instance, handle, fileName);
+ m_fileChooserView->hide();
+ });
+ }
+
+ m_fileChooserView->setHandle(handle);
+ m_fileChooserView->setInstance(instance);
+
+ showBrowser(m_fileChooserView, point);
+
+ return m_fileChooserView;
+}
+
+QObject *InspectorControlView::showMeshChooser(int handle, int instance, const QPoint &point)
+{
+ if (!m_meshChooserView) {
+ m_meshChooserView = new MeshChooserView(this);
+ connect(m_meshChooserView, &MeshChooserView::meshSelected, this,
+ [this] (int handle, int instance, const QString &name){
+ if (m_inspectorControlModel)
+ m_inspectorControlModel->setPropertyValue(instance, handle, name);
+ });
+ }
+
+ m_meshChooserView->setHandle(handle);
+ m_meshChooserView->setInstance(instance);
+
+ showBrowser(m_meshChooserView, point);
+
+ return m_meshChooserView;
+}
+
+QObject *InspectorControlView::showTextureChooser(int handle, int instance, const QPoint &point)
+{
+ if (!m_textureChooserView) {
+ m_textureChooserView = new TextureChooserView(this);
+ connect(m_textureChooserView, &TextureChooserView::textureSelected, this,
+ [this] (int handle, int instance, const QString &fileName){
+ setPropertyValueFromFilename(instance, handle, fileName);
+ m_textureChooserView->hide();
+ });
+ }
+
+ m_textureChooserView->setHandle(handle);
+ m_textureChooserView->setInstance(instance);
+
+ showBrowser(m_textureChooserView, point);
+
+ return m_textureChooserView;
+}
+
+QObject *InspectorControlView::showObjectReference(int handle, int instance, const QPoint &point)
+{
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ if (!m_objectReferenceModel) {
+ m_objectReferenceModel
+ = new ObjectListModel(g_StudioApp.GetCore(), doc->GetActiveRootInstance(), this);
+ }
+ if (!m_objectReferenceView)
+ m_objectReferenceView = new ObjectBrowserView(this);
+ m_objectReferenceView->setModel(m_objectReferenceModel);
+
+ disconnect(m_objectReferenceView);
+
+ showBrowser(m_objectReferenceView, point);
+
+ connect(m_objectReferenceView, &ObjectBrowserView::selectionChanged,
+ this, [this, doc, handle, instance] {
+ auto selectedItem = m_objectReferenceView->selectedHandle();
+ UICDM::SObjectRefType objRef = doc->GetDataModelObjectReferenceHelper()->GetAssetRefValue(
+ selectedItem, handle,
+ (CRelativePathTools::EPathType)(m_objectReferenceView->pathType()));
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*doc, QObject::tr("Set Property"))
+ ->SetInstancePropertyValue(instance, handle, objRef);
+ });
+
+ return m_objectReferenceView;
+}
+
+void InspectorControlView::showBrowser(QQuickWidget *browser, const QPoint &point)
+{
+ QSize popupSize = CStudioPreferences::browserPopupSize();
+ browser->resize(popupSize);
+ browser->move(point - QPoint(popupSize.width(), popupSize.height()));
+
+ // Show asynchronously to avoid flashing blank window on first show
+ QTimer::singleShot(0, this, [browser] {
+ browser->show();
+ browser->activateWindow();
+ browser->setFocus();
+ });
+}
+
+void InspectorControlView::OnBeginDataModelNotifications()
+{
+
+}
+
+void InspectorControlView::OnEndDataModelNotifications()
+{
+ m_inspectorControlModel->refresh();
+}
+
+void InspectorControlView::OnImmediateRefreshInstanceSingle(UICDM::CUICDMInstanceHandle inInstance)
+{
+ m_inspectorControlModel->refresh();
+}
+
+void InspectorControlView::OnImmediateRefreshInstanceMultiple(UICDM::CUICDMInstanceHandle *inInstance, long inInstanceCount)
+{
+ m_inspectorControlModel->refresh();
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h
new file mode 100644
index 00000000..e5815e6c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INSPECTORCONTROLVIEW_H
+#define INSPECTORCONTROLVIEW_H
+
+#include <QtQuickWidgets/qquickwidget.h>
+#include <QtCore/qpointer.h>
+#include "DispatchListeners.h"
+#include "Dispatch.h"
+#include "UICFileTools.h"
+#include "TabOrderHandler.h"
+
+class InspectorControlModel;
+class QAbstractItemModel;
+class CInspectableBase;
+class ImageChooserView;
+class ImageChooserModel;
+class MeshChooserView;
+class ObjectBrowserView;
+class ObjectListModel;
+class FileChooserView;
+class TextureChooserView;
+
+class InspectorControlView : public QQuickWidget,
+ public CPresentationChangeListener,
+ public IDataModelListener,
+ public TabNavigable
+{
+ Q_OBJECT
+ Q_PROPERTY(QString titleText READ titleText NOTIFY titleChanged FINAL)
+ Q_PROPERTY(QString titleIcon READ titleIcon NOTIFY titleChanged FINAL)
+public:
+ explicit InspectorControlView(QWidget *parent = nullptr);
+ ~InspectorControlView();
+
+ void OnSelectionSet(Q3DStudio::SSelectedValue inValue);
+ QAbstractItemModel *inspectorControlModel() const;
+
+ QString titleText() const;
+ Q_INVOKABLE QColor titleColor(int instance = 0, int handle = 0) const;
+ QString titleIcon() const;
+
+ Q_INVOKABLE void showContextMenu(int x, int y, int handle, int instance);
+ Q_INVOKABLE QObject *showImageChooser(int handle, int instance, const QPoint &point);
+ Q_INVOKABLE QObject *showFilesChooser(int handle, int instance, const QPoint &point);
+ Q_INVOKABLE QObject *showMeshChooser(int handle, int instance, const QPoint &point);
+ Q_INVOKABLE QObject *showObjectReference(int handle, int instance, const QPoint &point);
+ Q_INVOKABLE QObject *showTextureChooser(int handle, int instance, const QPoint &point);
+
+ // IDataModelListener
+ void OnBeginDataModelNotifications() override;
+ void OnEndDataModelNotifications() override;
+ void OnImmediateRefreshInstanceSingle(UICDM::CUICDMInstanceHandle inInstance) override;
+ void OnImmediateRefreshInstanceMultiple(UICDM::CUICDMInstanceHandle *inInstance,
+ long inInstanceCount) override;
+
+
+Q_SIGNALS:
+ void titleChanged();
+ void controlsChanged();
+ void imageSelected(const QString &name);
+
+public Q_SLOTS:
+ void toggleMasterLink();
+
+protected:
+ QSize sizeHint() const override;
+
+private:
+ void setInspectable(CInspectableBase *inInspectable);
+ void updateInspectable(CInspectableBase *inInspectable);
+ void initialize();
+ void onFilesChanged(const Q3DStudio::TFileModificationList &inFileModificationList);
+ void OnNewPresentation() override;
+ void OnClosingPresentation() override;
+ void OnLoadedSubPresentation() override;
+ void filterMaterials(std::vector<Q3DStudio::CFilePath> &materials);
+ void setPropertyValueFromFilename(long instance, int handle, const QString &name);
+ void showBrowser(QQuickWidget *browser, const QPoint &point);
+
+ std::shared_ptr<UICDM::ISignalConnection> m_selectionChangedConnection;
+ std::shared_ptr<UICDM::ISignalConnection> m_DirectoryConnection;
+ std::shared_ptr<UICDM::ISignalConnection> m_PropertyChangeConnection;
+ QColor m_backgroundColor;
+ InspectorControlModel *m_inspectorControlModel = nullptr;
+ CInspectableBase *m_inspectableBase = nullptr;
+ QPointer<ImageChooserView> m_imageChooserView;
+ QPointer<MeshChooserView> m_meshChooserView;
+ QPointer<FileChooserView> m_fileChooserView;
+ QPointer<TextureChooserView> m_textureChooserView;
+ QPointer<ObjectBrowserView> m_objectReferenceView;
+ QPointer<ObjectListModel> m_objectReferenceModel;
+ std::vector<Q3DStudio::CFilePath> m_fileList;
+
+ int m_instance;
+ int m_handle;
+};
+
+#endif // INSPECTORCONTROLVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml
new file mode 100644
index 00000000..9e838d4c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml
@@ -0,0 +1,771 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.8
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 2.2
+
+import Qt3DStudio 1.0
+import "../controls"
+import "../Action"
+
+Rectangle {
+ id: root
+ color: _backgroundColor
+
+ Connections {
+ target: _inspectorModel
+ onModelAboutToBeReset: {
+ _tabOrderHandler.clear();
+ }
+ }
+
+ ColumnLayout {
+ anchors.fill: parent
+ anchors.topMargin: 4
+ spacing: 8
+
+ RowLayout {
+ height: _controlBaseHeight + anchors.margins * 2
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.margins: 4
+
+ Image {
+ id: headerImage
+ source: _inspectorView.titleIcon !== "" ? _resDir + _inspectorView.titleIcon : ""
+ }
+
+ StyledLabel {
+ text: _inspectorView.titleText
+ color: _inspectorView.titleColor()
+ }
+ }
+
+ ListView {
+ id: groupElements
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ spacing: 4
+
+ clip: true
+
+ ScrollBar.vertical: ScrollBar {
+ visible: size < 1.0
+ }
+
+ model: _inspectorModel
+ delegate: Rectangle {
+ id: delegateItem
+
+ property int indexOfThisDelegate: index
+
+ width: parent.width
+ height: items.height
+ color: "transparent";
+
+ readonly property var values: model.values
+
+ Column {
+ id: items
+
+ x: 10
+ width: parent.width - x
+ spacing: 4
+
+ StyledLabel {
+ text: model.title
+ }
+
+ Column {
+ spacing: 4
+
+ Repeater {
+ model: delegateItem.values
+
+ onItemAdded: {
+ if (index === 0)
+ _tabOrderHandler.clearGroup(indexOfThisDelegate);
+ if (item.loadedItem.tabItem1 !== undefined) {
+ _tabOrderHandler.addItem(indexOfThisDelegate,
+ item.loadedItem.tabItem1)
+ if (item.loadedItem.tabItem2 !== undefined) {
+ _tabOrderHandler.addItem(
+ indexOfThisDelegate,
+ item.loadedItem.tabItem2)
+ if (item.loadedItem.tabItem3 !== undefined) {
+ _tabOrderHandler.addItem(
+ indexOfThisDelegate,
+ item.loadedItem.tabItem3)
+ }
+ }
+ }
+ }
+
+ RowLayout {
+ id: groupDelegateItem
+ spacing: 0
+
+ property alias loadedItem: loader.item
+
+ function showContextMenu(coords) {
+ _inspectorView.showContextMenu(
+ coords.x, coords.y,
+ model.modelData.handle,
+ model.modelData.instance);
+ // Refresh text; title color is wrong after this
+ propertyRow.color = _inspectorView.titleColor(
+ modelData.instance, modelData.handle);
+ }
+
+ Item {
+ Layout.alignment: Qt.AlignTop
+ width: animatedPropertyButton.sourceSize.width
+ height: _controlBaseHeight
+ visible: model.modelData.animatable
+ Image {
+ id: animatedPropertyButton
+
+ property bool animated: model.modelData.animated
+
+ anchors.fill: parent
+ fillMode: Image.Pad
+
+ source: {
+ _resDir + (animated
+ ? "Inspector-AnimateToggle-Active.png"
+ : "Inspector-AnimateToggle-Normal.png")
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton | Qt.LeftButton
+ onClicked: {
+ if (mouse.button === Qt.LeftButton) {
+ _inspectorModel.setPropertyAnimated(
+ model.modelData.instance,
+ model.modelData.handle,
+ !model.modelData.animated)
+ } else {
+ const coords = mapToItem(root, mouse.x, mouse.y);
+ groupDelegateItem.showContextMenu(coords);
+ }
+ }
+ }
+ }
+ }
+
+
+ Item {
+ // Spacer item
+ width: model.modelData.animatable
+ ? 4 : animatedPropertyButton.width + 4
+ height: loadedItem.height + 4 // Add little space between items
+ }
+
+ StyledLabel {
+ id: propertyRow
+
+ readonly property var modelData: model.modelData
+ text: model.modelData.title
+ color: _inspectorView.titleColor(modelData.instance,
+ modelData.handle)
+
+ Layout.alignment: Qt.AlignTop
+
+ MouseArea {
+ id: mouse
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton
+ hoverEnabled: true
+ onClicked: {
+ const coords = mapToItem(root, mouse.x, mouse.y);
+ groupDelegateItem.showContextMenu(coords);
+ }
+ }
+
+ StyledTooltip {
+ text: modelData.toolTip
+ visible: mouse.containsMouse
+ }
+ }
+
+ Loader {
+ id: loader
+ readonly property var modelData: propertyRow.modelData
+ sourceComponent: {
+ const dataType = modelData.dataType;
+ console.warn("KDAB_TODO: DEBUG for type", dataType,
+ "property", modelData.propertyType,
+ "text ", model.modelData.title);
+ switch (dataType) {
+ case DataModelDataType.Long:
+ if (modelData.propertyType ===
+ AdditionalMetaDataType.ShadowMapResolution) {
+ return shadowResolutionComponent;
+ }
+ if (modelData.propertyType === AdditionalMetaDataType.Range) {
+ return intSliderComponent;
+ }
+ console.warn("KDAB_TODO: implement handler for type \"Long\", property:",
+ modelData.propertyType);
+ return null;
+ case DataModelDataType.Long4:
+ if (modelData.propertyType === AdditionalMetaDataType.Image) {
+ return imageChooser;
+ }
+ console.warn("KDAB_TODO: implement handler for type \"long4\" property:",
+ modelData.propertyType);
+ return null;
+ case DataModelDataType.ObjectRef:
+ if (modelData.propertyType === AdditionalMetaDataType.ObjectRef)
+ return objectReference;
+ console.warn("KDAB_TODO: implement handler for type: \"objectref\" property:",
+ modelData.propertyType);
+ return null;
+ case DataModelDataType.StringOrInt:
+ //TODO: Maybe do some further check if the right combo is used
+ if (modelData.propertyType === AdditionalMetaDataType.StringList)
+ return slideSelectionDropDown;
+ console.warn("KDAB_TODO: (String) implement handler for type \"stringOrInt\" property:",
+ modelData.propertyType);
+ return null;
+ case DataModelDataType.String:
+ if (modelData.propertyType === AdditionalMetaDataType.Import)
+ return fileChooser;
+ if (modelData.propertyType === AdditionalMetaDataType.StringList)
+ return comboDropDown;
+ if (modelData.propertyType === AdditionalMetaDataType.Renderable)
+ return renderableDropDown;
+ if (modelData.propertyType === AdditionalMetaDataType.Mesh)
+ return meshChooser;
+ if (modelData.propertyType === AdditionalMetaDataType.MultiLine)
+ return multiLine;
+ if (modelData.propertyType === AdditionalMetaDataType.Font)
+ return comboDropDown;
+ if (modelData.propertyType === AdditionalMetaDataType.Texture)
+ return textureChooser;
+ console.warn("KDAB_TODO: (String) implement handler for type \"string\" property:",
+ modelData.propertyType);
+ return null;
+ case DataModelDataType.Bool:
+ return checkBox;
+ case DataModelDataType.Float:
+ if (modelData.propertyType === AdditionalMetaDataType.None)
+ return valueComponent;
+ if (modelData.propertyType === AdditionalMetaDataType.Range)
+ return sliderComponent;
+ if (modelData.propertyType === AdditionalMetaDataType.FontSize)
+ return fontSizeComponent;
+ console.warn("KDAB_TODO: implement handler for type\"float\" property:",
+ modelData.propertyType);
+ return null;
+ case DataModelDataType.Float3:
+ if (modelData.propertyType === AdditionalMetaDataType.Color)
+ return colorBox;
+ if (modelData.propertyType === AdditionalMetaDataType.Rotation)
+ return xyzPropertyComponent;
+ if (modelData.propertyType === AdditionalMetaDataType.None)
+ return xyzPropertyComponent;
+ console.warn("KDAB_TODO: implement handler for type:\"float3\" property:",
+ modelData.propertyType, "text ",
+ model.modelData.title);
+ return null;
+ case DataModelDataType.StringRef:
+ if (modelData.propertyType === AdditionalMetaDataType.None)
+ return materialDropDown;
+ console.warn("KDAB_TODO: implement handler for type:\"StringRef\" text ",
+ model.modelData.title);
+ return null;
+ default:
+ console.warn("KDAB_TODO: implement handler for type",
+ dataType, "property",
+ modelData.propertyType, "text ",
+ model.modelData.title);
+ }
+ return null;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Component {
+ id: multiLine
+
+ ScrollView {
+ id: scrollView
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property variant value: parent.modelData.value
+ property Item tabItem1: textArea
+
+ width: _valueWidth
+ height: _controlBaseHeight * 3
+ clip: true
+
+ ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
+ ScrollBar.vertical.policy: ScrollBar.AsNeeded
+
+ TextArea {
+ id: textArea
+
+ text: scrollView.value
+ horizontalAlignment: TextInput.AlignLeft
+ verticalAlignment: TextInput.AlignTop
+ font.pixelSize: _fontSize
+ color: _textColor
+ wrapMode: TextEdit.WordWrap
+ selectionColor: _selectionColor
+ selectedTextColor: _textColor
+
+ topPadding: 6
+ bottomPadding: 6
+ rightPadding: 6
+
+ background: Rectangle {
+ color: textArea.enabled ? _studioColor2 : "transparent"
+ border.width: textArea.activeFocus ? 1 : 0
+ border.color: textArea.activeFocus ? _selectionColor : _disabledColor
+ }
+
+ MouseArea {
+ id: mouseAreaX
+ anchors.fill: parent
+ property int clickedPos
+ preventStealing: true
+
+ onPressed: {
+ textArea.forceActiveFocus()
+ clickedPos = textArea.positionAt(mouse.x, mouse.y)
+ textArea.cursorPosition = clickedPos
+ }
+ onDoubleClicked: textArea.selectAll()
+ onPositionChanged: {
+ textArea.cursorPosition = textArea.positionAt(mouse.x, mouse.y)
+ textArea.select(clickedPos, textArea.cursorPosition)
+ }
+ }
+
+ onTextChanged: {
+ _inspectorModel.setPropertyValue(scrollView.instance, scrollView.handle,
+ text, false)
+ }
+
+ onEditingFinished: {
+ _inspectorModel.setPropertyValue(scrollView.instance, scrollView.handle,
+ text, true)
+ }
+ }
+ }
+ }
+
+ Component {
+ id: meshChooser
+ HandlerFilesChooser {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property variant values: parent.modelData.values
+ value: parent.modelData.value
+ onShowBrowser: {
+ activeBrowser = _inspectorView.showMeshChooser(handle, instance,
+ mapToGlobal(width, 0))
+ }
+ }
+ }
+
+ Component {
+ id: imageChooser
+ HandlerFilesChooser {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property variant values: parent.modelData.values
+ value: parent.modelData.value
+ onShowBrowser: {
+ activeBrowser = _inspectorView.showImageChooser(handle, instance,
+ mapToGlobal(width, 0))
+ }
+ }
+ }
+
+ Component {
+ id: fileChooser
+ HandlerFilesChooser {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property variant values: parent.modelData.values
+ value: parent.modelData.value === "" ? qsTr("[None]") : parent.modelData.value
+ onShowBrowser: {
+ activeBrowser = _inspectorView.showFilesChooser(handle, instance,
+ mapToGlobal(width, 0))
+ }
+ }
+ }
+
+ Component {
+ id: textureChooser
+ HandlerFilesChooser {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property variant values: parent.modelData.values
+ value: parent.modelData.value
+ onShowBrowser: {
+ activeBrowser = _inspectorView.showTextureChooser(handle, instance,
+ mapToGlobal(width, 0))
+ }
+ }
+ }
+
+ Component {
+ id: xyzPropertyComponent
+
+ RowLayout {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property variant values: parent.modelData.values
+ property alias tabItem1: xyzHandler.tabItem1
+ property alias tabItem2: xyzHandler.tabItem2
+ property alias tabItem3: xyzHandler.tabItem3
+ spacing: 0
+ Item {
+ width: _valueWidth - xyzHandler.width
+ }
+ HandlerPropertyBaseXYZ {
+ id: xyzHandler
+ valueX: Number(values[0]).toFixed(3)
+ valueY: Number(values[1]).toFixed(3)
+ valueZ: Number(values[2]).toFixed(3)
+ onEditingFinished: {
+ _inspectorModel.setPropertyValue(parent.instance, parent.handle,
+ Qt.vector3d(valueX, valueY, valueZ))
+ }
+ }
+ }
+ }
+
+ Component {
+ id: valueComponent
+
+ RowLayout {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property real value: Number(parent.modelData.value).toFixed(3)
+ property Item tabItem1: floatField
+ spacing: 0
+ Item {
+ width: _valueWidth - floatField.width
+ }
+ FloatTextField {
+ id: floatField
+ text: parent.value
+ implicitHeight: _controlBaseHeight
+ implicitWidth: _valueWidth / 2
+
+ onWheelEventFinished: {
+ _inspectorModel.setPropertyValue(parent.instance, parent.handle, Number(text));
+ }
+
+ onEditingFinished: {
+ _inspectorModel.setPropertyValue(parent.instance, parent.handle, Number(text));
+ }
+ }
+ }
+ }
+
+ Component {
+ id: sliderComponent
+
+ HandlerPropertyBaseSlider {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property variant values: parent.modelData.values
+ property real oldValue: 0.0
+
+ value: parent.modelData.value
+ sliderMin: values[0]
+ sliderMax: values[1]
+
+ onEditingStarted: {
+ oldValue = value
+ }
+ onEditingFinished: {
+ // make sure the undo step is created, therefore resetting it to the old value
+ var val = value
+ _inspectorModel.setPropertyValue(instance, handle, oldValue, false)
+ _inspectorModel.setPropertyValue(instance, handle, val, true)
+ }
+ onSliderMoved: {
+ _inspectorModel.setPropertyValue(instance, handle, value, false)
+ }
+ }
+ }
+
+ Component {
+ id: comboDropDown
+
+ StyledComboBox {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property var values: parent.modelData.values
+ property var value: parent.modelData.value
+
+ model: values
+
+ implicitWidth: _valueWidth
+ implicitHeight: _controlBaseHeight
+
+ Component.onCompleted: {
+ currentIndex = find(value)
+ }
+ onCurrentIndexChanged: {
+ var newValue = textAt(currentIndex)
+ if (value !== newValue && currentIndex !== -1)
+ _inspectorModel.setPropertyValue(instance, handle, newValue)
+ }
+ onValueChanged: {
+ currentIndex = find(value)
+ }
+ }
+ }
+
+ Component {
+ id: slideSelectionDropDown
+
+ StyledComboBox {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property var values: parent.modelData.values
+ property var value: parent.modelData.value
+
+ model: values
+
+ implicitWidth: _valueWidth
+ implicitHeight: _controlBaseHeight
+
+ Component.onCompleted: {
+ var newIndex = find(value)
+ if (newIndex === -1)
+ newIndex = find(value + "|separator")
+ currentIndex = newIndex
+ }
+ onCurrentIndexChanged: {
+ var newValue = textAt(currentIndex).replace("|separator", "")
+ if (value !== newValue && currentIndex !== -1) {
+ _inspectorModel.setSlideSelection(instance, handle,
+ currentIndex, values)
+ }
+ }
+ onValueChanged: {
+ var newIndex = find(value)
+ if (newIndex === -1)
+ newIndex = find(value + "|separator")
+ currentIndex = newIndex
+ }
+ }
+ }
+
+ Component {
+ id: materialDropDown
+
+ StyledComboBox {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property var values: parent.modelData.values
+ property var value: parent.modelData.value
+
+ model: values
+
+ implicitWidth: _valueWidth
+ implicitHeight: _controlBaseHeight
+
+ Component.onCompleted: {
+ currentIndex = find(value)
+ }
+ onCurrentIndexChanged: {
+ var newValue = textAt(currentIndex)
+ if (value !== newValue && currentIndex !== -1)
+ _inspectorModel.setMaterialTypeValue(instance, handle, newValue)
+ }
+ onValueChanged: {
+ currentIndex = find(value)
+ }
+ }
+ }
+
+ Component {
+ id: renderableDropDown
+
+ StyledComboBox {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property var values: parent.modelData.values
+ property var value: parent.modelData.value
+ model: values
+
+ implicitWidth: _valueWidth
+ implicitHeight: _controlBaseHeight
+
+ Component.onCompleted: {
+ currentIndex = find(value)
+ }
+
+ onCurrentIndexChanged: {
+ var newValue = textAt(currentIndex)
+ if (value !== newValue && currentIndex !== -1)
+ _inspectorModel.setRenderableValue(instance, handle, newValue)
+ }
+ onValueChanged: {
+ currentIndex = find(value)
+ }
+ }
+ }
+
+ Component {
+ id: checkBox
+
+ Image {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property bool checked: parent.modelData.value
+
+ source: (_resDir + (checked ? "checkbox-checked.png" : "checkbox-unchecked.png"))
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: _inspectorModel.setPropertyValue(instance, handle, !checked)
+ }
+ }
+ }
+
+ Component {
+ id: colorBox
+
+ HandlerGenericBaseColor {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+
+ color: parent.modelData.value
+ onColorSelected: _inspectorModel.setPropertyValue(instance, handle, selectedColor)
+ }
+ }
+
+ Component {
+ id: objectReference
+
+ HandlerGenericChooser {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property variant values: parent.modelData.values
+ value: parent.modelData.value
+ onShowBrowser: {
+ activeBrowser = _inspectorView.showObjectReference(handle, instance,
+ mapToGlobal(width, 0))
+ }
+ }
+ }
+
+ Component {
+ id: intSliderComponent
+
+ HandlerPropertyBaseSlider {
+ intSlider: true;
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property variant values: parent.modelData.values
+ intValue: parent.modelData.value
+ sliderMin: values[0]
+ sliderMax: values[1]
+
+ onEditingFinished: {
+ _inspectorModel.setPropertyValue(instance, handle, intValue)
+ }
+ }
+ }
+
+ Component {
+ id: fontSizeComponent
+
+ StyledComboBox {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property real value: parent.modelData.value
+
+ model: ["8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "26", "28", "36", "48", "72", "96", "120"]
+
+ implicitWidth: _valueWidth
+ implicitHeight: _controlBaseHeight
+
+ Component.onCompleted: {
+ currentIndex = find(value)
+ }
+
+ onCurrentIndexChanged: {
+ var newvalue = parseInt(textAt(currentIndex))
+ _inspectorModel.setPropertyValue(instance, handle, newvalue)
+ }
+
+ onValueChanged: {
+ currentIndex = find(value)
+ }
+ }
+ }
+
+ Component {
+ id: shadowResolutionComponent
+
+ StyledComboBox {
+ property int instance: parent.modelData.instance
+ property int handle: parent.modelData.handle
+ property var value: parent.modelData.value
+ property int newValue
+
+ model: ["8", "9", "10", "11"]
+ implicitWidth: _valueWidth
+ implicitHeight: _controlBaseHeight
+
+ Component.onCompleted: {
+ currentIndex = find(value)
+ }
+
+ onCurrentIndexChanged: {
+ newValue = parseInt(textAt(currentIndex))
+ if (value !== newValue && currentIndex !== -1)
+ _inspectorModel.setPropertyValue(instance, handle, newValue)
+ }
+
+ onValueChanged: {
+ currentIndex = find(value)
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorGroup.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorGroup.cpp
new file mode 100644
index 00000000..c3ea86cb
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorGroup.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "InspectorGroup.h"
+
+//==============================================================================
+/**
+ * Constructor
+ */
+CInspectorGroup::CInspectorGroup()
+{
+}
+
+//==============================================================================
+/**
+ * Destructor
+ */
+CInspectorGroup::~CInspectorGroup()
+{
+}
+
+//==============================================================================
+/**
+ * Set the name to show up in the title bar
+ */
+void CInspectorGroup::SetName(const QString &inName)
+{
+ m_name = inName;
+}
+
+QString CInspectorGroup::GetName() const
+{
+ return m_name;
+}
+
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorGroup.h b/src/Authoring/Studio/Palettes/Inspector/InspectorGroup.h
new file mode 100644
index 00000000..98ac824d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorGroup.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_INSPECTOR_GROUP_H
+#define INCLUDED_INSPECTOR_GROUP_H 1
+
+#pragma once
+
+#include <QString>
+
+//==============================================================================
+/**
+ * @class CInspectorGroup
+ * @brief This is the base class for inspector groups.
+ *
+ * Derive from this class in order to create a new group for the inspector
+ * palette.
+ */
+class CInspectorGroup
+{
+public:
+ enum EGroupCommand {
+ EGroupCommandNone = 0,
+ EGroupCommandToggle,
+ };
+
+public:
+ CInspectorGroup();
+ virtual ~CInspectorGroup();
+
+ void SetName(const QString &inName);
+ QString GetName() const;
+
+protected:
+ QString m_name;
+};
+
+#endif // INCLUDED_INSPECTOR_GROUP_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/MeshChooser.qml b/src/Authoring/Studio/Palettes/Inspector/MeshChooser.qml
new file mode 100644
index 00000000..229c4c8c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/MeshChooser.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+Rectangle {
+ id: root
+
+ color: _backgroundColor
+ border.color: _studioColor3
+
+ ColumnLayout {
+ anchors.fill: parent
+ ListView {
+ id: listView
+
+ anchors {
+ fill: parent
+ leftMargin: 8
+ }
+
+ boundsBehavior: Flickable.StopAtBounds
+ spacing: 4
+ clip: true
+
+ ScrollBar.vertical: ScrollBar {}
+
+ model: _meshChooserModel
+
+ delegate: ChooserDelegate {
+ onClicked: _meshChooserView.setSelectedMeshName(filePath)
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.cpp b/src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.cpp
new file mode 100644
index 00000000..e1b61bbf
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "MeshChooserModel.h"
+#include "Core.h"
+#include "Doc.h"
+#include "IDocumentBufferCache.h"
+#include "StudioApp.h"
+
+MeshChooserModel::MeshChooserModel(QObject *parent)
+ : ChooserModelBase(parent)
+{
+}
+
+MeshChooserModel::~MeshChooserModel()
+{
+
+}
+
+bool MeshChooserModel::isVisible(const QString &path) const
+{
+ return getIconType(path) == OBJTYPE_MODEL;
+}
+
+const QVector<ChooserModelBase::FixedItem> MeshChooserModel::getFixedItems() const
+{
+ static QVector<FixedItem> items;
+
+ if (items.isEmpty()) {
+ auto primitiveNames = g_StudioApp.GetCore()->GetDoc()->GetBufferCache().GetPrimitiveNames();
+ for (auto item = primitiveNames; *item; ++item) {
+ auto itemName = *item;
+ if (itemName[0] == L'#')
+ items.append({ OBJTYPE_MODEL, QString::fromWCharArray(itemName + 1) });
+ }
+ }
+
+ return items;
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.h b/src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.h
new file mode 100644
index 00000000..5aea88a8
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MESHCHOOSERMODEL_H
+#define MESHCHOOSERMODEL_H
+
+#include "ChooserModelBase.h"
+
+class MeshChooserModel : public ChooserModelBase
+{
+ Q_OBJECT
+
+public:
+ explicit MeshChooserModel(QObject *parent = nullptr);
+ virtual ~MeshChooserModel();
+
+private:
+ bool isVisible(const QString &path) const override;
+ const QVector<FixedItem> getFixedItems() const override;
+};
+
+#endif // MESHCHOOSERMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.cpp b/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.cpp
new file mode 100644
index 00000000..86f7c75b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.cpp
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "MeshChooserView.h"
+#include "MeshChooserModel.h"
+#include "Literals.h"
+#include "StudioUtils.h"
+#include "StudioPreferences.h"
+#include "IDocumentEditor.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMValue.h"
+#include "Core.h"
+#include "Doc.h"
+#include "StudioApp.h"
+#include "IDocumentBufferCache.h"
+
+#include <QtCore/qtimer.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+
+MeshChooserView::MeshChooserView(QWidget *parent)
+ : QQuickWidget(parent)
+ , m_model(new MeshChooserModel(this))
+{
+ setWindowTitle(tr("Meshes"));
+ setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QTimer::singleShot(0, this, &MeshChooserView::initialize);
+}
+
+void MeshChooserView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty("_resDir"_L1,
+ resourceImageUrl());
+ rootContext()->setContextProperty("_meshChooserView"_L1, this);
+ rootContext()->setContextProperty("_meshChooserModel"_L1, m_model);
+
+ engine()->addImportPath(qmlImportPath());
+ setSource(QUrl("qrc:/Studio/Palettes/Inspector/MeshChooser.qml"_L1));
+}
+
+QSize MeshChooserView::sizeHint() const
+{
+ return {500, 500};
+}
+
+void MeshChooserView::setSelectedMeshName(const QString &name)
+{
+ hide();
+ bool resourceName = false;
+ QString meshName = QLatin1Char('#') + name;
+ const wchar_t **files = g_StudioApp.GetCore()->GetDoc()->GetBufferCache().GetPrimitiveNames();
+ for (const wchar_t **item = files; item && *item; ++item) {
+ QString primitive = QString::fromWCharArray(*item);
+ if (primitive == meshName) {
+ resourceName = true;
+ break;
+ }
+ }
+ if (!resourceName)
+ meshName = name;
+
+ Q_EMIT meshSelected(m_handle, m_instance, meshName);
+}
+
+void MeshChooserView::setHandle(int handle)
+{
+ m_handle = handle;
+}
+
+void MeshChooserView::setInstance(int instance)
+{
+ m_instance = instance;
+}
+
+void MeshChooserView::focusOutEvent(QFocusEvent *event)
+{
+ QQuickWidget::focusOutEvent(event);
+ QTimer::singleShot(0, this, &MeshChooserView::close);
+}
+
+void MeshChooserView::showEvent(QShowEvent *event)
+{
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+
+ UICDM::SValue value;
+ propertySystem->GetInstancePropertyValue(m_instance, m_handle, value);
+
+ const QString meshValue = UICDM::get<QString>(value);
+ const Q3DStudio::CFilePath selectionItem = Q3DStudio::CFilePath::fromQString(meshValue);
+ const Q3DStudio::CFilePath selectionWithoutId = selectionItem.GetPathWithoutIdentifier();
+
+ QString currentFile;
+
+ if (selectionWithoutId.size()) {
+ currentFile = selectionWithoutId.toQString();
+ } else {
+ currentFile = selectionItem.GetIdentifier().toQString();
+ }
+
+ m_model->setCurrentFile(currentFile);
+
+ QQuickWidget::showEvent(event);
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.h b/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.h
new file mode 100644
index 00000000..b47770d9
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/MeshChooserView.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MESHCHOOSERVIEW_H
+#define MESHCHOOSERVIEW_H
+
+#include <QQuickWidget>
+
+namespace Q3DStudio {
+class CFilePath;
+class CString;
+}
+
+class QAbstractItemModel;
+class MeshChooserModel;
+class MeshChooserView : public QQuickWidget
+{
+ Q_OBJECT
+public:
+ explicit MeshChooserView(QWidget *parent = nullptr);
+
+ QSize sizeHint() const override;
+
+ Q_INVOKABLE void setSelectedMeshName(const QString &name);
+
+ void setHandle(int handle);
+ void setInstance(int instance);
+
+Q_SIGNALS:
+ void meshSelected(int handle, int instance, const QString &name);
+
+protected:
+ void focusOutEvent(QFocusEvent *event) override;
+
+private:
+ void showEvent(QShowEvent *event) override;
+ void initialize();
+ int m_handle = -1;
+ int m_instance = -1;
+ MeshChooserModel *m_model = nullptr;
+};
+
+#endif // MESHCHOOSERVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowser.qml b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowser.qml
new file mode 100644
index 00000000..d0ece17a
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowser.qml
@@ -0,0 +1,175 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import Qt3DStudio 1.0
+import "../controls"
+
+Rectangle {
+ id: root
+
+ property alias selectedText: selectionText.text
+
+ color: _backgroundColor
+ border.color: _studioColor3
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ spacing: 10
+
+ ListView {
+ id: browserList
+
+ Layout.margins: 10
+ Layout.columnSpan: 2
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.minimumHeight: 80
+ Layout.preferredHeight: count * 20
+ Layout.preferredWidth: root.width
+
+ ScrollBar.vertical: ScrollBar {}
+
+ model: _objectBrowserView.model
+ boundsBehavior: Flickable.StopAtBounds
+ clip: true
+
+ delegate: Item {
+ id: delegateItem
+
+ x: model.depth * 20
+ width: parent.width
+ height: model.parentExpanded ? typeIcon.height + 10 : 0
+
+ visible: height > 0
+
+ Behavior on height {
+ NumberAnimation {
+ duration: 100
+ easing.type: Easing.OutQuad
+ }
+ }
+
+ Row {
+ id: row
+
+ height: typeIcon.height
+ spacing: 5
+
+ Image {
+ source: {
+ if (!model.hasChildren)
+ return "";
+ model.expanded ? _resDir + "arrow_down.png"
+ : _resDir + "arrow.png";
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: model.expanded = !model.expanded
+ }
+ }
+
+ Rectangle {
+ height: typeIcon.height
+ width: typeIcon.width + name.width + 10
+
+ color: model.index === browserList.currentIndex ? _selectionColor
+ : "transparent"
+
+ Row {
+ spacing: 10
+ Image {
+ id: typeIcon
+
+ source: model.icon
+ }
+
+ StyledLabel {
+ id: name
+ anchors.verticalCenter: typeIcon.verticalCenter
+ color: model.textColor
+ text: model.name
+ }
+ }
+
+ MouseArea {
+ id: delegateArea
+
+ anchors.fill: parent
+ onClicked: browserList.currentIndex = model.index
+ onDoubleClicked: {
+ browserList.currentIndex = model.index;
+ _objectBrowserView.close();
+ }
+ }
+ }
+ }
+ }
+
+ onCurrentIndexChanged: _objectBrowserView.selection = currentIndex
+ }
+
+ StyledMenuSeparator {}
+
+ GridLayout {
+ columns: 2
+ Layout.margins: 10
+
+ StyledLabel {
+ text: qsTr("Type")
+ }
+
+ StyledComboBox {
+ id: pathCombo
+ model: [qsTr("Absolute Reference"), qsTr("Path Reference")]
+
+ onActivated: {
+ if (index === 0)
+ _objectBrowserView.pathType = ObjectBrowserView.Name;
+ else if (index === 1)
+ _objectBrowserView.pathType = ObjectBrowserView.Relative;
+ }
+ }
+
+ StyledLabel {
+ text: qsTr("Path")
+ }
+
+ StyledLabel {
+ id: selectionText
+ Layout.preferredWidth: _valueWidth
+ text: pathCombo.currentIndex === 0 ? _objectBrowserView.name(browserList.currentIndex)
+ : _objectBrowserView.path(browserList.currentIndex)
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp
new file mode 100644
index 00000000..86067722
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "ObjectBrowserView.h"
+
+#include "CColor.h"
+#include "Literals.h"
+#include "ObjectListModel.h"
+#include "StudioPreferences.h"
+#include "StudioUtils.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qtimer.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+
+ObjectBrowserView::ObjectBrowserView(QWidget *parent)
+ : QQuickWidget(parent)
+{
+ setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QTimer::singleShot(0, this, &ObjectBrowserView::initialize);
+}
+
+QAbstractItemModel *ObjectBrowserView::model() const
+{
+ return m_model;
+}
+
+void ObjectBrowserView::setModel(ObjectListModel *model)
+{
+ if (!m_model) {
+ m_model = new FlatObjectListModel(model, this);
+ }
+ m_model->setSourceModel(model);
+
+ Q_EMIT modelChanged();
+}
+
+
+QSize ObjectBrowserView::sizeHint() const
+{
+ return {500, 500};
+}
+
+QString ObjectBrowserView::name(int index) const
+{
+ return m_model->index(index, 0).data(ObjectListModel::NameRole).toString();
+}
+
+QString ObjectBrowserView::path(int index) const
+{
+ return m_model->index(index, 0).data(ObjectListModel::PathReferenceRole).toString();
+}
+
+void ObjectBrowserView::setSelection(int index)
+{
+ if (m_selection != index) {
+ m_selection = index;
+ Q_EMIT selectionChanged();
+ }
+}
+
+void ObjectBrowserView::setPathType(ObjectBrowserView::PathType type)
+{
+ if (type != m_pathType) {
+ m_pathType = type;
+ Q_EMIT pathTypeChanged();
+ }
+}
+
+UICDM::CUICDMInstanceHandle ObjectBrowserView::selectedHandle() const
+{
+ auto handleId = m_model->index(m_selection, 0).data(ObjectListModel::HandleRole).toInt();
+ return UICDM::CUICDMInstanceHandle(handleId);
+}
+
+void ObjectBrowserView::focusOutEvent(QFocusEvent *event)
+{
+ QQuickWidget::focusOutEvent(event);
+ QTimer::singleShot(0, this, &ObjectBrowserView::close);
+}
+
+void ObjectBrowserView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty("_objectBrowserView"_L1, this);
+ rootContext()->setContextProperty("_resDir"_L1, resourceImageUrl());
+ qmlRegisterUncreatableType<ObjectBrowserView>("Qt3DStudio", 1, 0, "ObjectBrowserView"
+ , tr("Creation of ObjectBrowserView not allowed from QML"));
+ engine()->addImportPath(qmlImportPath());
+ setSource(QUrl("qrc:/Studio/Palettes/Inspector/ObjectBrowser.qml"_L1));
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.h b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.h
new file mode 100644
index 00000000..8a4ed1eb
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef OBJECTBROWSERVIEW_H
+#define OBJECTBROWSERVIEW_H
+
+#include <QQuickWidget>
+
+#include "RelativePathTools.h"
+#include "UICDMHandles.h"
+
+#include <QColor>
+
+class ObjectListModel;
+class FlatObjectListModel;
+
+class QAbstractItemModel;
+
+class ObjectBrowserView : public QQuickWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(QAbstractItemModel *model READ model NOTIFY modelChanged FINAL)
+ Q_PROPERTY(int selection READ selection WRITE setSelection NOTIFY selectionChanged FINAL)
+ Q_PROPERTY(PathType pathType READ pathType WRITE setPathType NOTIFY pathTypeChanged FINAL)
+
+public:
+ ObjectBrowserView(QWidget *parent = nullptr);
+
+
+ enum PathType {
+ Name = CRelativePathTools::EPATHTYPE_GUID,
+ Relative = CRelativePathTools::EPATHTYPE_RELATIVE,
+ };
+ Q_ENUM(PathType)
+
+ QAbstractItemModel *model() const;
+ void setModel(ObjectListModel *model);
+ QSize sizeHint() const override;
+
+ Q_INVOKABLE QString name(int index) const;
+ Q_INVOKABLE QString path(int index) const;
+
+ int selection() const { return m_selection; }
+ void setSelection(int index);
+
+ PathType pathType() const {return m_pathType;}
+ void setPathType(PathType type);
+
+ UICDM::CUICDMInstanceHandle selectedHandle() const;
+
+Q_SIGNALS:
+ void modelChanged();
+ void pathTypeChanged();
+ void selectionChanged();
+
+protected:
+ void focusOutEvent(QFocusEvent *event) override;
+
+private:
+ void initialize();
+
+ FlatObjectListModel *m_model = nullptr;
+ QHash<int, ObjectListModel *> m_subModels;
+ QColor m_baseColor = QColor::fromRgb(75, 75, 75);
+ QColor m_selectColor;
+ int m_selection = -1;
+ PathType m_pathType = Name;
+};
+
+#endif // OBJECTBROWSERVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp
new file mode 100644
index 00000000..ad1d752f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp
@@ -0,0 +1,336 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ObjectListModel.h"
+
+#include "Core.h"
+#include "Doc.h"
+#include "GraphUtils.h"
+#include "IObjectReferenceHelper.h"
+#include "StudioUtils.h"
+#include "SlideSystem.h"
+#include "StudioObjectTypes.h"
+#include "StudioPreferences.h"
+#include "UICDMStudioSystem.h"
+
+#include <QCoreApplication>
+#include <QColor>
+
+ObjectListModel::ObjectListModel(CCore *core,
+ const UICDM::CUICDMInstanceHandle &baseHandle, QObject *parent)
+ : QAbstractItemModel(parent)
+ , m_core(core)
+ , m_baseHandle(baseHandle)
+{
+ auto doc = m_core->GetDoc();
+ m_objRefHelper = doc->GetDataModelObjectReferenceHelper();
+ m_slideHandle = m_objRefHelper->GetSlideList(m_baseHandle)[0];
+}
+
+QHash<int, QByteArray> ObjectListModel::roleNames() const
+{
+ auto names = QAbstractItemModel::roleNames();
+ names.insert(NameRole, "name");
+ names.insert(HandleRole, "handle");
+ names.insert(IconRole, "icon");
+ names.insert(TextColorRole, "textColor");
+ names.insert(AbsolutePathRole, "absolutePath");
+ names.insert(PathReferenceRole, "referencePath");
+
+ return names;
+}
+
+int ObjectListModel::rowCount(const QModelIndex &parent) const
+{
+ if (!parent.isValid())
+ return 1;
+
+ const auto handle = handleForIndex(parent);
+ const auto children = childrenList(m_slideHandle, handle);
+ return children.size();
+}
+
+int ObjectListModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent)
+ return 1;
+}
+
+QVariant ObjectListModel::data(const QModelIndex &index, int role) const
+{
+ if (!hasIndex(index.row(), index.column(), index.parent()))
+ return {};
+
+ switch (role) {
+ case NameRole: {
+ return nameForHandle(handleForIndex(index));
+ }
+ case PathReferenceRole: {
+ Q3DStudio::CString data(m_objRefHelper->GetObjectReferenceString(
+ m_baseHandle, CRelativePathTools::EPATHTYPE_RELATIVE, handleForIndex(index)));
+ return data.toQString();
+ }
+ case AbsolutePathRole: {
+ Q3DStudio::CString data(m_objRefHelper->GetObjectReferenceString(
+ m_baseHandle, CRelativePathTools::EPATHTYPE_GUID, handleForIndex(index)));
+ return data.toQString();
+ }
+ case HandleRole: {
+ return (int)handleForIndex(index);
+ }
+ case IconRole: {
+ auto info = m_objRefHelper->GetInfo(handleForIndex(index));
+ return resourceImageUrl() + CStudioObjectTypes::GetNormalIconName(info.m_Type);
+ }
+ case TextColorRole: {
+ auto info = m_objRefHelper->GetInfo(handleForIndex(index));
+ if (info.m_Master)
+ return QVariant::fromValue(CStudioPreferences::masterColor());
+ else
+ return QVariant::fromValue(CStudioPreferences::textColor());
+ }
+ default:
+ return {};
+ }
+
+ return {};
+}
+
+QModelIndex ObjectListModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (!parent.isValid())
+ return createIndex(row, column, (quintptr)(m_baseHandle));
+
+ const auto handle = handleForIndex(parent);
+ const auto children = childrenList(m_slideHandle, handle);
+ if (row >= children.size())
+ return {};
+
+ auto childHandle = children[row];
+ return createIndex(row, column, (quintptr)(childHandle));
+}
+
+QModelIndex ObjectListModel::parent(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return {};
+
+ const auto handle = handleForIndex(index);
+ UICDM::CUICDMInstanceHandle parentHandle = m_core->GetDoc()->GetAssetGraph()->GetParent(handle);
+ if (!parentHandle.Valid())
+ return {};
+
+ int row = 0;
+ UICDM::CUICDMInstanceHandle grandParentHandle = m_core->GetDoc()->GetAssetGraph()
+ ->GetParent(handle);
+ const auto children = childrenList(m_slideHandle, grandParentHandle);
+ const auto it = std::find(children.begin(), children.end(), parentHandle);
+ if (it != children.end())
+ row = it - children.begin();
+
+ return createIndex(row, 0, (quintptr)(parentHandle));
+}
+
+UICDM::CUICDMInstanceHandle ObjectListModel::handleForIndex(const QModelIndex &index) const
+{
+ return static_cast<UICDM::CUICDMInstanceHandle>(index.internalId());
+}
+
+UICDM::TInstanceHandleList ObjectListModel::childrenList(const UICDM::CUICDMSlideHandle &slideHandle, const UICDM::CUICDMInstanceHandle &handle) const
+{
+ auto slideSystem = m_core->GetDoc()->GetStudioSystem()->GetSlideSystem();
+ auto currentMaster = slideSystem->GetMasterSlide(slideHandle);
+
+ UICDM::TInstanceHandleList children;
+ m_objRefHelper->GetChildInstanceList(handle, children, slideHandle, m_baseHandle);
+ children.erase(
+ std::remove_if(children.begin(), children.end(),
+ [&slideHandle, slideSystem, &currentMaster](const UICDM::CUICDMInstanceHandle &h) {
+ const auto childSlide = slideSystem->GetAssociatedSlide(h);
+ if (!childSlide.Valid())
+ return true;
+ const auto childMaster = slideSystem->GetMasterSlide(childSlide);
+ if (childMaster == currentMaster) {
+ return childSlide != childMaster && childSlide != slideHandle;
+ } else {
+ return childSlide != childMaster;
+ }
+ }), children.end());
+ return children;
+}
+
+QString ObjectListModel::nameForHandle(const UICDM::CUICDMInstanceHandle &handle) const
+{
+ const auto data = m_objRefHelper->GetInfo(handle);
+ return data.m_Name.toQString();
+}
+
+QModelIndex ObjectListModel::indexForHandle(const UICDM::CUICDMInstanceHandle &handle,
+ const QModelIndex &startIndex) const
+{
+ if (handle == m_baseHandle)
+ return index(0, 0, {});
+
+ for (int i = 0; i < rowCount(startIndex); i++) {
+ auto idx = index(i, 0, startIndex);
+ if (static_cast<UICDM::CUICDMInstanceHandle>(idx.internalId()) == handle)
+ return idx;
+ if (rowCount(idx) > 0)
+ return indexForHandle(handle, idx);
+ }
+ return {};
+}
+
+
+FlatObjectListModel::FlatObjectListModel(ObjectListModel *sourceModel, QObject *parent)
+ : QAbstractListModel(parent)
+ , m_sourceModel(sourceModel)
+
+{
+ Q_ASSERT(sourceModel);
+ m_sourceInfo = collectSourceIndexes({}, 0);
+}
+
+QVector<FlatObjectListModel::SourceInfo> FlatObjectListModel::collectSourceIndexes(
+ const QModelIndex &sourceIndex, int depth) const
+{
+ QVector<SourceInfo> sourceInfo;
+
+ for (int i = 0; i < m_sourceModel->rowCount(sourceIndex); i++) {
+ auto idx = m_sourceModel->index(i, 0, sourceIndex);
+ SourceInfo info;
+ info.depth = depth;
+ info.index = idx;
+ sourceInfo.append(info);
+ if (m_sourceModel->rowCount(idx) > 0) {
+ sourceInfo += collectSourceIndexes(idx, depth + 1);
+ }
+ }
+
+ return sourceInfo;
+}
+
+QHash<int, QByteArray> FlatObjectListModel::roleNames() const
+{
+ auto roles = m_sourceModel->roleNames();
+ roles.insert(DepthRole, "depth");
+ roles.insert(ExpandedRole, "expanded");
+ roles.insert(ParentExpandedRole, "parentExpanded");
+ roles.insert(HasChildrenRole, "hasChildren");
+ return roles;
+}
+
+QModelIndex FlatObjectListModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+ int row = proxyIndex.row();
+ if (row < 0 || row >= m_sourceInfo.count())
+ return {};
+ return m_sourceInfo[row].index;
+}
+
+QVariant FlatObjectListModel::data(const QModelIndex &index, int role) const
+{
+ const auto row = index.row();
+ if (row < 0 || row >= m_sourceInfo.count())
+ return {};
+
+ switch (role) {
+ case DepthRole: {
+ auto info = m_sourceInfo[row];
+ return info.depth;
+ }
+ case ExpandedRole: {
+ auto info = m_sourceInfo[row];
+ return info.expanded;
+ }
+ case ParentExpandedRole: {
+ auto info = m_sourceInfo[row];
+ if (info.depth == 0)
+ return true;
+
+ int depth = info.depth;
+ for (int i = row - 1; i >= 0; i--) {
+ const auto prevInfo = m_sourceInfo[i];
+ if (prevInfo.depth < depth) {
+ if (!prevInfo.expanded) {
+ return false;
+ } else {
+ depth = prevInfo.depth;
+ }
+ }
+ }
+ return true;
+ }
+ case HasChildrenRole: {
+ if (row == m_sourceInfo.count() - 1)
+ return false;
+ auto info = m_sourceInfo[row];
+ auto nextInfo = m_sourceInfo[row + 1];
+ return (nextInfo.depth > info.depth);
+ }
+ }
+
+ QModelIndex sourceIndex = mapToSource(index);
+ return m_sourceModel->data(sourceIndex, role);
+}
+
+bool FlatObjectListModel::setData(const QModelIndex &index, const QVariant &data, int role)
+{
+ const auto row = index.row();
+ if (row < 0 || row >= m_sourceInfo.count())
+ return {};
+
+ switch (role) {
+ case ExpandedRole: {
+ auto info = &m_sourceInfo[index.row()];
+ info->expanded = data.toBool();
+ Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), {});
+ return true;
+ }
+ }
+
+ QModelIndex sourceIndex = mapToSource(index);
+ return m_sourceModel->setData(sourceIndex, data, role);
+}
+
+int FlatObjectListModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return m_sourceInfo.count();
+}
+
+void FlatObjectListModel::setSourceModel(ObjectListModel *sourceModel)
+{
+ beginResetModel();
+ m_sourceModel = sourceModel;
+ m_sourceInfo = collectSourceIndexes({}, 0);
+ endResetModel();
+}
+
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h
new file mode 100644
index 00000000..fbff3537
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OBJECTLISTMODEL_H
+#define OBJECTLISTMODEL_H
+
+#include <QAbstractItemModel>
+#include <QAbstractListModel>
+
+#include "UICDMHandles.h"
+
+class IObjectReferenceHelper;
+class CCore;
+
+class ObjectListModel : public QAbstractItemModel
+{
+ Q_OBJECT
+public:
+ ObjectListModel(CCore *core, const UICDM::CUICDMInstanceHandle &baseHandle, QObject *parent = nullptr);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex &index) const override;
+
+ enum Roles {
+ NameRole = Qt::DisplayRole,
+ AbsolutePathRole = Qt::UserRole + 1,
+ PathReferenceRole,
+ IconRole,
+ TextColorRole,
+ HandleRole,
+ LastRole = HandleRole
+ };
+
+ QHash<int, QByteArray> roleNames() const override;
+
+ UICDM::CUICDMInstanceHandle baseHandle() const {return m_baseHandle;}
+
+private:
+ UICDM::CUICDMInstanceHandle handleForIndex(const QModelIndex &index) const;
+
+ UICDM::TInstanceHandleList childrenList(const UICDM::CUICDMSlideHandle &slideHandle,
+ const UICDM::CUICDMInstanceHandle &handle) const;
+
+ QString nameForHandle(const UICDM::CUICDMInstanceHandle &handle) const;
+
+ QModelIndex indexForHandle(const UICDM::CUICDMInstanceHandle &handle, const QModelIndex &startIndex = {}) const;
+
+ CCore *m_core;
+ UICDM::CUICDMSlideHandle m_slideHandle;
+ UICDM::CUICDMInstanceHandle m_baseHandle;
+ IObjectReferenceHelper *m_objRefHelper;
+};
+
+class FlatObjectListModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ FlatObjectListModel(ObjectListModel *sourceModel, QObject *parent = nullptr);
+
+ enum Roles {
+ DepthRole = ObjectListModel::LastRole + 1,
+ ExpandedRole,
+ ParentExpandedRole,
+ HasChildrenRole
+ };
+
+ QHash<int, QByteArray> roleNames() const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ bool setData(const QModelIndex &index, const QVariant &data, int role = Qt::EditRole) override;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ void setSourceModel(ObjectListModel *sourceModel);
+ ObjectListModel *sourceModel() const {return m_sourceModel;}
+
+private:
+ QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
+
+ struct SourceInfo {
+ bool expanded = false;
+ int depth = 0;
+ QPersistentModelIndex index;
+ };
+
+ QVector<SourceInfo> collectSourceIndexes(const QModelIndex &sourceIndex, int depth) const;
+
+ QVector<SourceInfo> m_sourceInfo;
+ ObjectListModel *m_sourceModel;
+};
+
+
+#endif // OBJECTLISTMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectReference.qml b/src/Authoring/Studio/Palettes/Inspector/ObjectReference.qml
new file mode 100644
index 00000000..3e456067
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectReference.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+
+Rectangle {
+ id: root
+
+ color: _backgroundColor
+ ColumnLayout {
+ anchors.fill: parent
+ //KDAB_FIXME implement object chooser
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.cpp b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.cpp
new file mode 100644
index 00000000..40dc91e1
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ObjectReferenceModel.h"
+
+ObjectReferenceModel::ObjectReferenceModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+ //KDAB_FIXME: Understand how it must be filled
+}
+
+ObjectReferenceModel::~ObjectReferenceModel()
+{
+
+}
+
+
+int ObjectReferenceModel::rowCount(const QModelIndex &parent) const
+{
+ //KDAB_FIXME
+ return 0;
+}
+
+QVariant ObjectReferenceModel::data(const QModelIndex &index, int role) const
+{
+ //KDAB_FIXME
+ return {};
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.h b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.h
new file mode 100644
index 00000000..29932442
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OBJECTREFERENCEMODEL_H
+#define OBJECTREFERENCEMODEL_H
+
+#include <QAbstractListModel>
+
+class ObjectReferenceModel : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ explicit ObjectReferenceModel(QObject *parent = nullptr);
+ ~ObjectReferenceModel();
+
+ int rowCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+};
+
+#endif // OBJECTREFERENCEMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.cpp b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.cpp
new file mode 100644
index 00000000..eab0b0aa
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ObjectReferenceView.h"
+#include "Literals.h"
+#include "StudioUtils.h"
+#include "StudioPreferences.h"
+#include "IDocumentEditor.h"
+#include "UICDMValue.h"
+#include "Core.h"
+#include "Doc.h"
+#include "StudioApp.h"
+
+#include <QtCore/qtimer.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+
+ObjectReferenceView::ObjectReferenceView(QWidget *parent) : QQuickWidget(parent)
+{
+ setWindowTitle(tr("Object Reference"));
+ setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QTimer::singleShot(0, this, &ObjectReferenceView::initialize);
+}
+
+void ObjectReferenceView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty("_resDir"_L1,
+ resourceImageUrl());
+ rootContext()->setContextProperty("_objectReferenceView"_L1, this);
+ engine()->addImportPath(qmlImportPath());
+ setSource(QUrl("qrc:/Studio/Palettes/Inspector/ObjectReference.qml"_L1));
+}
+
+QSize ObjectReferenceView::sizeHint() const
+{
+ return {500, 500};
+}
+
+QAbstractItemModel *ObjectReferenceView::model() const
+{
+ return m_model;
+}
+
+void ObjectReferenceView::setModel(QAbstractItemModel *model)
+{
+ if (m_model != model) {
+ m_model = model;
+ Q_EMIT modelChanged();
+ }
+}
+
+void ObjectReferenceView::setHandle(int handle)
+{
+ m_handle = handle;
+}
+
+void ObjectReferenceView::setInstance(int instance)
+{
+ m_instance = instance;
+}
+
+void ObjectReferenceView::setSelectedReference(const QString &name)
+{
+ UICDM::SValue v = QVariant(name);
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*g_StudioApp.GetCore()->GetDoc(), QObject::tr("Set Property"))
+ ->SetInstancePropertyValue(m_instance, m_handle, v);
+}
+
+void ObjectReferenceView::focusOutEvent(QFocusEvent *event)
+{
+ QQuickWidget::focusOutEvent(event);
+ close();
+}
+
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.h b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.h
new file mode 100644
index 00000000..5634fd97
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OBJECTREFERENCEVIEW_H
+#define OBJECTREFERENCEVIEW_H
+
+#include <QQuickWidget>
+class QAbstractItemModel;
+
+class ObjectReferenceView : public QQuickWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(QAbstractItemModel *model READ model NOTIFY modelChanged FINAL)
+public:
+ explicit ObjectReferenceView(QWidget *parent = nullptr);
+
+ QSize sizeHint() const override;
+ QAbstractItemModel *model() const;
+ void setModel(QAbstractItemModel *model);
+
+ void setHandle(int handle);
+ void setInstance(int instance);
+
+ Q_INVOKABLE void setSelectedReference(const QString &name);
+
+protected:
+ void focusOutEvent(QFocusEvent *event) override;
+
+Q_SIGNALS:
+ void modelChanged();
+
+private:
+ void initialize();
+ int m_handle = -1;
+ int m_instance = -1;
+ QColor m_baseColor = QColor::fromRgb(75, 75, 75);
+ QAbstractItemModel *m_model = nullptr;
+};
+
+#endif // OBJECTREFERENCEVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.cpp b/src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.cpp
new file mode 100644
index 00000000..415b1877
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "TabOrderHandler.h"
+
+TabOrderHandler::TabOrderHandler(QObject *parent)
+ : QObject(parent)
+{
+
+}
+
+TabOrderHandler::~TabOrderHandler()
+{
+
+}
+
+void TabOrderHandler::addItem(int group, QQuickItem *item)
+{
+ m_itemMap[group].append(item);
+}
+
+void TabOrderHandler::clear()
+{
+ m_itemMap.clear();
+}
+
+void TabOrderHandler::clearGroup(int group)
+{
+ m_itemMap[group].clear();
+}
+
+void TabOrderHandler::tabNavigate(bool tabForward)
+{
+ // Find the currently focused control
+ for (int i = 0; i < m_itemMap.size(); i++) {
+ const QList<QQuickItem *> items = m_itemMap[i];
+ for (int j = 0; j < items.size(); j++) {
+ if (items[j]->hasActiveFocus()) {
+ if (tabForward)
+ nextItem(i, j)->forceActiveFocus();
+ else
+ previousItem(i, j)->forceActiveFocus();
+ return;
+ }
+ }
+ }
+ // Activate the first item if could not find currently focused item
+ for (int i = 0; i < m_itemMap.size(); i++) {
+ if (m_itemMap[i].size() > 0)
+ m_itemMap[i][0]->forceActiveFocus();
+ }
+}
+
+QQuickItem *TabOrderHandler::nextItem(int group, int index)
+{
+ if (m_itemMap[group].size() > index + 1) {
+ // Try next item in group
+ index++;
+ } else {
+ // Get item in next available group
+ int nextGroup = group + 1;
+ while (nextGroup != group) {
+ if (m_itemMap.size() >= nextGroup)
+ nextGroup = 0;
+ if (m_itemMap[nextGroup].size() == 0)
+ nextGroup++;
+ else
+ group = nextGroup;
+ }
+ index = 0;
+ }
+ return m_itemMap[group][index];
+}
+
+QQuickItem *TabOrderHandler::previousItem(int group, int index)
+{
+ if (index - 1 >= 0) {
+ // Try previous item in group
+ index--;
+ } else {
+ // Get last item in previous available group
+ int nextGroup = group - 1;
+ while (nextGroup != group) {
+ if (nextGroup < 0)
+ nextGroup = m_itemMap.size() - 1;
+ if (m_itemMap[nextGroup].size() == 0)
+ nextGroup--;
+ else
+ group = nextGroup;
+ }
+ index = m_itemMap[group].size() - 1;
+ }
+ return m_itemMap[group][index];
+}
+
diff --git a/src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.h b/src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.h
new file mode 100644
index 00000000..10c1d400
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef TABORDERHANDLER_H
+#define TABORDERHANDLER_H
+
+#include <QtCore/qobject.h>
+#include <QtQuick/qquickitem.h>
+
+class TabOrderHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit TabOrderHandler(QObject *parent = nullptr);
+ ~TabOrderHandler();
+
+ Q_INVOKABLE void addItem(int group, QQuickItem *item);
+ Q_INVOKABLE void clear();
+ Q_INVOKABLE void clearGroup(int group);
+
+ void tabNavigate(bool tabForward);
+
+private:
+ QQuickItem *nextItem(int group, int index);
+ QQuickItem *previousItem(int group, int index);
+
+ QHash<int, QList<QQuickItem *> > m_itemMap;
+};
+
+class TabNavigable {
+public:
+ TabNavigable() : m_tabOrderHandler(new TabOrderHandler) {}
+ virtual ~TabNavigable() { delete m_tabOrderHandler; }
+ TabOrderHandler *tabOrderHandler() const { return m_tabOrderHandler; }
+
+private:
+ TabOrderHandler *m_tabOrderHandler;
+};
+
+#endif // TABORDERHANDLER_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/TextureChooser.qml b/src/Authoring/Studio/Palettes/Inspector/TextureChooser.qml
new file mode 100644
index 00000000..4f90640e
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/TextureChooser.qml
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+Rectangle {
+ id: root
+
+ color: _backgroundColor
+ border.color: _studioColor3
+
+ ColumnLayout {
+ anchors.fill: parent
+
+ spacing: 10
+ ListView {
+ id: listView
+
+ anchors {
+ fill: parent
+ leftMargin: 8
+ }
+
+ boundsBehavior: Flickable.StopAtBounds
+ spacing: 4
+ clip: true
+
+ ScrollBar.vertical: ScrollBar {}
+
+ model: _textureChooserModel
+
+ delegate: ChooserDelegate {
+ onClicked: {
+ _textureChooserView.textureSelected(
+ _textureChooserView.handle,
+ _textureChooserView.instance,
+ filePath);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.cpp b/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.cpp
new file mode 100644
index 00000000..78084b06
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "TextureChooserView.h"
+#include "ImageChooserModel.h"
+#include "StudioPreferences.h"
+#include "Literals.h"
+#include "StudioUtils.h"
+#include "IDocumentEditor.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMValue.h"
+#include "Core.h"
+#include "Doc.h"
+#include "StudioApp.h"
+#include "StudioPreferences.h"
+
+#include <QtCore/qtimer.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+
+TextureChooserView::TextureChooserView(QWidget *parent)
+ : QQuickWidget(parent)
+ , m_model(new ImageChooserModel(this))
+{
+ setWindowTitle(tr("Texture"));
+ setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QTimer::singleShot(0, this, &TextureChooserView::initialize);
+}
+
+void TextureChooserView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty("_textureChooserView"_L1, this);
+ rootContext()->setContextProperty("_textureChooserModel"_L1, m_model);
+ engine()->addImportPath(qmlImportPath());
+ setSource(QUrl("qrc:/Studio/Palettes/Inspector/TextureChooser.qml"_L1));
+}
+
+QSize TextureChooserView::sizeHint() const
+{
+ return {500, 500};
+}
+
+void TextureChooserView::setHandle(int handle)
+{
+ m_handle = handle;
+}
+
+int TextureChooserView::handle() const
+{
+ return m_handle;
+}
+
+void TextureChooserView::setInstance(int instance)
+{
+ m_instance = instance;
+}
+
+int TextureChooserView::instance() const
+{
+ return m_instance;
+}
+
+void TextureChooserView::focusOutEvent(QFocusEvent *event)
+{
+ QQuickWidget::focusOutEvent(event);
+ QTimer::singleShot(0, this, &TextureChooserView::close);
+}
+
+void TextureChooserView::showEvent(QShowEvent *event)
+{
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+
+ UICDM::SValue value;
+ propertySystem->GetInstancePropertyValue(m_instance, m_handle, value);
+
+ m_model->setCurrentFile(UICDM::get<QString>(value));
+
+ QQuickWidget::showEvent(event);
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.h b/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.h
new file mode 100644
index 00000000..5bd51367
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/TextureChooserView.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TEXTURECHOOSERVIEW_H
+#define TEXTURECHOOSERVIEW_H
+
+#include <QQuickWidget>
+
+class ImageChooserModel;
+
+class TextureChooserView : public QQuickWidget
+{
+ Q_OBJECT
+ Q_PROPERTY(int instance READ instance)
+ Q_PROPERTY(int handle READ handle)
+
+public:
+ explicit TextureChooserView(QWidget *parent = nullptr);
+
+ QSize sizeHint() const override;
+
+ void setHandle(int handle);
+ int handle() const;
+
+ void setInstance(int instance);
+ int instance() const;
+
+Q_SIGNALS:
+ void textureSelected(int handle, int instance, const QString &name);
+
+protected:
+ void focusOutEvent(QFocusEvent *event) override;
+
+private:
+ void showEvent(QShowEvent *event) override;
+ void initialize();
+ int m_handle = -1;
+ int m_instance = -1;
+ ImageChooserModel *m_model = nullptr;
+};
+
+#endif // TEXTURECHOOSERVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.cpp b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.cpp
new file mode 100644
index 00000000..1d009b4c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.cpp
@@ -0,0 +1,325 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "UICDMInspectable.h"
+#include "UICDMInspectorGroup.h"
+#include "UICDMInspectorRow.h"
+#include "StudioApp.h"
+#include "Doc.h"
+#include "UICDMStudioSystem.h"
+#include "ClientDataModelBridge.h"
+#include "UICDMDataCore.h"
+#include "UICDMPropertyDefinition.h"
+#include "Core.h"
+#include "StudioFullSystem.h"
+#include "StudioCoreSystem.h"
+#include "UICDMMetaData.h"
+#include "UICDMSlides.h"
+#include "IDocumentReader.h"
+#include "Strings.h"
+#include "StringLoader.h"
+
+using namespace UICDM;
+
+//==============================================================================
+/**
+ * Constructor
+ */
+CUICDMInspectable::CUICDMInspectable(CStudioApp &inApp, CCore *inCore,
+ UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMInstanceHandle inDualPersonalityInstance /*= 0*/)
+ : CInspectableBase(inCore)
+ , m_Instance(inInstance)
+ , m_DualPersonalityInstance((inDualPersonalityInstance != 0) ? inDualPersonalityInstance
+ : inInstance)
+ , m_App(inApp)
+{
+ QT3DS_ASSERT(inCore->GetDoc()->GetDocumentReader().IsInstance(m_Instance));
+}
+
+//==============================================================================
+/**
+ * Query the name of the inspectable item
+ */
+Q3DStudio::CString CUICDMInspectable::GetName()
+{
+ CClientDataModelBridge *theBridge =
+ m_Core->GetDoc()->GetStudioSystem()->GetClientDataModelBridge();
+
+ if (m_Instance == m_DualPersonalityInstance)
+ return theBridge->GetName(m_Instance);
+
+ Q3DStudio::CString theName = theBridge->GetName(m_Instance);
+ theName += " (";
+ theName += theBridge->GetName(m_DualPersonalityInstance);
+ theName += ")";
+
+ return theName;
+}
+
+//==============================================================================
+/**
+ * Query the number of groups to display
+ */
+long CUICDMInspectable::GetGroupCount()
+{
+ // If you have a dual personality inspectable then you may overwrite
+ QT3DS_ASSERT(
+ m_Instance == m_DualPersonalityInstance
+ || m_Core->GetDoc()->GetStudioSystem()->GetClientDataModelBridge()->IsComponentInstance(
+ m_Instance));
+ IMetaData &theMetaData = *m_Core->GetDoc()->GetStudioSystem()->GetActionMetaData();
+ long count = (long)theMetaData.GetGroupCountForInstance(m_Instance);
+ return count;
+}
+
+//==============================================================================
+/**
+ * Return the property group for display
+ */
+CInspectorGroup *CUICDMInspectable::GetGroup(long inIndex)
+{
+ CUICDMInspectorGroup *theGroup =
+ new CUICDMInspectorGroup(m_App, GetGroupName(inIndex).toQString(), *this, inIndex);
+
+ TMetaDataPropertyHandleList theProperties = GetGroupProperties(inIndex);
+
+ size_t thePropertyCount = theProperties.size();
+ for (size_t thePropertyIndex = 0; thePropertyIndex < thePropertyCount; ++thePropertyIndex)
+ theGroup->CreateRow(m_Core->GetDoc(), theProperties[thePropertyIndex]);
+
+ return theGroup;
+}
+
+//==============================================================================
+/**
+ * Return the property handles for display, given the group index
+ */
+TMetaDataPropertyHandleList CUICDMInspectable::GetGroupProperties(long inIndex)
+{
+ TMetaDataPropertyHandleList retval;
+ IMetaData &theMetaData = *m_Core->GetDoc()->GetStudioSystem()->GetActionMetaData();
+ theMetaData.GetMetaDataProperties(GetGroupInstance(inIndex), retval);
+ UICDM::IPropertySystem &thePropertySystem(
+ *m_Core->GetDoc()->GetStudioSystem()->GetPropertySystem());
+ // get name of the current group fofr filtering
+ Option<UICDM::TCharStr> theGroupFilterName =
+ theMetaData.GetGroupFilterNameForInstance(GetGroupInstance(inIndex), inIndex);
+ long theGroupCount = GetGroupCount();
+
+ // end is explicitly required
+ for (size_t idx = 0; idx < retval.size(); ++idx) {
+ if (theMetaData.GetMetaDataPropertyInfo(retval[idx])->m_IsHidden) {
+ retval.erase(retval.begin() + idx);
+ --idx;
+ } else if (theGroupCount > 1 && theGroupFilterName.hasValue()
+ && theMetaData.GetMetaDataPropertyInfo(retval[idx])->m_GroupName
+ != theGroupFilterName) {
+ retval.erase(retval.begin() + idx);
+ --idx;
+ } else {
+ qt3ds::foundation::NVConstDataRef<SPropertyFilterInfo> theFilters(
+ theMetaData.GetMetaDataPropertyFilters(retval[idx]));
+ if (theFilters.size()) {
+ Option<bool> keepProperty;
+ // The tests are done in an ambiguous way. Really, show if equal should take
+ // multiple conditions
+ // as should hide if equal. They do not, so we need to rigorously define exactly
+ // how those two interact.
+ for (QT3DSU32 propIdx = 0, propEnd = theFilters.size(); propIdx < propEnd; ++propIdx) {
+ const SPropertyFilterInfo &theFilter(theFilters[propIdx]);
+
+ QT3DS_ASSERT(theFilter.m_FilterType == PropertyFilterTypes::ShowIfEqual
+ || theFilter.m_FilterType == PropertyFilterTypes::HideIfEqual);
+
+ SValue theValue;
+ thePropertySystem.GetInstancePropertyValue(
+ GetGroupInstance(inIndex), theFilter.m_FilterProperty, theValue);
+ bool resultIfTrue =
+ theFilter.m_FilterType == PropertyFilterTypes::ShowIfEqual ? true : false;
+ if (Equals(theValue.toOldSkool(), theFilter.m_Value.toOldSkool())) {
+ keepProperty = resultIfTrue;
+ break;
+ } else {
+ keepProperty = !resultIfTrue;
+ }
+ }
+ if (keepProperty.hasValue() && *keepProperty == false) {
+ retval.erase(retval.begin() + idx);
+ --idx;
+ }
+ }
+ }
+ }
+ return retval;
+}
+
+//==============================================================================
+/**
+ * Return the Resource String ID for the Group Name, given the group index
+ */
+Q3DStudio::CString CUICDMInspectable::GetGroupName(long inGroupIndex)
+{
+ std::vector<TCharStr> theGroupNames;
+ IMetaData &theMetaData = *m_Core->GetDoc()->GetStudioSystem()->GetActionMetaData();
+ theMetaData.GetGroupNamesForInstance(GetGroupInstance(inGroupIndex), theGroupNames);
+
+ size_t theIndex = inGroupIndex;
+
+ if (theGroupNames.size() > theIndex) {
+ Q3DStudio::CString theName = theGroupNames[inGroupIndex].wide_str();
+ return theName;
+ } else
+ return ::LoadResourceString(IDS_PROPERTIES_BASIC);
+}
+
+//==============================================================================
+/**
+ * Return the Inspectable Instance Handle for the Group, given the group index
+ */
+CUICDMInstanceHandle CUICDMInspectable::GetGroupInstance(long inGroupIndex)
+{
+ Q_UNUSED(inGroupIndex);
+ return m_DualPersonalityInstance;
+}
+
+EStudioObjectType CUICDMInspectable::GetObjectType()
+{
+ IMetaData &theMetaData = *m_Core->GetDoc()->GetStudioSystem()->GetActionMetaData();
+ Option<UICDM::TCharStr> theObjTypeName = theMetaData.GetTypeForInstance(m_Instance);
+ if (theObjTypeName.hasValue()) {
+ ComposerObjectTypes::Enum theType =
+ ComposerObjectTypes::Convert(theObjTypeName->wide_str());
+ switch (theType) {
+ case ComposerObjectTypes::Slide: {
+ CDoc *theDoc = m_Core->GetDoc();
+ CClientDataModelBridge *theBridge =
+ theDoc->GetStudioSystem()->GetClientDataModelBridge();
+ UICDM::CUICDMInstanceHandle theInstance =
+ theBridge->GetOwningComponentInstance(theDoc->GetActiveSlide());
+ Option<TCharStr> theObjTypeName = theMetaData.GetTypeForInstance(theInstance);
+ if (theObjTypeName.hasValue()) {
+ ComposerObjectTypes::Enum theType =
+ ComposerObjectTypes::Convert(theObjTypeName->wide_str());
+ if (theType == ComposerObjectTypes::Scene)
+ return OBJTYPE_SCENE;
+ else
+ return OBJTYPE_COMPONENT;
+ }
+ return OBJTYPE_UNKNOWN;
+ }
+ case ComposerObjectTypes::Scene:
+ return OBJTYPE_SCENE;
+ case ComposerObjectTypes::Layer:
+ return OBJTYPE_LAYER;
+ case ComposerObjectTypes::Behavior:
+ return OBJTYPE_BEHAVIOR;
+ case ComposerObjectTypes::Material:
+ return OBJTYPE_MATERIAL;
+ case ComposerObjectTypes::Camera:
+ return OBJTYPE_CAMERA;
+ case ComposerObjectTypes::Light:
+ return OBJTYPE_LIGHT;
+ case ComposerObjectTypes::Model:
+ return OBJTYPE_MODEL;
+ case ComposerObjectTypes::Group:
+ return OBJTYPE_GROUP;
+ case ComposerObjectTypes::Image:
+ return OBJTYPE_IMAGE;
+ case ComposerObjectTypes::Text:
+ return OBJTYPE_TEXT;
+ case ComposerObjectTypes::Component:
+ return OBJTYPE_COMPONENT;
+ case ComposerObjectTypes::Effect:
+ return OBJTYPE_EFFECT;
+ case ComposerObjectTypes::CustomMaterial:
+ return OBJTYPE_CUSTOMMATERIAL;
+ case ComposerObjectTypes::ReferencedMaterial:
+ return OBJTYPE_REFERENCEDMATERIAL;
+ case ComposerObjectTypes::Path:
+ return OBJTYPE_PATH;
+ case ComposerObjectTypes::SubPath:
+ return OBJTYPE_SUBPATH;
+ case ComposerObjectTypes::PathAnchorPoint:
+ return OBJTYPE_PATHANCHORPOINT;
+ case ComposerObjectTypes::Lightmaps:
+ return OBJTYPE_LIGHTMAPS;
+ }
+ }
+ return OBJTYPE_UNKNOWN;
+}
+
+bool CUICDMInspectable::IsValid() const
+{
+ return m_Core->GetDoc()->GetStudioSystem()->IsInstance(m_Instance)
+ && m_Core->GetDoc()->GetStudioSystem()->IsInstance(m_DualPersonalityInstance);
+}
+
+bool CUICDMInspectable::IsMaster()
+{
+ ISlideSystem *theSlideSystem = m_Core->GetDoc()->GetStudioSystem()->GetSlideSystem();
+ UICDM::CUICDMSlideHandle theSlideHandle = theSlideSystem->GetAssociatedSlide(m_Instance);
+ if (theSlideHandle.Valid())
+ return theSlideSystem->IsMasterSlide(theSlideHandle);
+ // Slide handle may not be valid if we are selecting the Scene or if we are inside Component and
+ // we select the Component root.
+ return false;
+}
+
+// std::wstring CUICDMInspectable::GetTypeString( ) const
+//{
+// std::wstring theReturn(L"");
+// try
+// {
+// IPropertySystem* thePropertySystem = m_Core->GetDoc( )->GetStudioSystem(
+//)->GetPropertySystem( );
+// CUICDMPropertyHandle theProperty =
+//thePropertySystem->GetAggregateInstancePropertyByName( m_Instance, L"type" );
+// SValue theTypeValue;
+// if ( theProperty && thePropertySystem->GetInstancePropertyValue( m_Instance,
+//theProperty, theTypeValue ) )
+// {
+// theReturn.assign( UICDM::get<TDataStrPtr>( theTypeValue )->GetData() );
+// }
+// }
+// catch( ... )
+// {
+// theReturn.assign(L"");
+// }
+//
+// return theReturn;
+//}
diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.h b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.h
new file mode 100644
index 00000000..f497d4f9
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_UICDM_INSPECTABLE_H
+#define INCLUDED_UICDM_INSPECTABLE_H 1
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "InspectableBase.h"
+#include "UICDMHandles.h"
+#include "StudioApp.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+
+//==============================================================================
+/**
+* For inspecting data model instances
+*/
+class CUICDMInspectable : public CInspectableBase
+{
+protected: // Fields
+ UICDM::CUICDMInstanceHandle m_Instance;
+ UICDM::CUICDMInstanceHandle m_DualPersonalityInstance;
+ CStudioApp &m_App;
+
+public: // Constructor
+ CUICDMInspectable(CStudioApp &inApp, CCore *inCore, UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMInstanceHandle inDualPersonalityInstance = 0);
+
+public: // CInspectableBase
+ Q3DStudio::CString GetName() override;
+ long GetGroupCount() override;
+ CInspectorGroup *GetGroup(long) override;
+ EStudioObjectType GetObjectType() override;
+ // virtual std::wstring GetTypeString( ) const;
+ bool IsValid() const override;
+ bool IsMaster() override;
+ virtual UICDM::TMetaDataPropertyHandleList GetGroupProperties(long inGroupIndex);
+ virtual UICDM::CUICDMInstanceHandle GetGroupInstance(long inGroupIndex);
+
+protected:
+ virtual Q3DStudio::CString GetGroupName(long inGroupIndex);
+};
+
+#endif
diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.cpp b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.cpp
new file mode 100644
index 00000000..86f62847
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "UICDMInspectorGroup.h"
+#include "UICDMInspectorRow.h"
+#include "UICDMInspectable.h"
+#include "StudioApp.h"
+#include "Core.h"
+#include "UICDMMetaData.h"
+#include "Doc.h"
+#include "UICDMStudioSystem.h"
+
+//==============================================================================
+/**
+ * Constructor
+ */
+CUICDMInspectorGroup::CUICDMInspectorGroup(CStudioApp &inApp, const QString &inName,
+ CUICDMInspectable &inInspectable, long inIndex)
+ : CEasyInspectorGroup(inName)
+ , m_App(inApp)
+ , m_Inspectable(inInspectable)
+ , m_Index(inIndex)
+{
+}
+
+//==============================================================================
+/**
+ * clean up
+ */
+CUICDMInspectorGroup::~CUICDMInspectorGroup()
+{
+ std::vector<Q3DStudio::CUICDMInspectorRow *>::iterator theIterator =
+ m_UICDMInspectorRows.begin();
+ for (; theIterator != m_UICDMInspectorRows.end(); ++theIterator)
+ delete (*theIterator);
+}
+
+//==============================================================================
+/**
+ * Method to create a new InspectorRowBase.
+ */
+void CUICDMInspectorGroup::CreateRow(CDoc *inDoc, UICDM::CUICDMMetaDataPropertyHandle inProperty)
+{
+ Q3DStudio::CUICDMInspectorRow *theUICDMRow =
+ new Q3DStudio::CUICDMInspectorRow(inDoc, inProperty);
+ m_UICDMInspectorRows.push_back(
+ theUICDMRow); // this CUICDMInspectorRow is now owned by this class
+
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.h b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.h
new file mode 100644
index 00000000..3d811364
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_UICDM_INSPECTORGROUP_H
+#define INCLUDED_UICDM_INSPECTORGROUP_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "EasyInspectorGroup.h"
+#include "UICDMHandles.h"
+#include "StudioApp.h"
+
+class CDoc;
+namespace Q3DStudio {
+class CUICDMInspectorRow;
+};
+
+class CUICDMInspectable;
+
+//==============================================================================
+/**
+ *
+ */
+class CUICDMInspectorGroup: public CEasyInspectorGroup
+{
+protected: // Members
+ CStudioApp &m_App;
+ std::vector<Q3DStudio::CUICDMInspectorRow *> m_UICDMInspectorRows;
+ CUICDMInspectable &m_Inspectable;
+ long m_Index;
+
+public: // Construction
+ CUICDMInspectorGroup(CStudioApp &inApp, const QString &inName,
+ CUICDMInspectable &inInspectable, long inIndex);
+ ~CUICDMInspectorGroup();
+
+ const std::vector<Q3DStudio::CUICDMInspectorRow *> &GetRows() const
+ {
+ return m_UICDMInspectorRows;
+ }
+
+public: // Use
+ void CreateRow(CDoc *inDoc, UICDM::CUICDMMetaDataPropertyHandle inProperty);
+};
+
+#endif
diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.cpp b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.cpp
new file mode 100644
index 00000000..d92ef10a
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "UICDMInspectorRow.h"
+#include "UICDMMetaData.h"
+#include "Doc.h"
+#include "StudioApp.h"
+#include "UICDMSlides.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMAnimation.h"
+#include "UICDMSignals.h"
+#include "CmdDataModelDeanimate.h"
+#include "UICDMDataCore.h"
+#include "Core.h"
+#include "ClientDataModelBridge.h"
+#include "IDocumentEditor.h"
+
+//==============================================================================
+// Namespace
+//==============================================================================
+using namespace UICDM;
+namespace Q3DStudio {
+
+//==============================================================================
+/**
+ * Constructor
+ */
+CUICDMInspectorRow::CUICDMInspectorRow(CDoc *inDoc,
+ CUICDMMetaDataPropertyHandle inProperty)
+ : m_MetaProperty(inProperty)
+{
+ IMetaData *theMetaData = inDoc->GetStudioSystem()->GetActionMetaData();
+ SMetaDataPropertyInfo theInfo(theMetaData->GetMetaDataPropertyInfo(inProperty));
+ m_MetaDataPropertyInfo = theInfo;
+}
+
+//==============================================================================
+/**
+ * Destructor
+ */
+CUICDMInspectorRow::~CUICDMInspectorRow()
+{
+}
+
+} // namespace Q3DStudio
diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.h b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.h
new file mode 100644
index 00000000..ff2155bc
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "UICDMHandles.h"
+#include "IEasyInspectorRowListener.h"
+#include "IDataDrivenChangeListener.h"
+#include "DispatchListeners.h"
+#include "UICDMMetaDataTypes.h"
+#include "CmdBatch.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CDoc;
+class CEasyInspectorRow;
+
+// UICDM
+namespace UICDM {
+class ISignalConnection;
+}
+
+class CGenericEdit;
+//==============================================================================
+// Namespace
+//==============================================================================
+namespace Q3DStudio {
+
+//==============================================================================
+/**
+ * This is a binding between a DataModelInspectable and an EasyInspectorRow
+ */
+class CUICDMInspectorRow
+{
+ //==============================================================================
+ // Members
+ //==============================================================================
+protected:
+ UICDM::CUICDMMetaDataPropertyHandle m_MetaProperty;
+ UICDM::SMetaDataPropertyInfo m_MetaDataPropertyInfo;
+
+ //==============================================================================
+ // Methods
+ //==============================================================================
+public: // Construction
+ CUICDMInspectorRow(CDoc *inDoc, UICDM::CUICDMMetaDataPropertyHandle inProperty);
+ virtual ~CUICDMInspectorRow();
+
+private: // Disabled parameterless construction
+ CUICDMInspectorRow();
+
+public: // Use
+ UICDM::CUICDMMetaDataPropertyHandle GetMetaDataProperty() const
+ {
+ return m_MetaProperty;
+ }
+ const UICDM::SMetaDataPropertyInfo &GetMetaDataPropertyInfo() const
+ {
+ return m_MetaDataPropertyInfo;
+ }
+};
+
+} // namespace Q3DStudio
diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.cpp b/src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.cpp
new file mode 100644
index 00000000..70b204e5
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.cpp
@@ -0,0 +1,226 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "stdafx.h"
+#include "UICDMMaterialInspectable.h"
+#include "UICDMInspectorGroup.h"
+#include "UICDMInspectorRow.h"
+#include "Core.h"
+#include "IDocumentEditor.h"
+#include "GenericComboDropDown.h"
+#include "UICDMHandles.h"
+#include "Doc.h"
+#include "GenericFunctor.h"
+#include "StudioApp.h"
+#include "UICDMStudioSystem.h"
+#include "ClientDataModelBridge.h"
+#include "IDocumentReader.h"
+#include "Dispatch.h"
+#include "IDirectoryWatchingSystem.h"
+#include "UICDMSignals.h"
+#include "UICString.h"
+
+using namespace UICDM;
+
+struct SMaterialTypeDropDown : public CGenericComboDropDown
+{
+ struct SMaterialEntry
+ {
+ Q3DStudio::CString m_Name;
+ Q3DStudio::CString m_RelativePath;
+ bool operator<(const SMaterialEntry &inOther) const { return m_Name < inOther.m_Name; }
+ };
+ CUICDMInstanceHandle m_Instance;
+ Q3DStudio::CAutoMemPtr<CGenericEditCommitListener> m_CommitListener;
+ vector<SMaterialEntry> m_Materials;
+ CDoc &m_Doc;
+ TSignalConnectionPtr m_FileListPtr;
+
+ SMaterialTypeDropDown(CDoc &inDoc, CUICDMInstanceHandle inInstance)
+ : m_Instance(inInstance)
+ , m_Doc(inDoc)
+ {
+ using Q3DStudio::CString;
+ using Q3DStudio::CFilePath;
+ m_CommitListener =
+ CREATE_LISTENER(CGenericEditCommitListener, SMaterialTypeDropDown, OnDataCommit);
+ AddCommitListener(m_CommitListener);
+ m_FileListPtr = m_Doc.GetDirectoryWatchingSystem()->AddDirectory(
+ m_Doc.GetDocumentDirectory().toQString(),
+ std::bind(&SMaterialTypeDropDown::OnFilesChanged, this, std::placeholders::_1));
+ }
+
+ vector<SMaterialEntry>::iterator GetMaterialEntry(const Q3DStudio::CString &inRelativePath)
+ {
+ for (size_t idx = 0, end = m_Materials.size(); idx < end; ++idx)
+ if (m_Materials[idx].m_RelativePath == inRelativePath)
+ return m_Materials.begin() + idx;
+ return m_Materials.end();
+ }
+
+ vector<SMaterialEntry>::iterator
+ GetOrCreateMaterialEntry(const Q3DStudio::CString &inRelativePath)
+ {
+ vector<SMaterialEntry>::iterator retval = GetMaterialEntry(inRelativePath);
+ if (retval == m_Materials.end()) {
+ m_Materials.push_back(SMaterialEntry());
+ m_Materials.back().m_RelativePath = inRelativePath;
+ return m_Materials.begin() + m_Materials.size() - 1;
+ } else
+ return retval;
+ }
+
+ void OnFilesChanged(const Q3DStudio::TFileModificationList &inFileModificationList)
+ {
+ for (size_t idx = 0, end = inFileModificationList.size(); idx < end; ++idx) {
+ const Q3DStudio::SFileModificationRecord &theRecord = inFileModificationList[idx];
+ Q3DStudio::CFilePath relativePath(Q3DStudio::CFilePath::GetRelativePathFromBase(
+ m_Doc.GetDocumentDirectory(), theRecord.m_File));
+ Q3DStudio::CString extension = relativePath.GetExtension();
+ if (extension.CompareNoCase("material")) {
+ switch (theRecord.m_ModificationType) {
+ case Q3DStudio::FileModificationType::Created:
+ case Q3DStudio::FileModificationType::Modified: {
+ SMaterialEntry &theEntry =
+ *GetOrCreateMaterialEntry(Q3DStudio::CString(relativePath));
+ theEntry.m_Name =
+ m_Doc.GetDocumentReader().GetCustomMaterialName(theRecord.m_File);
+ } break;
+ case Q3DStudio::FileModificationType::Destroyed: {
+ vector<SMaterialEntry>::iterator theEntry = GetMaterialEntry(relativePath);
+ if (theEntry != m_Materials.end())
+ m_Materials.erase(theEntry);
+ } break;
+
+ default: // don't care.
+ break;
+ }
+ }
+ }
+
+ std::sort(m_Materials.begin(), m_Materials.end());
+
+ RefreshAllItems();
+ }
+
+ void RefreshAllItems()
+ {
+ RemoveAllItems();
+ AddItem("Standard Material");
+ AddItem("Referenced Material");
+ CClientDataModelBridge *theBridge = m_Doc.GetStudioSystem()->GetClientDataModelBridge();
+ long selectIdx = 0;
+ EStudioObjectType theType = theBridge->GetObjectType(m_Instance);
+
+ if (theType == OBJTYPE_REFERENCEDMATERIAL)
+ selectIdx = 1;
+
+ Q3DStudio::CString sourcePath = theBridge->GetSourcePath(m_Instance);
+
+ for (size_t matIdx = 0, end = m_Materials.size(); matIdx < end; ++matIdx) {
+ AddItem(m_Materials[matIdx].m_Name);
+ if (m_Materials[matIdx].m_RelativePath.Compare(sourcePath))
+ selectIdx = (long)matIdx + 2;
+ }
+
+ SelectItem(selectIdx, false);
+ }
+
+ // Note that the this object is probably deleted when this happens or will be during its
+ // execution.
+ static void DoChangeObjectType(CDoc *inDoc, const Q3DStudio::CString &inNewType,
+ CUICDMInstanceHandle instance)
+ {
+ using namespace Q3DStudio;
+ SCOPED_DOCUMENT_EDITOR(*inDoc, QObject::tr("Set Property"))->SetMaterialType(instance, inNewType);
+ }
+
+ void OnDataCommit()
+ {
+ using Q3DStudio::CString;
+ size_t item = this->GetSelectedItem();
+ if (item >= 0) {
+ CString selectedType = this->GetItemText(this->GetSelectedItem());
+ if (item > 1) {
+ size_t matIdx = item - 2;
+ if (matIdx < m_Materials.size())
+ selectedType = m_Materials[matIdx].m_RelativePath;
+ }
+ // Fire a command to do this later because we will get screwed if we don't as we will be
+ // deleted
+ // during this process.
+ g_StudioApp.GetCore()->GetDispatch()->FireOnAsynchronousCommand(
+ std::bind(&DoChangeObjectType, &m_Doc, selectedType, m_Instance));
+ }
+ }
+};
+
+UICDMMaterialInspectorGroup::UICDMMaterialInspectorGroup(
+ CStudioApp &inApp,
+ const Q3DStudio::CString &inName,
+ CUICDMInspectable &inInspectable,
+ long inIndex)
+ : CUICDMInspectorGroup(inApp, inName.toQString(), inInspectable, inIndex)
+{
+}
+
+struct SUICDMMaterialInspectorGroup : public UICDMMaterialInspectorGroup
+{
+ SUICDMMaterialInspectorGroup(CStudioApp &inApp, const Q3DStudio::CString &inName,
+ CUICDMInspectable &inInspectable, long inIndex)
+ : UICDMMaterialInspectorGroup(inApp, inName, inInspectable, inIndex)
+ {
+ Q3DStudio::CString theMaterialGroupName = L"Material";
+ m_isMaterialGroup = (inName == theMaterialGroupName);
+ }
+
+ bool isMaterialGroup() const override
+ {
+ return m_isMaterialGroup;
+ }
+
+private:
+ bool m_isMaterialGroup;
+};
+
+CInspectorGroup *CUICDMMaterialInspectable::GetGroup(long inIndex)
+{
+ Q3DStudio::CString theGroupName = GetGroupName(inIndex);
+ Q3DStudio::CString theMaterialGroupName = L"Material";
+
+ CUICDMInspectorGroup *theGroup =
+ new SUICDMMaterialInspectorGroup(m_App, theGroupName, *this, inIndex);
+
+ TMetaDataPropertyHandleList theProperties = GetGroupProperties(inIndex);
+ size_t thePropertyCount = theProperties.size();
+
+ for (size_t thePropertyIndex = 0; thePropertyIndex < thePropertyCount; ++thePropertyIndex)
+ theGroup->CreateRow(m_Core->GetDoc(), theProperties[thePropertyIndex]);
+
+ return theGroup;
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.h b/src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.h
new file mode 100644
index 00000000..20bb4365
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_UICDM_MATERIAL_INSPECTABLE_H
+#define INCLUDED_UICDM_MATERIAL_INSPECTABLE_H 1
+
+#include "UICDMInspectable.h"
+#include "UICDMInspectorGroup.h"
+
+class UICDMMaterialInspectorGroup : public CUICDMInspectorGroup
+{
+public:
+ UICDMMaterialInspectorGroup(CStudioApp &inApp, const Q3DStudio::CString &inName,
+ CUICDMInspectable &inInspectable, long inIndex);
+
+ virtual bool isMaterialGroup() const = 0;
+};
+
+class CUICDMMaterialInspectable : public CUICDMInspectable
+{
+public:
+ CUICDMMaterialInspectable(CStudioApp &inApp, CCore *inCore,
+ UICDM::CUICDMInstanceHandle inInstance)
+ : CUICDMInspectable(inApp, inCore, inInstance)
+ {
+ }
+
+ CInspectorGroup *GetGroup(long) override;
+};
+
+#endif
diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.cpp b/src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.cpp
new file mode 100644
index 00000000..85f9b60c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+#include "Strings.h"
+#include "StringLoader.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "UICDMSceneInspectable.h"
+#include "Core.h"
+#include "Doc.h"
+#include "UICDMStudioSystem.h"
+
+CUICDMSceneInspectable::CUICDMSceneInspectable(
+ CStudioApp &inApp, CCore *inCore, UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMInstanceHandle inCurrentActiveSlideInstance)
+ : CUICDMInspectable(inApp, inCore, inInstance)
+ , m_CurrentActiveSlideInstance(inCurrentActiveSlideInstance)
+{
+}
+
+bool CUICDMSceneInspectable::IsValid() const
+{
+ return CUICDMInspectable::IsValid()
+ && m_Core->GetDoc()->GetStudioSystem()->IsInstance(m_CurrentActiveSlideInstance);
+}
+
+long CUICDMSceneInspectable::GetGroupCount()
+{
+ return 2; // hard-coded to basic and shared
+}
+
+//==============================================================================
+/**
+ * Return the Resource String ID for the Group Name, given the group index
+ */
+Q3DStudio::CString CUICDMSceneInspectable::GetGroupName(long inGroupIndex)
+{
+ return (inGroupIndex == 0) ? ::LoadResourceString(IDS_PROPERTIES_BASIC)
+ : ::LoadResourceString(IDS_PROPERTIES_SHARED);
+}
+
+UICDM::CUICDMInstanceHandle CUICDMSceneInspectable::GetGroupInstance(long inGroupIndex)
+{
+ return (inGroupIndex == 0) ? m_CurrentActiveSlideInstance : m_Instance;
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.h b/src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.h
new file mode 100644
index 00000000..f30693b9
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_UICDM_SCENE_INSPECTABLE_H
+#define INCLUDED_UICDM_SCENE_INSPECTABLE_H 1
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "UICDMInspectable.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+
+//==============================================================================
+/**
+* For inspecting scene data model instances
+*/
+class CUICDMSceneInspectable : public CUICDMInspectable
+{
+public:
+ CUICDMSceneInspectable(CStudioApp &inApp, CCore *inCore, UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMInstanceHandle inCurrentActiveSlideInstance);
+
+ bool IsValid() const override;
+ // CUICDMInspectable
+ long GetGroupCount() override;
+
+protected:
+ inline Q3DStudio::CString GetGroupName(long inGroupIndex) override;
+ inline UICDM::CUICDMInstanceHandle GetGroupInstance(long inGroupIndex) override;
+
+ UICDM::CUICDMInstanceHandle m_CurrentActiveSlideInstance;
+};
+
+#endif
diff --git a/src/Authoring/Studio/Palettes/Master/MasterControl.cpp b/src/Authoring/Studio/Palettes/Master/MasterControl.cpp
new file mode 100644
index 00000000..922b6d02
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Master/MasterControl.cpp
@@ -0,0 +1,295 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "MasterControl.h"
+#include "Renderer.h"
+#include "StudioPreferences.h"
+#include "StudioApp.h"
+#include "Doc.h"
+#include "InspectorControl.h"
+#include "ActionControl.h"
+#include "GenericTabControl.h"
+
+//===============================================================================
+/**
+ * Constructor
+ * @param inStudioApp
+ */
+CMasterControl::CMasterControl(IMasterControlProvider *inProvider)
+ : m_Provider(inProvider)
+ , m_TabMenu(nullptr)
+ , m_RenderDevice(nullptr)
+{
+ // Create the tab control
+ m_TabControl = new CGenericTabControl();
+ AddChild(m_TabControl);
+ m_TabControl->SigTabSelected.connect(std::bind(&CMasterControl::OnTabSelected, this,
+ std::placeholders::_1, std::placeholders::_2));
+
+ // Add the drop-down menu
+ m_MenuButton = new CProceduralButton<CButtonControl>();
+ m_MenuButton->SetUpImage("Storage-Dropdown-Normal.png");
+ m_MenuButton->SetDisabledImage("Tab-Menu-Disabled.png");
+ m_MenuButton->SetAbsoluteSize(m_MenuButton->GetImageSize());
+ m_MenuButton->SetFillColorUp(CStudioPreferences::GetDarkBaseColor());
+ m_MenuButton->SetFillColorDown(CStudioPreferences::GetDarkBaseColor());
+ m_MenuButton->SetFillColorOver(CStudioPreferences::GetDarkBaseColor());
+ m_MenuButton->SetFillColorDisabled(CStudioPreferences::GetDarkBaseColor());
+ m_MenuButton->SetFillStyleAll(CProceduralButton<CButtonControl>::EFILLSTYLE_FLOOD);
+ CProceduralButton<CButtonControl>::SBorderOptions theBorders(false, false, false, false);
+ m_MenuButton->SetBorderVisibilityAll(theBorders);
+ m_MenuButton->SigButtonDown.connect(std::bind(&CMasterControl::OnMenuButtonDown, this,
+ std::placeholders::_1));
+ m_TabControl->SetTabBarSibling(m_MenuButton);
+}
+
+//===============================================================================
+/**
+ * Destructor
+ */
+CMasterControl::~CMasterControl()
+{
+ RemoveChild(m_TabControl);
+}
+
+//===============================================================================
+/**
+ * Display the context menu for this control
+ */
+void CMasterControl::DisplayContextMenu(CPt inPosition)
+{
+ ASSERT(m_Provider != nullptr);
+ m_Provider->OnContextMenu(this, inPosition, m_TabMenu);
+}
+
+//=============================================================================
+/**
+ * Callback when the menu button is selected
+ */
+void CMasterControl::AddControl(const Q3DStudio::CString &inName, long inType, CControl *inControl)
+{
+ inControl->SetName(inName);
+ m_ControlList.insert(std::make_pair(inControl, inType));
+ m_TabControl->AddTab(inName, inControl);
+}
+
+//=============================================================================
+/**
+ * Callback when the menu button is selected
+ */
+void CMasterControl::RemoveControl(CControl *inControl)
+{
+ TControlMap::iterator theIterator = m_ControlList.begin();
+ TControlMap::iterator theEndIterator = m_ControlList.end();
+ for (; theIterator != theEndIterator; ++theIterator) {
+ if (inControl == theIterator->first) {
+ m_ControlList.erase(theIterator);
+ break;
+ }
+ }
+
+ if (m_ControlList.size())
+ m_TabControl->SelectTab((long)0);
+
+ m_TabControl->RemoveTab(inControl);
+}
+
+//=============================================================================
+/**
+ * Callback when the menu button is selected
+ */
+void CMasterControl::SelectControl(long inIndex)
+{
+ m_TabControl->SelectTab(inIndex);
+}
+
+//=============================================================================
+/**
+ * Callback when the menu button is selected
+ */
+void CMasterControl::SelectControl(CControl *inControl)
+{
+ m_TabControl->SelectTab(inControl);
+}
+
+//=============================================================================
+/**
+ * Return the number of controls
+ */
+long CMasterControl::GetControlCount()
+{
+ return m_TabControl->GetTabCount();
+}
+
+//=============================================================================
+/**
+ * Return the control for the specified type
+ */
+CControl *CMasterControl::FindControl(long inType)
+{
+ CControl *theControl = nullptr;
+ TControlMap::iterator theIterator = m_ControlList.begin();
+ TControlMap::iterator theEndIterator = m_ControlList.end();
+ for (; theIterator != theEndIterator; ++theIterator) {
+ if (inType == theIterator->second) {
+ theControl = theIterator->first;
+ break;
+ }
+ }
+ return theControl;
+}
+
+//=============================================================================
+/**
+ * Return the active control
+ */
+CControl *CMasterControl::GetActiveControl()
+{
+ return m_TabControl->GetSelectedTab();
+}
+
+//=============================================================================
+/**
+ * Return the index of the active tab
+ */
+long CMasterControl::GetActiveIndex()
+{
+ return m_TabControl->GetSelectedTabIndex();
+}
+
+//=============================================================================
+/**
+ * Return the active type
+ */
+long CMasterControl::GetActiveType()
+{
+ return m_ControlList[GetActiveControl()];
+}
+
+//=============================================================================
+/**
+ * Callback when the menu button is selected
+ */
+void CMasterControl::OnMenuButtonDown(CControl *)
+{
+ CPt thePosition(GetSize().x, GetPosition().y + m_MenuButton->GetSize().y);
+ DisplayContextMenu(thePosition);
+}
+
+//=============================================================================
+/**
+ * Callback when a tab changes
+ */
+void CMasterControl::OnTabSelected(CControl *, CControl *inNewControl)
+{
+ // Notify the provider that the selection changed
+ m_Provider->OnControlSelected(this, inNewControl, m_ControlList[inNewControl]);
+
+ // Set the enabled state of the menu item
+ m_MenuButton->SetEnabled((m_TabControl->GetTabCount() != 0));
+}
+
+//==============================================================================
+// CControl
+//==============================================================================
+
+Q3DStudio::CString CMasterControl::GetName()
+{
+ CControl *theActiveControl = GetActiveControl();
+ if (theActiveControl)
+ return theActiveControl->GetName();
+ return L"< Empty >";
+}
+
+//=============================================================================
+/**
+ * Fills the whole control with the base (gray) color, then other controls will
+ * draw on top of that.
+ * @param inRenderer renderer to draw to
+ */
+void CMasterControl::Draw(CRenderer *inRenderer)
+{
+ inRenderer->FillSolidRect(GetSize(), CStudioPreferences::GetDarkBaseColor());
+}
+
+//=============================================================================
+/**
+ * Set the size of the tree control
+ */
+void CMasterControl::SetSize(CPt inSize)
+{
+ CControl::SetSize(inSize);
+ m_TabControl->SetSize(inSize);
+}
+
+//=============================================================================
+/**
+ * Check to see if the right mouse down occurred on the tab control
+ */
+bool CMasterControl::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (m_TabControl->IsInTabBar(inPoint)) {
+ DisplayContextMenu(inPoint);
+ return true;
+ }
+
+ return CControl::OnMouseRDown(inPoint, inFlags); // not handled
+}
+
+//=============================================================================
+/**
+ * Return the window handle to the master view
+ */
+UICRenderDevice CMasterControl::GetPlatformDevice()
+{
+ return m_RenderDevice;
+}
+
+//=============================================================================
+/**
+ * Overriden from CControl. Since this control's parent is the CWnd, ensure
+ * that it gets the keyboard focus if this function is called.
+ * @see CControl::SetFocus
+ */
+void CMasterControl::GrabFocus(CControl *inControl)
+{
+ if (m_RenderDevice) {
+ ::SetFocus(m_RenderDevice);
+ }
+
+ CControl::GrabFocus(inControl);
+}
diff --git a/src/Authoring/Studio/Palettes/Master/MasterControl.h b/src/Authoring/Studio/Palettes/Master/MasterControl.h
new file mode 100644
index 00000000..40a347a4
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Master/MasterControl.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 1999-2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_MASTER_CONTROL_H
+#define INCLUDED_MASTER_CONTROL_H 1
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "Control.h"
+#include "ProceduralButton.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CStudioApp;
+class CRenderer;
+class CAssetControl;
+class CGenericTabControl;
+class CMasterControl;
+
+//==============================================================================
+/**
+ * @class IMasterControlProvider
+ */
+class IMasterControlProvider
+{
+public:
+ virtual void OnControlRemoved(CMasterControl *inControl) = 0;
+ virtual void OnContextMenu(CMasterControl *inControl, const CPt &inPosition,
+ CContextMenu *inMyMenu) = 0;
+ virtual void OnControlSelected(CMasterControl *inMaster, CControl *inControl, long inType) = 0;
+};
+
+//==============================================================================
+/**
+ * @class CMasterControl
+ * @brief Class wrapping up all controls that appear in the Inspector Palette.
+ */
+class CMasterControl : public CControl
+{
+protected:
+ typedef std::map<CControl *, long> TControlMap;
+
+public:
+ CMasterControl(IMasterControlProvider *inProvider);
+ ~CMasterControl();
+
+ void SetRenderDevice(UICRenderDevice inDevice) { m_RenderDevice = inDevice; }
+
+ void AddControl(const Q3DStudio::CString &inName, long inType, CControl *inControl);
+ void RemoveControl(CControl *inControl);
+ void SelectControl(long inIndex);
+ void SelectControl(CControl *inControl);
+ long GetControlCount();
+ CControl *FindControl(long inType);
+
+ long GetActiveType();
+ long GetActiveIndex();
+ CControl *GetActiveControl();
+
+ // CControl
+ virtual Q3DStudio::CString GetName();
+ void Draw(CRenderer *inRenderer) override;
+ void SetSize(CPt inSize) override;
+ bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ UICRenderDevice GetPlatformDevice() override;
+ void GrabFocus(CControl *inControl) override;
+
+protected:
+ void DisplayContextMenu(CPt inPosition);
+ void OnTabSelected(CControl *inOldControl, CControl *inNewControl);
+ void OnMenuButtonDown(CControl *);
+
+protected:
+ IMasterControlProvider *m_Provider; ///<
+ CContextMenu *m_TabMenu; ///<
+ Q3DStudio::CAutoMemPtr<CGenericTabControl> m_TabControl; ///<
+ Q3DStudio::CAutoMemPtr<CProceduralButton<CButtonControl>>
+ m_MenuButton; ///< menu button for the storage palette
+ TControlMap m_ControlList; ///< the list of controls to display
+ UICRenderDevice m_RenderDevice; ///<
+};
+
+#endif //#ifndef INCLUDED_MASTER_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/Master/MasterView.cpp b/src/Authoring/Studio/Palettes/Master/MasterView.cpp
new file mode 100644
index 00000000..8a4a9bd5
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Master/MasterView.cpp
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "MasterView.h"
+#include "WndControl.h"
+#include "StudioApp.h"
+#include "MasterControl.h"
+#include "IDragable.h"
+
+//==============================================================================
+// Message Maps, etc.
+//==============================================================================
+IMPLEMENT_DYNCREATE(CMasterView, CView)
+
+BEGIN_MESSAGE_MAP(CMasterView, CView)
+//{{AFX_MSG_MAP(CMasterView)
+ON_WM_SIZE()
+ON_WM_ERASEBKGND()
+ON_WM_MOUSEACTIVATE()
+//}}AFX_MSG_MAP
+ON_MESSAGE(WM_STUDIO_INITIALIZE_PALETTES, OnInitializePalettes)
+END_MESSAGE_MAP()
+
+int CMasterView::OnMouseActivate(CWnd *, UINT, UINT)
+{
+ return MA_NOACTIVATE;
+}
+
+//=============================================================================
+/**
+ * Constructor: Protected because the view is always created dynamically.
+ * You must call Initialize() before trying to use this class.
+ */
+CMasterView::CMasterView()
+ : m_WndControl(nullptr)
+ , m_Provider(nullptr)
+{
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CMasterView::~CMasterView()
+{
+ m_WndControl->DestroyWindow();
+ m_WndControl = nullptr;
+
+ m_MasterControl = nullptr;
+}
+
+//==============================================================================
+/**
+ * Handles the WM_INITIALUPDATE message. Responsible for preparing the view
+ * before it is displayed for the first time.
+ */
+LRESULT CMasterView::OnInitializePalettes(WPARAM inwParam, LPARAM)
+{
+ if (!m_WndControl) {
+ CStudioApp *theStudioApp = reinterpret_cast<CStudioApp *>(inwParam);
+
+ m_MasterControl = new CMasterControl(m_Provider);
+ m_WndControl = new CWndControl(m_MasterControl);
+
+ m_WndControl->RegiserForDnd(this);
+
+ m_WndControl->AddMainFlavor(EUIC_FLAVOR_LISTBOX);
+ m_WndControl->AddMainFlavor(EUIC_FLAVOR_FILE);
+ m_WndControl->AddMainFlavor(EUIC_FLAVOR_ASSET_UICFILE);
+ m_WndControl->AddMainFlavor(EUIC_FLAVOR_ASSET_LIB);
+ m_WndControl->AddMainFlavor(EUIC_FLAVOR_ASSET_TL);
+ m_WndControl->AddMainFlavor(EUIC_FLAVOR_BASIC_OBJECTS);
+
+ CRect theClientRect;
+ GetClientRect(&theClientRect);
+
+ m_WndControl->CreateEx(
+ WS_EX_NOPARENTNOTIFY, AfxRegisterWndClass(CS_DBLCLKS, LoadCursor(nullptr, IDC_ARROW),
+ (HBRUSH)GetStockObject(BLACK_BRUSH)),
+ L"MasterViewWndCtrl", WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
+ theClientRect, this, 100);
+ m_MasterControl->SetRenderDevice(m_WndControl->GetSafeHwnd());
+ }
+
+ return 0;
+}
+
+//=============================================================================
+/**
+ * Required by base class but does nothing since all drawing is handled by the
+ * child control.
+ */
+void CMasterView::OnDraw(CDC *inDC)
+{
+ Q_UNUSED(inDC);
+}
+
+//=============================================================================
+/**
+ * Resizes the wnd control to fill the whole view.
+ */
+void CMasterView::OnSize(UINT inType, int inX, int inY)
+{
+ CView::OnSize(inType, inX, inY);
+ if (::IsWindow(m_WndControl->GetSafeHwnd()))
+ m_WndControl->MoveWindow(0, 0, inX, inY);
+}
+
+//==============================================================================
+/**
+ * Tells the Inspector to erase before redrawing. Overridden because we erasing
+ * before each draw produces a flashing effect.
+ * @param inDC the DC to erase on.
+ * @return FALSE.
+ */
+BOOL CMasterView::OnEraseBkgnd(CDC *inDC)
+{
+ Q_UNUSED(inDC);
+ return FALSE;
+}
diff --git a/src/Authoring/Studio/Palettes/Master/MasterView.h b/src/Authoring/Studio/Palettes/Master/MasterView.h
new file mode 100644
index 00000000..008d748f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Master/MasterView.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_MASTER_VIEW_H
+#define INCLUDED_MASTER_VIEW_H 1
+
+#pragma once
+//==============================================================================
+// Includes
+//==============================================================================
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CStudioApp;
+class CWndControl;
+class CMasterControl;
+class IMasterControlProvider;
+
+//=============================================================================
+/**
+ * Windows view encapsulating the inspector palette.
+ */
+class CMasterView : public CView
+{
+protected:
+ CMasterView();
+ DECLARE_DYNCREATE(CMasterView)
+ virtual ~CMasterView();
+
+ afx_msg void OnSize(UINT inType, int inX, int inY);
+ afx_msg BOOL OnEraseBkgnd(CDC *inDC);
+ afx_msg int OnMouseActivate(CWnd *pDesktopWnd, UINT nHitTest, UINT message);
+ DECLARE_MESSAGE_MAP()
+
+public:
+ virtual void OnDraw(CDC *inDC);
+ virtual LRESULT OnInitializePalettes(WPARAM inwParam, LPARAM inlParam);
+
+ void SetProvider(IMasterControlProvider *inProvider) { m_Provider = inProvider; }
+ CMasterControl *GetMasterControl() const { return m_MasterControl; }
+
+protected:
+ IMasterControlProvider *m_Provider; ///<
+ CWndControl *m_WndControl; ///<
+ Q3DStudio::CAutoMemPtr<CMasterControl> m_MasterControl; ///<
+};
+
+#endif // INCLUDED_MASTER_VIEW_H
diff --git a/src/Authoring/Studio/Palettes/Progress/ProgressCallback.h b/src/Authoring/Studio/Palettes/Progress/ProgressCallback.h
new file mode 100644
index 00000000..eeff02b8
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Progress/ProgressCallback.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_PROGRESS_CALLBACK_H
+#define INCLUDED_PROGRESS_CALLBACK_H 1
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+
+//==============================================================================
+// Forwards
+//==============================================================================
+
+//==============================================================================
+/**
+ * Callback interface to progress update window
+ */
+class IProgressCallback
+{
+public:
+ virtual void SetProgress(long inPercent) = 0;
+
+ virtual void SetActionText(const Q3DStudio::CString &inText) = 0;
+};
+
+#endif // INCLUDED_PROGRESS_CALLBACK_H \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Progress/ProgressControl.cpp b/src/Authoring/Studio/Palettes/Progress/ProgressControl.cpp
new file mode 100644
index 00000000..2a69bf44
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Progress/ProgressControl.cpp
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+#include "Strings.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "ProgressControl.h"
+#include "Renderer.h"
+#include "ResourceCache.h"
+#include "ResImage.h"
+
+//==============================================================================
+/**
+ * Constructor
+ */
+CProgressControl::CProgressControl()
+ : m_Percent(0)
+{
+ // Load the image
+ m_Image = CResourceCache::GetInstance()->GetBitmap("progress-screen.png");
+
+ // Load the default string for the window for now
+ m_ActionText = ::LoadResourceString(IDS_WAIT_LOADING);
+}
+
+//==============================================================================
+/**
+ * Destructor
+ */
+CProgressControl::~CProgressControl()
+{
+}
+
+//==============================================================================
+/**
+ * The size of this control is equal to the size of the image that we display.
+ * @return the size (in pixels) of this control.
+ */
+CPt CProgressControl::GetSize() const
+{
+ return m_Image->GetSize();
+}
+
+//==============================================================================
+/**
+ * Draws this control.
+ * @param inRenderer renderer to draw to.
+ */
+void CProgressControl::Draw(CRenderer *inRenderer)
+{
+ // Draw the image over the whole window
+ inRenderer->DrawBitmap(CPt(0, 0), m_Image);
+
+ // Show "Loading..."
+ inRenderer->DrawText(105, 20, m_ActionText, GetSize(), CColor(255, 255, 255));
+
+ // Show the file name
+ if (!m_FileName.IsEmpty())
+ inRenderer->DrawText(105, 35, m_FileName, GetSize(), CColor(255, 255, 255));
+
+ // Show the percentage
+ inRenderer->DrawText(105, 50, m_PercentString, GetSize(), CColor(255, 255, 255));
+}
+
+//==============================================================================
+/**
+ * Sets the text displayed above the file name. For instance: "Loading..."
+ * @param inText text to be shown above the file name
+ */
+void CProgressControl::SetActionText(const Q3DStudio::CString &inText)
+{
+ m_ActionText = inText;
+ Invalidate();
+}
+
+//==============================================================================
+/**
+ * Changes the percentage complete displayed by this control.
+ * @param inPercent new percentage complete.
+ */
+void CProgressControl::SetProgress(long inPercent)
+{
+ m_Percent = inPercent;
+ char theBuffer[256] = { 0 };
+ _ltoa(m_Percent, theBuffer, 10);
+ m_PercentString = theBuffer;
+ m_PercentString += " %";
+ Invalidate();
+}
+
+//==============================================================================
+/**
+ * Sets the name of the file that is being opened. This is displayed on the
+ * control.
+ * @param inFileName File name to display in the middle of this control
+ */
+void CProgressControl::SetFileName(const Q3DStudio::CString &inFileName)
+{
+ m_FileName = inFileName;
+ Invalidate();
+}
diff --git a/src/Authoring/Studio/Palettes/Progress/ProgressControl.h b/src/Authoring/Studio/Palettes/Progress/ProgressControl.h
new file mode 100644
index 00000000..1d596c0c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Progress/ProgressControl.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_PROGRESS_CONTROL_H
+#define INCLUDED_PROGRESS_CONTROL_H 1
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "Control.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CRenderer;
+class CResImage;
+
+//==============================================================================
+/**
+ * Top-level control of a loading progress window.
+ */
+class CProgressControl : public CControl
+{
+public:
+ CProgressControl();
+ virtual ~CProgressControl();
+
+ virtual CPt GetSize() const;
+ virtual void Draw(CRenderer *inRenderer);
+ virtual void SetActionText(const Q3DStudio::CString &inText);
+ virtual void SetProgress(long inPercent);
+ void SetFileName(const Q3DStudio::CString &inFileName);
+
+protected:
+ long m_Percent;
+ Q3DStudio::CString m_ActionText;
+ Q3DStudio::CString m_PercentString;
+ Q3DStudio::CString m_FileName;
+ CResImage *m_Image;
+};
+
+#endif // INCLUDED_PROGRESS_CONTROL_H \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.cpp b/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.cpp
new file mode 100644
index 00000000..edcafbf1
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ProjectContextMenu.h"
+#include "ProjectView.h"
+
+ProjectContextMenu::ProjectContextMenu(ProjectView *parent, int index)
+ : QMenu(parent)
+ , m_view(parent)
+ , m_index(index)
+{
+ QAction *action = new QAction(tr("Show in Explorer"));
+ connect(action, &QAction::triggered, this, &ProjectContextMenu::handleShowInExplorer);
+ addAction(action);
+
+ addSeparator();
+
+ action = new QAction(tr("Copy Path"));
+ connect(action, &QAction::triggered, this, &ProjectContextMenu::handleCopyPath);
+ addAction(action);
+
+ action = new QAction(tr("Copy Full Path"));
+ connect(action, &QAction::triggered, this, &ProjectContextMenu::handleCopyFullPath);
+ addAction(action);
+
+ if (m_view->isGroup(m_index)) {
+ addSeparator();
+ action = new QAction(tr("Refresh Import..."));
+ connect(action, &QAction::triggered, this, &ProjectContextMenu::handleRefreshImport);
+ addAction(action);
+ }
+}
+
+ProjectContextMenu::~ProjectContextMenu()
+{
+}
+
+void ProjectContextMenu::handleShowInExplorer()
+{
+ m_view->showInExplorer(m_index);
+}
+
+void ProjectContextMenu::handleCopyPath()
+{
+ m_view->copyPath(m_index);
+}
+
+void ProjectContextMenu::handleCopyFullPath()
+{
+ m_view->copyFullPath(m_index);
+}
+
+void ProjectContextMenu::handleRefreshImport()
+{
+ m_view->refreshImport(m_index);
+}
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.h b/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.h
new file mode 100644
index 00000000..51dc8c5d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Project/ProjectContextMenu.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROJECT_CONTEXT_MENU_H
+#define PROJECT_CONTEXT_MENU_H
+
+#include <QtWidgets/qmenu.h>
+
+class ProjectView;
+
+class ProjectContextMenu : public QMenu
+{
+ Q_OBJECT
+public:
+ explicit ProjectContextMenu(ProjectView *parent, int index);
+ virtual ~ProjectContextMenu();
+
+private Q_SLOTS:
+ void handleShowInExplorer();
+ void handleCopyPath();
+ void handleCopyFullPath();
+ void handleRefreshImport();
+
+private:
+ ProjectView *m_view;
+ int m_index;
+};
+#endif // PROJECT_CONTEXT_MENU_H
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp
new file mode 100644
index 00000000..07ddd3d4
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp
@@ -0,0 +1,587 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qtAuthoring-config.h"
+#include <QtCore/qset.h>
+
+#include "stdafx.h"
+#include "ProjectFileSystemModel.h"
+#include "StudioUtils.h"
+#include "StudioApp.h"
+#include "ClientDataModelBridge.h"
+#include "Core.h"
+#include "Doc.h"
+#include "UICFileTools.h"
+#include "ImportUtils.h"
+#include "Dialogs.h"
+#include "UICDMStudioSystem.h"
+#include "UICImportTranslation.h"
+#include "IDocumentEditor.h"
+#include "PathImportTranslator.h"
+#include "IDragable.h"
+
+ProjectFileSystemModel::ProjectFileSystemModel(QObject *parent) : QAbstractListModel(parent)
+ , m_model(new QFileSystemModel(this))
+{
+ connect(m_model, &QAbstractItemModel::rowsInserted, this, &ProjectFileSystemModel::modelRowsInserted);
+ connect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved, this, &ProjectFileSystemModel::modelRowsRemoved);
+ connect(m_model, &QAbstractItemModel::layoutChanged, this, &ProjectFileSystemModel::modelLayoutChanged);
+}
+
+QHash<int, QByteArray> ProjectFileSystemModel::roleNames() const
+{
+ auto modelRoleNames = m_model->roleNames();
+ modelRoleNames.insert(IsExpandableRole, "_isExpandable");
+ modelRoleNames.insert(IsDraggableRole, "_isDraggable");
+ modelRoleNames.insert(IsReferencedRole, "_isReferenced");
+ modelRoleNames.insert(DepthRole, "_depth");
+ modelRoleNames.insert(ExpandedRole, "_expanded");
+ return modelRoleNames;
+}
+
+int ProjectFileSystemModel::rowCount(const QModelIndex &) const
+{
+ return m_items.count();
+}
+
+QVariant ProjectFileSystemModel::data(const QModelIndex &index, int role) const
+{
+ const auto &item = m_items.at(index.row());
+
+ switch (role) {
+ case Qt::DecorationRole: {
+ QString path = item.index.data(QFileSystemModel::FilePathRole).toString();
+ return resourceImageUrl() + getIconName(path);
+ }
+
+ case IsExpandableRole: {
+ if (item.index == m_rootIndex) {
+ return false;
+ } else {
+ return hasVisibleChildren(item.index);
+ }
+ }
+
+ case IsDraggableRole:
+ return QFileInfo(item.index.data(QFileSystemModel::FilePathRole).toString()).isFile();
+
+ case IsReferencedRole: {
+ const QString path = item.index.data(QFileSystemModel::FilePathRole).toString();
+ return m_references.contains(path);
+ }
+
+ case DepthRole:
+ return item.depth;
+
+ case ExpandedRole:
+ return item.expanded;
+
+ default:
+ return m_model->data(item.index, role);
+ }
+}
+
+QMimeData *ProjectFileSystemModel::mimeData(const QModelIndexList &indexes) const
+{
+ const auto path = filePath(indexes.first().row()); // can only drag one item
+ CUICFile dragFile(Q3DStudio::CString::fromQString(path));
+ return CDropSourceFactory::Create(EUIC_FLAVOR_ASSET_UICFILE,
+ reinterpret_cast<void *>(&dragFile),
+ sizeof(dragFile));
+}
+
+QString ProjectFileSystemModel::filePath(int row) const
+{
+ if (row < 0 || row >= m_items.size())
+ return QString();
+ const auto &item = m_items.at(row);
+ return item.index.data(QFileSystemModel::FilePathRole).toString();
+}
+
+void ProjectFileSystemModel::updateReferences(bool emitDataChanged)
+{
+ m_references.clear();
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+ const auto sourcePathList = bridge->GetSourcePathList();
+ const auto fontFileList = bridge->GetFontFileList();
+ const auto effectTextureList = bridge->GetDynamicObjectTextureList();
+
+ auto addFileReferences = [this, doc](const Q3DStudio::CString &str) {
+ auto path = doc->GetResolvedPathToDoc(str).toQString();
+ path = QDir::cleanPath(path);
+ m_references.append(path);
+ QString rootPath = QDir::cleanPath(doc->GetDocumentDirectory().toQString());
+ QString parentPath = QFileInfo(path).path();
+ do {
+ if (!m_references.contains(parentPath))
+ m_references.append(parentPath);
+ path = parentPath;
+ parentPath = QFileInfo(path).path();
+ } while (rootPath != path && parentPath != path);
+ };
+
+ std::for_each(sourcePathList.begin(), sourcePathList.end(), addFileReferences);
+ std::for_each(fontFileList.begin(), fontFileList.end(), addFileReferences);
+ std::for_each(effectTextureList.begin(), effectTextureList.end(), addFileReferences);
+
+ if (emitDataChanged)
+ Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), {IsReferencedRole});
+}
+
+void ProjectFileSystemModel::setRootPath(const QString &path)
+{
+ setRootIndex(m_model->setRootPath(path));
+}
+
+void ProjectFileSystemModel::setRootIndex(const QModelIndex &rootIndex)
+{
+ if (rootIndex == m_rootIndex)
+ return;
+
+ clearModelData();
+ updateReferences(false);
+
+ m_rootIndex = rootIndex;
+
+ beginInsertRows({}, 0, 0);
+ m_items.append({ m_rootIndex, 0, true, nullptr, 0 });
+ endInsertRows();
+
+ showModelTopLevelItems();
+}
+
+void ProjectFileSystemModel::clearModelData()
+{
+ beginResetModel();
+ m_items.clear();
+ endResetModel();
+}
+
+void ProjectFileSystemModel::showModelTopLevelItems()
+{
+ int rowCount = m_model->rowCount(m_rootIndex);
+
+ if (rowCount == 0) {
+ if (m_model->hasChildren(m_rootIndex) && m_model->canFetchMore(m_rootIndex))
+ m_model->fetchMore(m_rootIndex);
+ } else {
+ showModelChildItems(m_rootIndex, 0, rowCount - 1);
+ }
+}
+
+void ProjectFileSystemModel::showModelChildItems(const QModelIndex &parentIndex, int start, int end)
+{
+ const int parentRow = modelIndexRow(parentIndex);
+ if (parentRow == -1)
+ return;
+
+ Q_ASSERT(isVisible(parentIndex));
+
+ QVector<QModelIndex> rowsToInsert;
+ for (int i = start; i <= end; ++i) {
+ const auto &childIndex = m_model->index(i, 0, parentIndex);
+ if (isVisible(childIndex))
+ rowsToInsert.append(childIndex);
+ }
+
+ const int insertCount = rowsToInsert.count();
+ if (insertCount == 0)
+ return;
+
+ auto parent = &m_items[parentRow];
+
+ const int depth = parent->depth + 1;
+ const int startRow = parentRow + parent->childCount + 1;
+
+ beginInsertRows({}, startRow, startRow + insertCount - 1);
+
+ for (auto it = rowsToInsert.rbegin(); it != rowsToInsert.rend(); ++it)
+ m_items.insert(startRow, { *it, depth, false, parent, 0 });
+
+ for (; parent != nullptr; parent = parent->parent)
+ parent->childCount += insertCount;
+
+ endInsertRows();
+
+ // also fetch children so we're notified when files are added or removed in immediate subdirs
+ for (const auto &childIndex : rowsToInsert) {
+ if (m_model->hasChildren(childIndex) && m_model->canFetchMore(childIndex))
+ m_model->fetchMore(childIndex);
+ }
+}
+
+void ProjectFileSystemModel::expand(int row)
+{
+ Q_ASSERT(row >= 0 && row < m_items.size());
+
+ auto &item = m_items[row];
+ Q_ASSERT(item.expanded == false);
+
+ const auto &modelIndex = item.index;
+
+ const int rowCount = m_model->rowCount(modelIndex);
+ if (rowCount == 0) {
+ if (m_model->hasChildren(modelIndex) && m_model->canFetchMore(modelIndex))
+ m_model->fetchMore(modelIndex);
+ } else {
+ showModelChildItems(modelIndex, 0, rowCount - 1);
+ }
+
+ item.expanded = true;
+ Q_EMIT dataChanged(index(row), index(row));
+}
+
+bool ProjectFileSystemModel::hasValidUrlsForDropping(const QList<QUrl> &urls) const
+{
+ for (const auto &url : urls) {
+ if (url.isLocalFile()) {
+ const QString path = url.toLocalFile();
+ const QFileInfo fileInfo(path);
+ if (fileInfo.isFile()) {
+ const QString extension = fileInfo.suffix();
+ return extension.compare(QLatin1String(CDialogs::GetDAEFileExtension()),
+ Qt::CaseInsensitive) == 0
+#ifdef QT_3DSTUDIO_FBX
+ || extension.compare(QLatin1String(CDialogs::GetFbxFileExtension()),
+ Qt::CaseInsensitive) == 0
+#endif
+ || getIconType(path) != OBJTYPE_UNKNOWN;
+ }
+ }
+ }
+
+ return false;
+}
+
+void ProjectFileSystemModel::dropUrls(const QList<QUrl> &urls, int row)
+{
+ Q_ASSERT(row >= 0 && row < m_items.size());
+
+ const auto &item = m_items.at(row);
+ const QString targetPath = item.index.data(QFileSystemModel::FilePathRole).toString();
+ const QDir targetDir(targetPath);
+
+ if (targetDir.exists()) {
+ for (const auto& url : urls)
+ dropUrl(targetPath, url);
+
+ if (!item.expanded)
+ expand(row);
+ }
+}
+
+void ProjectFileSystemModel::dropUrl(const QDir &targetDir, const QUrl &url) const
+{
+ using namespace Q3DStudio;
+ using namespace UICIMP;
+ // Drag and Drop - From Explorer window to Project Palette
+ // For all valid Project File Types:
+ // - This performs a file copy from the source Explorer location to the selected Project Palette
+ // Folder
+ // - The destination copy must NOT be read-only even if the source is read-only
+ // For DAE, it will import the file.
+
+ if (!url.isLocalFile())
+ return;
+
+ const QString sourceFile = url.toLocalFile();
+
+ const QFileInfo fileInfo(sourceFile);
+ if (!fileInfo.isFile())
+ return;
+
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+
+ const QString extension = fileInfo.suffix();
+ const QString fileStem = fileInfo.baseName();
+ const QString outputFileName = QStringLiteral("%1.%2").arg(fileStem).arg(CDialogs::GetImportFileExtension());
+
+ if (extension.compare(QLatin1String(CDialogs::GetDAEFileExtension()), Qt::CaseInsensitive) == 0) {
+ SColladaTranslator translator(sourceFile);
+ const QDir outputDir = SFileTools::FindUniqueDestDirectory(targetDir, fileStem);
+ const QString fullOutputFile = outputDir.filePath(outputFileName);
+ const SImportResult importResult =
+ CPerformImport::TranslateToImportFile(translator, CFilePath::fromQString(fullOutputFile));
+ bool forceError = QFileInfo(fullOutputFile).isFile() == false;
+ IDocumentEditor::DisplayImportErrors(
+ sourceFile, importResult.m_Error, doc->GetImportFailedHandler(),
+ translator.m_TranslationLog, forceError);
+#ifdef QT_3DSTUDIO_FBX
+ } else if (extension.compare(QLatin1String(CDialogs::GetFbxFileExtension()), Qt::CaseInsensitive) == 0) {
+ SFbxTranslator translator(sourceFile);
+ const QDir outputDir = SFileTools::FindUniqueDestDirectory(targetDir, fileStem);
+ const QString fullOutputFile = outputDir.filePath(outputFileName);
+ const SImportResult importResult =
+ CPerformImport::TranslateToImportFile(translator, CFilePath::fromQString(fullOutputFile));
+ bool forceError = QFileInfo(fullOutputFile).isFile() == false;
+ IDocumentEditor::DisplayImportErrors(
+ sourceFile, importResult.m_Error, doc->GetImportFailedHandler(),
+ translator.m_TranslationLog, forceError);
+#endif
+ } else if (extension.compare(QLatin1String("svg"), Qt::CaseInsensitive) == 0) {
+ IDocumentReader &reader(doc->GetDocumentReader());
+ SPathImportTranslator translator(sourceFile, *reader.GetLuaContext(), reader.GetFoundation());
+ const QDir outputDir = SFileTools::FindUniqueDestDirectory(targetDir, fileStem);
+ const QString fullOutputFile = outputDir.filePath(outputFileName);
+ const SImportResult importResult =
+ CPerformImport::TranslateToImportFile(translator, CFilePath::fromQString(fullOutputFile));
+ bool forceError = QFileInfo(fullOutputFile).isFile() == false;
+ IDocumentEditor::DisplayImportErrors(
+ sourceFile, importResult.m_Error,
+ doc->GetImportFailedHandler(),
+ translator.m_TranslationLog, forceError);
+ } else {
+ // Copy the file to target directory
+ // FindAndCopyDestFile will make sure the file name is unique and make sure it is
+ // not read only.
+ bool copyResult = SFileTools::FindAndCopyDestFile(targetDir, sourceFile);
+ ASSERT(copyResult);
+
+ // For effect and custom material files, automatically copy related resources
+ if (CDialogs::IsEffectFileExtension(extension.toLatin1().data())
+ || CDialogs::IsMaterialFileExtension(extension.toLatin1().data())) {
+ std::vector<Q3DStudio::CString> effectFileSourcePaths;
+ doc->GetDocumentReader().ParseSourcePathsOutOfEffectFile(
+ Q3DStudio::CFilePath::GetAbsolutePath(CFilePath::fromQString(sourceFile)),
+ effectFileSourcePaths);
+
+ const QDir fileDir = QFileInfo(sourceFile).dir();
+ const QDir documentDir(doc->GetDocumentDirectory().toQString());
+
+ for (const auto &effectFile : effectFileSourcePaths) {
+ const QString sourcePath = fileDir.filePath(effectFile.toQString());
+ const QString resultPath = documentDir.filePath(effectFile.toQString());
+
+ const QFileInfo resultFileInfo(resultPath);
+ if (!resultFileInfo.exists()) {
+ resultFileInfo.dir().mkpath(".");
+ QFile::copy(sourcePath, resultPath);
+ }
+ }
+ }
+ }
+}
+
+void ProjectFileSystemModel::collapse(int row)
+{
+ Q_ASSERT(row >= 0 && row < m_items.size());
+
+ auto &item = m_items[row];
+ Q_ASSERT(item.expanded == true);
+
+ const int childCount = item.childCount;
+
+ if (childCount > 0) {
+ beginRemoveRows({}, row + 1, row + childCount);
+
+ m_items.erase(std::begin(m_items) + row + 1, std::begin(m_items) + row + 1 + childCount);
+
+ for (auto parent = &item; parent != nullptr; parent = parent->parent)
+ parent->childCount -= childCount;
+
+ endRemoveRows();
+ }
+
+ item.expanded = false;
+ Q_EMIT dataChanged(index(row), index(row));
+}
+
+int ProjectFileSystemModel::modelIndexRow(const QModelIndex &modelIndex) const
+{
+ auto it = std::find_if(
+ std::begin(m_items),
+ std::end(m_items),
+ [&modelIndex](const TreeItem &item)
+ {
+ return item.index == modelIndex;
+ });
+
+ return it != std::end(m_items) ? std::distance(std::begin(m_items), it) : -1;
+}
+
+bool ProjectFileSystemModel::isExpanded(const QModelIndex &modelIndex) const
+{
+ if (modelIndex == m_rootIndex)
+ return true;
+ const int row = modelIndexRow(modelIndex);
+ return row != -1 && m_items.at(row).expanded;
+}
+
+EStudioObjectType ProjectFileSystemModel::getIconType(const QString &path) const
+{
+ Q3DStudio::CFilePath filePath(Q3DStudio::CString::fromQString(path));
+ return Q3DStudio::ImportUtils::GetObjectFileTypeForFile(filePath).m_IconType;
+}
+
+QString ProjectFileSystemModel::getIconName(const QString &path) const
+{
+ QString iconName;
+
+ QFileInfo fileInfo(path);
+ if (fileInfo.isFile()) {
+ EStudioObjectType type = getIconType(path);
+ if (type != OBJTYPE_UNKNOWN)
+ iconName = CStudioObjectTypes::GetNormalIconName(type);
+ else
+ iconName = QStringLiteral("Objects-Layer-Normal.png");
+ } else {
+ iconName = QStringLiteral("Objects-Folder-Normal.png");
+ }
+
+ return iconName;
+}
+
+bool ProjectFileSystemModel::hasVisibleChildren(const QModelIndex &modelIndex) const
+{
+ const QDir dir(modelIndex.data(QFileSystemModel::FilePathRole).toString());
+ if (!dir.exists() || dir.isEmpty())
+ return false;
+
+ const auto fileInfoList = dir.entryInfoList(QDir::Dirs|QDir::Files|QDir::NoDotAndDotDot);
+ for (const auto &fileInfo : fileInfoList) {
+ if (fileInfo.isDir() || getIconType(fileInfo.filePath()) != OBJTYPE_UNKNOWN)
+ return true;
+ }
+
+ return false;
+}
+
+bool ProjectFileSystemModel::isVisible(const QModelIndex &modelIndex) const
+{
+ bool result = false;
+
+ if (modelIndex == m_rootIndex) {
+ result = true;
+ } else {
+ QString path = modelIndex.data(QFileSystemModel::FilePathRole).toString();
+ QFileInfo fileInfo(path);
+ if (fileInfo.isFile()) {
+ result = getIconType(path) != OBJTYPE_UNKNOWN;
+ } else {
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+void ProjectFileSystemModel::modelRowsInserted(const QModelIndex &parent, int start, int end)
+{
+ if (!m_rootIndex.isValid())
+ return;
+
+ if (isExpanded(parent)) {
+ showModelChildItems(parent, start, end);
+ } else {
+ if (hasVisibleChildren(parent)) {
+ // show expand arrow
+ const int row = modelIndexRow(parent);
+ Q_EMIT dataChanged(index(row), index(row));
+ }
+ }
+}
+
+void ProjectFileSystemModel::modelRowsRemoved(const QModelIndex &parent, int start, int end)
+{
+ if (!m_rootIndex.isValid())
+ return;
+
+ if (isExpanded(parent)) {
+ for (int i = start; i <= end; ++i) {
+ const int row = modelIndexRow(m_model->index(i, 0, parent));
+
+ if (row != -1) {
+ const auto &item = m_items.at(row);
+
+ beginRemoveRows({}, row, row + item.childCount);
+
+ for (auto parent = item.parent; parent != nullptr; parent = parent->parent)
+ parent->childCount -= 1 + item.childCount;
+
+ m_items.erase(std::begin(m_items) + row, std::begin(m_items) + row + item.childCount + 1);
+
+ endRemoveRows();
+ }
+ }
+ }
+
+ if (!hasVisibleChildren(parent)) {
+ // hide expand arrow
+ const int row = modelIndexRow(parent);
+ m_items[row].expanded = false;
+ Q_EMIT dataChanged(index(row), index(row));
+ }
+}
+
+void ProjectFileSystemModel::modelLayoutChanged()
+{
+ if (!m_rootIndex.isValid())
+ return;
+
+ QSet<QPersistentModelIndex> expandedItems;
+ for (const auto &item : m_items) {
+ if (item.expanded)
+ expandedItems.insert(item.index);
+ }
+
+ const std::function<int(const QModelIndex &, TreeItem *)> insertChildren = [this, &expandedItems, &insertChildren](const QModelIndex &parentIndex, TreeItem *parent)
+ {
+ Q_ASSERT(isVisible(parentIndex));
+
+ const int rowCount = m_model->rowCount(parentIndex);
+ const int depth = parent->depth + 1;
+
+ int childCount = 0;
+
+ for (int i = 0; i < rowCount; ++i) {
+ const auto &childIndex = m_model->index(i, 0, parentIndex);
+ if (isVisible(childIndex)) {
+ const bool expanded = expandedItems.contains(childIndex);
+ m_items.append({ childIndex, depth, expanded, parent, 0 });
+ auto &item = m_items.last();
+ if (expanded) {
+ item.childCount = insertChildren(childIndex, &item);
+ childCount += item.childCount;
+ }
+ ++childCount;
+ }
+ }
+
+ return childCount;
+ };
+
+ const int itemCount = m_items.count();
+
+ m_items.erase(std::begin(m_items) + 1, std::end(m_items));
+ m_items.reserve(itemCount);
+ insertChildren(m_rootIndex, &m_items.first());
+
+ Q_ASSERT(m_items.count() == itemCount);
+
+ Q_EMIT dataChanged(index(0), index(itemCount - 1));
+}
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.h b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.h
new file mode 100644
index 00000000..c9ef1b27
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef TREEVIEWADAPTOR_H
+#define TREEVIEWADAPTOR_H
+
+#include "StudioObjectTypes.h"
+
+#include <QFileSystemModel>
+#include <QAbstractListModel>
+#include <QList>
+#include <QUrl>
+
+class QFileSystemModel;
+
+class ProjectFileSystemModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ explicit ProjectFileSystemModel(QObject *parent = nullptr);
+
+ enum {
+ IsExpandableRole = QFileSystemModel::FilePermissions + 1,
+ IsDraggableRole,
+ IsReferencedRole,
+ DepthRole,
+ ExpandedRole,
+ };
+
+ void setRootPath(const QString &path);
+
+ QHash<int, QByteArray> roleNames() const override;
+ int rowCount(const QModelIndex &parent = {}) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+ QMimeData *mimeData(const QModelIndexList &indexes) const override;
+
+ QString filePath(int row) const;
+
+ void updateReferences(bool emitDataChanged);
+
+ Q_INVOKABLE void expand(int row);
+ Q_INVOKABLE void collapse(int row);
+
+ Q_INVOKABLE void dropUrls(const QList<QUrl> &urls, int row);
+ Q_INVOKABLE bool hasValidUrlsForDropping(const QList<QUrl> &urls) const;
+
+Q_SIGNALS:
+ void modelChanged(QAbstractItemModel *model);
+
+private:
+ void setRootIndex(const QModelIndex &rootIndex);
+ void clearModelData();
+ void showModelTopLevelItems();
+ void showModelChildItems(const QModelIndex &parentItem, int start, int end);
+ int modelIndexRow(const QModelIndex &modelIndex) const;
+ bool isExpanded(const QModelIndex &modelIndex) const;
+ QString getIconName(const QString &path) const;
+ EStudioObjectType getIconType(const QString &path) const;
+ bool isVisible(const QModelIndex& modelIndex) const;
+ bool hasVisibleChildren(const QModelIndex &modelIndex) const;
+ void dropUrl(const QDir &targetDir, const QUrl &url) const;
+
+ void modelRowsInserted(const QModelIndex &parent, int start, int end);
+ void modelRowsRemoved(const QModelIndex &parent, int start, int end);
+ void modelRowsMoved(const QModelIndex &parent, int start, int end);
+ void modelLayoutChanged();
+
+ struct TreeItem {
+ QPersistentModelIndex index;
+ int depth;
+ bool expanded;
+ TreeItem *parent;
+ int childCount;
+ };
+
+ QFileSystemModel *m_model = nullptr;
+ QPersistentModelIndex m_rootIndex;
+ QList<TreeItem> m_items;
+ QStringList m_references;
+};
+
+#endif // TREEVIEWADAPTOR_H
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectView.cpp b/src/Authoring/Studio/Palettes/Project/ProjectView.cpp
new file mode 100644
index 00000000..0bdc69a6
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Project/ProjectView.cpp
@@ -0,0 +1,250 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "ProjectView.h"
+#include "ProjectFileSystemModel.h"
+#include "Core.h"
+#include "Dispatch.h"
+#include "Doc.h"
+#include "Literals.h"
+#include "StudioUtils.h"
+#include "ImportUtils.h"
+#include "StudioApp.h"
+#include "StudioClipboard.h"
+#include "StudioPreferences.h"
+#include "UICImport.h"
+#include "Dialogs.h"
+#include "IDocumentEditor.h"
+#include "ProjectContextMenu.h"
+
+#include <QtCore/qprocess.h>
+#include <QtCore/qtimer.h>
+#include <QtGui/qdrag.h>
+#include <QtGui/qdesktopservices.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+
+ProjectView::ProjectView(QWidget *parent) : QQuickWidget(parent)
+ , m_ProjectModel(new ProjectFileSystemModel(this))
+{
+ const QString theApplicationPath =
+ CUICFile::GetApplicationDirectory().GetAbsolutePath().toQString();
+
+ m_BehaviorDir = CUICFile(
+ Q3DStudio::CString::fromQString(theApplicationPath
+ + QLatin1String("/Content/Behavior Library")));
+ m_EffectDir = CUICFile(
+ Q3DStudio::CString::fromQString(theApplicationPath
+ + QLatin1String("/Content/Effect Library")));
+ m_FontDir = CUICFile(
+ Q3DStudio::CString::fromQString(theApplicationPath
+ + QLatin1String("/Content/Font Library")));
+ m_ImageDir = CUICFile(
+ Q3DStudio::CString::fromQString(theApplicationPath
+ + QLatin1String("/Content/Maps Library")));
+ m_MaterialDir = CUICFile(
+ Q3DStudio::CString::fromQString(theApplicationPath
+ + QLatin1String("/Content/Material Library")));
+ m_ModelDir = CUICFile(
+ Q3DStudio::CString::fromQString(theApplicationPath
+ + QLatin1String("/Content/Models Library")));
+
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ QTimer::singleShot(0, this, &ProjectView::initialize);
+
+ auto dispatch = g_StudioApp.GetCore()->GetDispatch();
+ dispatch->AddPresentationChangeListener(this);
+ dispatch->AddDataModelListener(this);
+}
+
+ProjectView::~ProjectView()
+{
+}
+
+QAbstractItemModel *ProjectView::projectModel() const
+{
+ return m_ProjectModel;
+}
+
+QSize ProjectView::sizeHint() const
+{
+ return {500,500};
+}
+
+void ProjectView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty("_resDir"_L1, resourceImageUrl());
+ rootContext()->setContextProperty("_projectView"_L1, this);
+
+ engine()->addImportPath(qmlImportPath());
+ setSource(QUrl("qrc:/Studio/Palettes/Project/ProjectView.qml"_L1));
+}
+
+void ProjectView::effectAction()
+{
+ m_EffectDir.Execute();
+}
+
+void ProjectView::fontAction()
+{
+ m_FontDir.Execute();
+}
+
+void ProjectView::imageAction()
+{
+ m_ImageDir.Execute();
+}
+
+void ProjectView::materialAction()
+{
+ m_MaterialDir.Execute();
+}
+
+void ProjectView::modelAction()
+{
+ m_ModelDir.Execute();
+}
+
+void ProjectView::behaviorAction()
+{
+ m_BehaviorDir.Execute();
+}
+
+void ProjectView::OnNewPresentation()
+{
+ rebuild();
+}
+
+void ProjectView::OnBeginDataModelNotifications()
+{
+}
+
+void ProjectView::OnEndDataModelNotifications()
+{
+ m_ProjectModel->updateReferences(true);
+}
+
+void ProjectView::OnImmediateRefreshInstanceSingle(UICDM::CUICDMInstanceHandle inInstance)
+{
+ Q_UNUSED(inInstance);
+}
+
+void ProjectView::OnImmediateRefreshInstanceMultiple(UICDM::CUICDMInstanceHandle *inInstance, long inInstanceCount)
+{
+ Q_UNUSED(inInstance);
+ Q_UNUSED(inInstanceCount);
+}
+
+void ProjectView::startDrag(int row)
+{
+ const auto index = m_ProjectModel->index(row);
+
+ QDrag drag(this);
+ drag.setMimeData(m_ProjectModel->mimeData({index}));
+ drag.exec(Qt::CopyAction);
+}
+
+void ProjectView::showInExplorer(int row) const
+{
+ if (row == -1)
+ return;
+ const auto path = m_ProjectModel->filePath(row);
+#if defined(Q_OS_WIN)
+ QProcess::startDetached("explorer", {"/select", path});
+#elif defined(Q_OS_MACOS)
+ QProcess::startDetached("/usr/bin/osascript", {"-e",
+ QStringLiteral("tell application \"Finder\" to reveal POSIX file \"%1\"").arg(path)});
+ QProcess::startDetached("/usr/bin/osascript", {"-e",
+ QStringLiteral("tell application \"Finder\" to activate")});
+#else
+ // we cannot select a file here, because no file browser really supports it...
+ QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(path).absolutePath()));
+#endif
+}
+
+void ProjectView::copyPath(int row) const
+{
+ if (row == -1)
+ return;
+ const auto path = m_ProjectModel->filePath(row);
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ const auto relativePath = doc->GetRelativePathToDoc(
+ Q3DStudio::CFilePath(Q3DStudio::CString::fromQString(path)));
+ CStudioClipboard::CopyTextToClipboard(relativePath.toQString());
+}
+
+void ProjectView::copyFullPath(int row) const
+{
+ if (row == -1)
+ return;
+ const auto path = m_ProjectModel->filePath(row);
+ CStudioClipboard::CopyTextToClipboard(path);
+}
+
+bool ProjectView::isGroup(int row) const
+{
+ if (row == -1)
+ return false;
+ Q3DStudio::CFilePath path(Q3DStudio::CString::fromQString(m_ProjectModel->filePath(row)));
+ return Q3DStudio::ImportUtils::GetObjectFileTypeForFile(path).m_ObjectType == OBJTYPE_GROUP;
+}
+
+void ProjectView::showContextMenu(int x, int y, int index)
+{
+ ProjectContextMenu contextMenu(this, index);
+ contextMenu.exec(mapToGlobal({x, y}));
+}
+
+void ProjectView::refreshImport(int row) const
+{
+ if (row == -1)
+ return;
+ using namespace Q3DStudio;
+ const auto path = m_ProjectModel->filePath(row);
+ UICIMP::ImportPtrOrError importPtr = UICIMP::Import::Load(path.toStdWString().c_str());
+ if (importPtr.m_Value) {
+ const auto destDir = QString::fromWCharArray(importPtr.m_Value->GetDestDir());
+ const auto srcFile = QString::fromWCharArray(importPtr.m_Value->GetSrcFile());
+ const QString fullSrcPath(QDir(destDir).filePath(srcFile));
+ const QFileInfo newFile(g_StudioApp.GetDialogs()->ConfirmRefreshModelFile(fullSrcPath));
+ if (newFile.exists() && newFile.isFile()){
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*doc, tr("Refresh Import..."))
+ ->RefreshImport(fullSrcPath, CString::fromQString(newFile.filePath()));
+ }
+ }
+}
+
+void ProjectView::rebuild()
+{
+ const auto theDoc = g_StudioApp.GetCore()->GetDoc();
+ const Q3DStudio::CFilePath thePath(theDoc->GetDocumentPath().GetAbsolutePath());
+ const Q3DStudio::CFilePath theRootDirPath = thePath.GetDirectory();
+
+ m_ProjectModel->setRootPath(theRootDirPath.toQString());
+}
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectView.h b/src/Authoring/Studio/Palettes/Project/ProjectView.h
new file mode 100644
index 00000000..f46aa976
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Project/ProjectView.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef PROJECTVIEW_H
+#define PROJECTVIEW_H
+
+#include "DispatchListeners.h"
+#include "UICFile.h"
+
+#include <QQuickWidget>
+#include <QModelIndex>
+
+class ProjectFileSystemModel;
+
+class ProjectView : public QQuickWidget,
+ public CPresentationChangeListener,
+ public IDataModelListener
+
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QAbstractItemModel *projectModel READ projectModel NOTIFY projectChanged FINAL)
+
+public:
+ explicit ProjectView(QWidget *parent = nullptr);
+ ~ProjectView();
+
+ QSize sizeHint() const override;
+
+ QAbstractItemModel *projectModel() const;
+
+ Q_INVOKABLE void effectAction();
+ Q_INVOKABLE void fontAction();
+ Q_INVOKABLE void imageAction();
+ Q_INVOKABLE void materialAction();
+ Q_INVOKABLE void modelAction();
+ Q_INVOKABLE void behaviorAction();
+
+ Q_INVOKABLE void startDrag(int row);
+
+ Q_INVOKABLE void showInExplorer(int row) const;
+ Q_INVOKABLE void copyPath(int row) const;
+ Q_INVOKABLE void copyFullPath(int row) const;
+ Q_INVOKABLE void refreshImport(int row) const;
+
+ Q_INVOKABLE bool isGroup(int row) const;
+ Q_INVOKABLE void showContextMenu(int x, int y, int index);
+
+ // CPresentationChangeListener
+ void OnNewPresentation() override;
+ // IDataModelListener
+ void OnBeginDataModelNotifications() override;
+ void OnEndDataModelNotifications() override;
+ // These are used during drag operations or during operations which
+ // require immediate user feedback. So they are unimplemented, effectively,
+ // we ignore them.
+ void OnImmediateRefreshInstanceSingle(UICDM::CUICDMInstanceHandle inInstance) override;
+ void OnImmediateRefreshInstanceMultiple(UICDM::CUICDMInstanceHandle *inInstance,
+ long inInstanceCount) override;
+
+Q_SIGNALS:
+ void projectChanged();
+
+private:
+ void initialize();
+ void rebuild();
+
+ ProjectFileSystemModel *m_ProjectModel = nullptr;
+ QColor m_BaseColor = QColor::fromRgb(75, 75, 75);
+ CUICFile m_BehaviorDir{""};
+ CUICFile m_EffectDir{""};
+ CUICFile m_FontDir{""};
+ CUICFile m_ImageDir{""};
+ CUICFile m_MaterialDir{""};
+ CUICFile m_ModelDir{""};
+};
+
+#endif // PROJECTVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectView.qml b/src/Authoring/Studio/Palettes/Project/ProjectView.qml
new file mode 100644
index 00000000..88ff608f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Project/ProjectView.qml
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+import "../controls"
+
+Rectangle {
+ id: root
+
+ color: _backgroundColor
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: 4
+
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton
+ onClicked: {
+ _projectView.showContextMenu(mouse.x, mouse.y, projectTree.currentIndex);
+ }
+ }
+
+ ListView {
+ id: projectTree
+
+ anchors.fill: parent
+
+ ScrollBar.vertical: ScrollBar {}
+
+ model: _projectView.projectModel
+
+ delegate: Rectangle {
+ id: delegateItem
+
+ width: parent.width
+ height: 20
+ color: index == projectTree.currentIndex ? _selectionColor : "transparent"
+
+ Row {
+ x: _depth*28
+ anchors.verticalCenter: delegateItem.verticalCenter
+
+ Image {
+ source: _resDir + (_expanded ? "arrow_down.png" : "arrow.png")
+ opacity: _isExpandable ? 1 : 0
+
+ MouseArea {
+ visible: _isExpandable
+ anchors.fill: parent
+ onClicked: {
+ if (_expanded)
+ projectTree.model.collapse(index)
+ else
+ projectTree.model.expand(index)
+ delegateMouseArea.clickPending = false
+ }
+ }
+ }
+
+ Image {
+ source: fileIcon
+ }
+
+ StyledLabel {
+ text: fileName
+ color: _isReferenced ? _textColor : _disabledColor
+ leftPadding: 2
+
+ Item {
+ id: dragItem
+
+ visible: _isDraggable
+ anchors.fill: parent
+
+ Drag.active: dragArea.drag.active
+ Drag.hotSpot.x: width / 2
+ Drag.hotSpot.y: height / 2
+ Drag.dragType: Drag.Automatic
+ Drag.supportedActions: Qt.CopyAction
+
+ MouseArea {
+ id: dragArea
+ anchors.fill: parent
+ drag.target: dragItem
+ }
+
+ Drag.onDragStarted: _projectView.startDrag(index)
+ }
+ }
+ }
+
+ DropArea {
+ id: dropArea
+
+ anchors.fill: parent
+
+ onEntered: {
+ if (drag.hasUrls && projectTree.model.hasValidUrlsForDropping(drag.urls)) {
+ drag.accept(Qt.CopyAction)
+ } else {
+ drag.accepted = false;
+ }
+ }
+
+ onDropped: {
+ if (drop.hasUrls) {
+ projectTree.model.dropUrls(drop.urls, index)
+ }
+ }
+ }
+
+ MouseArea {
+ id: delegateMouseArea
+ property bool clickPending: false
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton|Qt.LeftButton
+ propagateComposedEvents: true
+ onPressed: {
+ projectTree.currentIndex = model.index;
+
+ // Presses must be ignored by this handler in order for dragging to work
+ mouse.accepted = false;
+
+ // Since ignoring presses means we don't get doubleClicked events,
+ // detect doubleclick using custom timer.
+ if (clickPending) {
+ if (_isExpandable) {
+ if (_expanded)
+ projectTree.model.collapse(index);
+ else
+ projectTree.model.expand(index);
+ }
+ clickPending = false;
+ } else {
+ clickPending = true;
+ doubleClickTimer.restart();
+ }
+ }
+ Timer {
+ id: doubleClickTimer
+ repeat: false
+ triggeredOnStart: false
+ interval: 500
+ onTriggered: parent.clickPending = false;
+ }
+ }
+ }
+ }
+ }
+
+ StyledMenuSeparator {}
+
+ RowLayout {
+ width: parent.width
+ Layout.margins: 4
+ Layout.rightMargin: 12
+
+ Item {
+ Layout.fillWidth: true
+ }
+
+ StyledToolButton {
+ enabledImage: "Objects-Effect-Normal.png";
+ onClicked: _projectView.effectAction()
+ toolTipText: qsTr("Open Effect Library directory")
+ }
+
+ StyledToolButton {
+ enabledImage: "Objects-Text-Normal.png";
+ onClicked: _projectView.fontAction()
+ toolTipText: qsTr("Open Font Library directory")
+ }
+
+ StyledToolButton {
+ enabledImage: "Objects-Image-Normal.png";
+ onClicked: _projectView.imageAction()
+ toolTipText: qsTr("Open Maps Library directory")
+ }
+
+ StyledToolButton {
+ enabledImage: "Objects-Material-Normal.png";
+ onClicked: _projectView.materialAction()
+ toolTipText: qsTr("Open Material Library directory")
+ }
+
+ StyledToolButton {
+ enabledImage: "Objects-Model-Normal.png";
+ onClicked: _projectView.modelAction()
+ toolTipText: qsTr("Open Models Library directory")
+ }
+
+ StyledToolButton {
+ enabledImage: "Objects-Behavior-Normal.png";
+ onClicked: _projectView.behaviorAction()
+ toolTipText: qsTr("Open Behavior Library directory")
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideContextMenu.cpp b/src/Authoring/Studio/Palettes/Slide/SlideContextMenu.cpp
new file mode 100644
index 00000000..9af46cb1
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Slide/SlideContextMenu.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "SlideContextMenu.h"
+#include "SlideView.h"
+
+SlideContextMenu::SlideContextMenu(SlideView *parent, int row, int rowCount, bool master)
+ : QMenu(parent)
+ , m_view(parent)
+ , m_row(row)
+ , m_rowCount(rowCount)
+{
+ QAction *action = new QAction(tr("New Slide"));
+ action->setEnabled(!master);
+ connect(action, &QAction::triggered, this, &SlideContextMenu::handleAddNewSlide);
+ addAction(action);
+
+ action = new QAction(tr("Delete Slide"));
+ action->setEnabled(!master && m_row != -1);
+ connect(action, &QAction::triggered, this, &SlideContextMenu::handleRemoveSlide);
+ addAction(action);
+
+ action = new QAction(tr("Duplicate Slide"));
+ action->setEnabled(!master && m_row != -1);
+ connect(action, &QAction::triggered, this, &SlideContextMenu::handleDuplicateSlide);
+ addAction(action);
+}
+
+SlideContextMenu::~SlideContextMenu()
+{
+}
+
+void SlideContextMenu::handleAddNewSlide()
+{
+ m_view->addNewSlide(m_row == -1 ? m_rowCount : m_row + 1);
+}
+
+void SlideContextMenu::handleRemoveSlide()
+{
+ m_view->removeSlide(m_row);
+}
+
+void SlideContextMenu::handleDuplicateSlide()
+{
+ m_view->duplicateSlide(m_row);
+}
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideContextMenu.h b/src/Authoring/Studio/Palettes/Slide/SlideContextMenu.h
new file mode 100644
index 00000000..bb4bb864
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Slide/SlideContextMenu.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SLIDE_CONTEXT_MENU_H
+#define SLIDE_CONTEXT_MENU_H
+
+#include <QtWidgets/qmenu.h>
+
+class SlideView;
+
+class SlideContextMenu : public QMenu
+{
+ Q_OBJECT
+public:
+ explicit SlideContextMenu(SlideView *parent, int row, int rowCount, bool master);
+ virtual ~SlideContextMenu();
+
+private Q_SLOTS:
+ void handleAddNewSlide();
+ void handleRemoveSlide();
+ void handleDuplicateSlide();
+
+private:
+ SlideView *m_view;
+ int m_row;
+ int m_rowCount;
+};
+#endif // SLIDE_CONTEXT_MENU_H
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp b/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp
new file mode 100644
index 00000000..d2ef842c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "SlideModel.h"
+
+#include "CmdActivateSlide.h"
+#include "Core.h"
+#include "Doc.h"
+#include "StudioApp.h"
+
+#include "IDocumentEditor.h"
+
+#include "ClientDataModelBridge.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMSlides.h"
+
+SlideModel::SlideModel(int slideCount, QObject *parent) : QAbstractListModel(parent)
+ , m_slides(slideCount)
+{
+
+}
+
+QVariant SlideModel::data(const QModelIndex &index, int role) const
+{
+ if (!hasIndex(index.row(), index.column(),index.parent()))
+ return {};
+
+ const auto row = index.row();
+
+ switch (role) {
+ case NameRole:
+ return slideName(m_slides[row]);
+ case SelectedRole:
+ return row == m_selectedRow;
+ }
+
+ return {};
+}
+
+bool SlideModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!hasIndex(index.row(), index.column(),index.parent()))
+ return false;
+
+ auto &slideHandle = m_slides[index.row()];
+
+ switch (role) {
+ case NameRole: {
+ setSlideName(slideHandle, value.toString());
+ Q_EMIT dataChanged(index, index, {role});
+ break;
+ }
+ case HandleRole: {
+ slideHandle = value.value<UICDM::CUICDMSlideHandle>();
+ Q_EMIT dataChanged(index, index, {HandleRole, NameRole});
+ break;
+ }
+ case SelectedRole: {
+ m_selectedRow = value.toBool() ? index.row() : -1;
+
+ if (m_selectedRow != -1) {
+ CCmdActivateSlide *theCmd = new CCmdActivateSlide(GetDoc(), m_slides[m_selectedRow]);
+ g_StudioApp.GetCore()->ExecuteCommand(theCmd);
+ }
+
+ Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), {role});
+ return true;
+ }
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+int SlideModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return m_slides.count();
+}
+
+QHash<int, QByteArray> SlideModel::roleNames() const
+{
+ auto names = QAbstractListModel::roleNames();
+ names.insert(NameRole, "name");
+ names.insert(SelectedRole, "selected");
+
+ return names;
+}
+
+bool SlideModel::insertRows(int row, int count, const QModelIndex &parent)
+{
+ if (row > m_slides.count())
+ return false;
+
+ beginInsertRows(parent, row, row + count - 1);
+ for (int i = 0; i < count; i++)
+ m_slides.insert(row, {});
+ endInsertRows();
+
+ setData(index(row + count - 1), true, SelectedRole);
+ return true;
+}
+
+bool SlideModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ if (row + count > m_slides.count())
+ return false;
+
+ bool selectionRemoved = false;
+ beginRemoveRows(parent, row, row + count - 1);
+ for (int i = 0; i < count; i++) {
+ if (m_selectedRow == row)
+ selectionRemoved = true;
+ m_slides.removeAt(row);
+ }
+ endRemoveRows();
+
+ auto newSelectedRow = -1;
+ if (selectionRemoved) {
+ if (row > 0)
+ newSelectedRow = row - 1;
+ else
+ newSelectedRow = row + count - 1;
+ } else if (m_selectedRow >= m_slides.count()) {
+ newSelectedRow = m_slides.count() - 1;
+ }
+ if (newSelectedRow != -1)
+ setData(index(newSelectedRow), true, SelectedRole);
+
+ return true;
+}
+
+void SlideModel::duplicateRow(int row)
+{
+ const auto handle = m_slides[row];
+
+ beginInsertRows({}, row, row);
+ m_slides.insert(row + 1, Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(),
+ QObject::tr("Duplicate Slide"))
+ ->DuplicateSlide(handle));
+ endInsertRows();
+ setData(index(row + 1), true, SelectedRole);
+
+ Q_EMIT dataChanged(index(row, 0), index(row + 1, 0), {});
+}
+
+void SlideModel::move(int fromRow, int toRow)
+{
+ if (fromRow == toRow)
+ return;
+
+ auto handle = m_slides[fromRow];
+ // toRow + 1 as DocumentEditor uses 1 based indexes for slides
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Rearrange Slide"))
+ ->RearrangeSlide(handle, toRow + 1);
+
+ if (fromRow > toRow)
+ beginMoveRows({}, fromRow, fromRow, {}, toRow);
+ else
+ beginMoveRows({}, fromRow, fromRow, {}, toRow + 1);
+ m_slides.move(fromRow, toRow);
+ endMoveRows();
+}
+
+void SlideModel::clear()
+{
+ beginResetModel();
+ m_slides.clear();
+ endResetModel();
+}
+
+void SlideModel::addNewSlide(int row)
+{
+ const auto handle = (row < m_slides.size()) ? m_slides[row] : m_slides.last();
+
+ const auto instanceHandle = GetBridge()->GetOwningComponentInstance(handle);
+ UICDM::CUICDMSlideHandle theMasterSlide = GetBridge()->GetComponentSlide(instanceHandle, 0);
+
+ beginInsertRows({}, row, row);
+ m_slides.insert(row, Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(),
+ QObject::tr("Create Slide"))
+ ->AddSlide(theMasterSlide, row + 1));
+ endInsertRows();
+
+ setData(index(row), true, SelectedRole);
+}
+
+void SlideModel::removeSlide(int row)
+{
+ const auto handle = m_slides[row];
+
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*GetDoc(), QObject::tr("Delete Slide"))->DeleteSlide(handle);
+ removeRows(row, 1);
+}
+
+bool SlideModel::hasSlideWithName(const QString &name) const
+{
+ for (const auto &slide: m_slides) {
+ if (slideName(slide) == name)
+ return true;
+ }
+ return false;
+}
+
+QString SlideModel::slideName(const UICDM::CUICDMSlideHandle &handle) const
+{
+ auto doc = GetDoc();
+ if (!doc->IsValid())
+ return {};
+ const auto instanceHandle = doc->GetStudioSystem()->GetSlideSystem()->GetSlideInstance(handle);
+ return GetBridge()->GetName(instanceHandle).toQString();
+}
+
+void SlideModel::setSlideName(const UICDM::CUICDMSlideHandle &handle, const QString &name)
+{
+ const auto oldName = slideName(handle);
+ if (oldName != name && !name.trimmed().isEmpty()) {
+ using namespace UICDM;
+ CDoc *theDoc = GetDoc();
+ CClientDataModelBridge *theBridge = GetBridge();
+ if (!theBridge)
+ return;
+ const auto instanceHandle = GetDoc()->GetStudioSystem()->
+ GetSlideSystem()->GetSlideInstance(handle);
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*theDoc, QObject::tr("Set Slide Name"))
+ ->SetSlideName(instanceHandle, theBridge->GetNameProperty(),
+ Q3DStudio::CString::fromQString(oldName),
+ Q3DStudio::CString::fromQString(name));
+ }
+}
+
+CDoc *SlideModel::GetDoc() const
+{
+ return g_StudioApp.GetCore()->GetDoc();
+}
+
+CClientDataModelBridge *SlideModel::GetBridge() const
+{
+ auto doc = GetDoc();
+ if (!doc->IsValid())
+ return nullptr;
+ return doc->GetStudioSystem()->GetClientDataModelBridge();
+}
+
+
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideModel.h b/src/Authoring/Studio/Palettes/Slide/SlideModel.h
new file mode 100644
index 00000000..659fc548
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Slide/SlideModel.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SLIDEMODEL_H
+#define SLIDEMODEL_H
+
+#include <QAbstractListModel>
+
+#include "UICDMHandles.h"
+
+class CClientDataModelBridge;
+class CDoc;
+
+class SlideModel : public QAbstractListModel
+{
+ Q_OBJECT
+public:
+ enum Roles {
+ NameRole = Qt::DisplayRole,
+ HandleRole = Qt::UserRole + 1,
+ SelectedRole
+ };
+
+ SlideModel(int slideCount, QObject *parent = nullptr);
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ bool setData(const QModelIndex &index, const QVariant &value,
+ int role = Qt::DisplayRole) override;
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QHash<int, QByteArray> roleNames() const override;
+
+ bool insertRows(int row, int count,
+ const QModelIndex &parent = QModelIndex()) override;
+ bool removeRows(int row, int count,
+ const QModelIndex &parent = QModelIndex()) override;
+ void duplicateRow(int row);
+ void move(int fromRow, int toRow);
+
+ void clear();
+ void addNewSlide(int row);
+ void removeSlide(int row);
+
+private:
+ bool hasSlideWithName(const QString &name) const;
+ QString slideName(const UICDM::CUICDMSlideHandle &handle) const;
+ void setSlideName(const UICDM::CUICDMSlideHandle &handle, const QString &name);
+ inline CDoc *GetDoc() const;
+ inline CClientDataModelBridge *GetBridge() const;
+
+ QVector<UICDM::CUICDMSlideHandle> m_slides;
+ int m_selectedRow = -1;
+};
+
+
+#endif // SLIDEMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.cpp b/src/Authoring/Studio/Palettes/Slide/SlideView.cpp
new file mode 100644
index 00000000..08b38a2c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Slide/SlideView.cpp
@@ -0,0 +1,315 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "SlideView.h"
+#include "CColor.h"
+#include "Core.h"
+#include "Dispatch.h"
+#include "Doc.h"
+#include "Literals.h"
+#include "StudioPreferences.h"
+#include "SlideModel.h"
+#include "StudioApp.h"
+#include "StudioUtils.h"
+#include "SlideContextMenu.h"
+
+#include "ClientDataModelBridge.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMSlides.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qtimer.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlengine.h>
+
+SlideView::SlideView(QWidget *parent) : QQuickWidget(parent)
+ , m_MasterSlideModel(new SlideModel(1, this))
+ , m_SlidesModel(new SlideModel(0, this))
+ , m_ActiveRoot(0)
+{
+ g_StudioApp.GetCore()->GetDispatch()->AddPresentationChangeListener(this);
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ m_CurrentModel = m_SlidesModel;
+ QTimer::singleShot(0, this, &SlideView::initialize);
+}
+
+SlideView::~SlideView()
+{
+ clearSlideList();
+ g_StudioApp.GetCore()->GetDispatch()->RemovePresentationChangeListener(this);
+}
+
+bool SlideView::showMasterSlide() const
+{
+ return m_CurrentModel == m_MasterSlideModel;
+}
+
+void SlideView::setShowMasterSlide(bool show)
+{
+ const bool currentIsMaster = m_CurrentModel == m_MasterSlideModel;
+ if (show == currentIsMaster)
+ return;
+
+ if (show)
+ m_CurrentModel = m_MasterSlideModel;
+ else
+ m_CurrentModel = m_SlidesModel;
+
+ // We need to get the first slide in the correct master mode
+ CDoc *theDoc = GetDoc();
+ UICDM::CUICDMInstanceHandle theRoot = theDoc->GetActiveRootInstance();
+ CClientDataModelBridge *theBridge = GetBridge();
+ UICDM::CUICDMSlideHandle theNewActiveSlide =
+ theBridge->GetOrCreateGraphRoot(theRoot); // this will return the master slide
+ UICDM::ISlideSystem *theSlideSystem = theDoc->GetStudioSystem()->GetSlideSystem();
+ if (m_CurrentModel != m_MasterSlideModel) {
+ const auto theFind = m_MasterSlideReturnPointers.find(theNewActiveSlide);
+ size_t theSlideIndex = 1;
+ size_t theNumSlides = theSlideSystem->GetSlideCount(theNewActiveSlide);
+ if (theFind != m_MasterSlideReturnPointers.end() && theFind->second < theNumSlides)
+ theSlideIndex = theFind->second;
+
+ theNewActiveSlide = theSlideSystem->GetSlideByIndex(
+ theNewActiveSlide, theSlideIndex); // activate the first slide
+ } else {
+ int theIndex = theSlideSystem->GetActiveSlideIndex(theNewActiveSlide);
+ m_MasterSlideReturnPointers[theNewActiveSlide] = theIndex;
+ }
+
+ // We have forced a mode change, and so we need to set the current active TC
+ // to be in the correct mode so our slide palette will show the correct information
+ if (theNewActiveSlide.Valid()) {
+ theDoc->NotifyActiveSlideChanged(theNewActiveSlide);
+ }
+
+ Q_EMIT showMasterSlideChanged();
+ Q_EMIT currentModelChanged();
+}
+
+QSize SlideView::sizeHint() const
+{
+ return {150, 200};
+}
+
+void SlideView::deselectAll()
+{
+ g_StudioApp.GetCore()->GetDoc()->DeselectAllItems();
+}
+
+void SlideView::addNewSlide(int row)
+{
+ m_SlidesModel->addNewSlide(row);
+}
+
+void SlideView::removeSlide(int row)
+{
+ m_SlidesModel->removeSlide(row);
+}
+
+void SlideView::duplicateSlide(int row)
+{
+ m_SlidesModel->duplicateRow(row);
+}
+
+void SlideView::moveSlide(int from, int to)
+{
+ m_SlidesModel->move(from, to);
+}
+
+void SlideView::showContextMenu(int x, int y, int row)
+{
+ SlideContextMenu contextMenu(this, row, m_SlidesModel->rowCount(),
+ m_CurrentModel == m_MasterSlideModel);
+ contextMenu.exec(mapToGlobal({x, y}));
+}
+
+void SlideView::OnNewPresentation()
+{
+ // Register callbacks
+ UICDM::IStudioFullSystemSignalProvider *theSignalProvider =
+ g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetFullSystemSignalProvider();
+ m_MasterSlideReturnPointers.clear();
+
+ m_Connections.push_back(theSignalProvider->ConnectActiveSlide(
+ std::bind(&SlideView::OnActiveSlide, this, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3)));
+
+ // KDAB_TODO We most probably don't need to listen to the below signals,
+ // as the functionality is done in the model already. Remove after it is confirmed
+ // it works as desired when the rendering works.
+ m_Connections.push_back(theSignalProvider->ConnectSlideCreated(
+ std::bind(&SlideView::OnNewSlide, this, std::placeholders::_1)));
+ m_Connections.push_back(theSignalProvider->ConnectSlideDeleted(
+ std::bind(&SlideView::OnDeleteSlide, this, std::placeholders::_1)));
+ m_Connections.push_back(theSignalProvider->ConnectSlideRearranged(
+ std::bind(&SlideView::OnSlideRearranged, this, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3)));
+}
+
+void SlideView::OnClosingPresentation()
+{
+ m_Connections.clear();
+ clearSlideList();
+}
+
+void SlideView::OnActiveSlide(const UICDM::CUICDMSlideHandle &inMaster, int inIndex,
+ const UICDM::CUICDMSlideHandle &inSlide)
+{
+ // When the active slide changes, we need to update our button and mode
+ if (inMaster.Valid()) {
+ // if inIndex is 0, it means that we are activating master slide
+ setShowMasterSlide(inIndex == 0);
+ setActiveSlide(inSlide);
+ }
+}
+
+void SlideView::OnNewSlide(const UICDM::CUICDMSlideHandle &inSlide)
+{
+
+}
+
+void SlideView::OnDeleteSlide(const UICDM::CUICDMSlideHandle &inSlide)
+{
+
+}
+
+void SlideView::OnSlideRearranged(const UICDM::CUICDMSlideHandle &inMaster, int inOldIndex, int inNewIndex)
+{
+}
+
+void SlideView::initialize()
+{
+ CStudioPreferences::setQmlContextProperties(rootContext());
+ rootContext()->setContextProperty("_slideView"_L1, this);
+ rootContext()->setContextProperty("_resDir"_L1, resourceImageUrl());
+
+ engine()->addImportPath(qmlImportPath());
+ setSource(QUrl("qrc:/Studio/Palettes/Slide/SlideView.qml"_L1));
+}
+
+void SlideView::clearSlideList()
+{
+ m_ActiveRoot = 0;
+ m_SlidesModel->clear();
+}
+
+void SlideView::setActiveSlide(const UICDM::CUICDMSlideHandle &inActiveSlideHandle)
+{
+ // Make sure we are in the correct master mode based on the inActiveSlideHandle
+ // If we changed mode, then we need to force a rebuild
+ bool theRebuildFlag = isMaster(inActiveSlideHandle) && (m_CurrentModel != m_MasterSlideModel);
+
+ // Check to see if the incoming slide is a sibling of the current active slide
+ // If it is, then we may be able to update without rebuilding everything
+ if (!theRebuildFlag
+ && m_ActiveRoot == GetBridge()->GetOwningComponentInstance(inActiveSlideHandle)) {
+ // If this is a new active slide, but the same root parent
+ if (m_ActiveSlideHandle != inActiveSlideHandle) {
+ m_ActiveSlideHandle = inActiveSlideHandle;
+ }
+ } else {
+ // We have a new parent or a new slide that makes us rebuild the entire list
+ rebuildSlideList(inActiveSlideHandle);
+ }
+}
+
+void SlideView::rebuildSlideList(const UICDM::CUICDMSlideHandle &inActiveSlideHandle)
+{
+ // Clear out the existing slides
+ clearSlideList();
+
+ // Add new slide controls as required
+ if (inActiveSlideHandle.Valid()) {
+ m_ActiveSlideHandle = inActiveSlideHandle;
+ m_ActiveRoot = GetBridge()->GetOwningComponentInstance(inActiveSlideHandle);
+
+ // Get the Master Slide handle and the slide count
+ UICDM::ISlideSystem *theSlideSystem = GetSlideSystem();
+ UICDM::CUICDMSlideHandle theMasterSlide =
+ theSlideSystem->GetMasterSlide(inActiveSlideHandle);
+
+ // update handle for master slide
+ UICDM::CUICDMSlideHandle theMasterSlideHandle =
+ theSlideSystem->GetSlideByIndex(theMasterSlide, 0);
+ m_MasterSlideModel->setData(m_MasterSlideModel->index(0, 0),
+ QVariant::fromValue(theMasterSlideHandle),
+ SlideModel::HandleRole);
+
+ long theSlideCount = (long)theSlideSystem->GetSlideCount(theMasterSlide);
+
+ // Iterate through, creating the new slide controls
+ m_SlidesModel->clear();
+ m_SlidesModel->insertRows(0, theSlideCount - 1, {});
+ int row = 0;
+ for (long theSlideIndex = 1; theSlideIndex < theSlideCount; ++theSlideIndex) {
+ UICDM::CUICDMSlideHandle theSlideHandle =
+ theSlideSystem->GetSlideByIndex(theMasterSlide, theSlideIndex);
+ auto index = m_SlidesModel->index(row, 0);
+ m_SlidesModel->setData(index,
+ QVariant::fromValue(theSlideHandle),
+ SlideModel::HandleRole);
+ const auto instanceHandle =
+ GetDoc()->GetStudioSystem()->GetSlideSystem()->GetSlideInstance(theSlideHandle);
+ m_SlidesModel->setData(index,
+ GetBridge()->GetName(instanceHandle).toQString(),
+ SlideModel::NameRole);
+ // This slide is the active slide
+ if (theSlideHandle == m_ActiveSlideHandle) {
+ m_SlidesModel->setData(index, true, SlideModel::SelectedRole);
+ }
+ row++;
+ }
+ }
+}
+
+CDoc *SlideView::GetDoc()
+{
+ return g_StudioApp.GetCore()->GetDoc();
+}
+
+CClientDataModelBridge *SlideView::GetBridge()
+{
+ return GetDoc()->GetStudioSystem()->GetClientDataModelBridge();
+}
+
+UICDM::ISlideSystem *SlideView::GetSlideSystem()
+{
+ return GetDoc()->GetStudioSystem()->GetSlideSystem();
+}
+
+long SlideView::GetSlideIndex(const UICDM::CUICDMSlideHandle &inSlideHandle)
+{
+ return GetSlideSystem()->GetSlideIndex(inSlideHandle);
+}
+
+bool SlideView::isMaster(const UICDM::CUICDMSlideHandle &inSlideHandle)
+{
+ return (0 == GetSlideIndex(inSlideHandle));
+}
+
+
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.h b/src/Authoring/Studio/Palettes/Slide/SlideView.h
new file mode 100644
index 00000000..a4347ddd
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Slide/SlideView.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SLIDEVIEW_H
+#define SLIDEVIEW_H
+
+#include <QQuickWidget>
+
+#include "DispatchListeners.h"
+#include "SlideModel.h"
+
+#include "UICDMHandles.h"
+#include "UICDMSignals.h"
+#include <unordered_map>
+class CClientDataModelBridge;
+class CDoc;
+
+namespace UICDM {
+class ISlideSystem;
+}
+
+class SlideView : public QQuickWidget, public CPresentationChangeListener
+{
+ Q_OBJECT
+ Q_PROPERTY(QAbstractItemModel *currentModel READ currentModel NOTIFY currentModelChanged FINAL)
+ Q_PROPERTY(bool showMasterSlide READ showMasterSlide WRITE setShowMasterSlide NOTIFY showMasterSlideChanged FINAL)
+public:
+ SlideView(QWidget *parent = nullptr);
+ ~SlideView();
+
+ bool showMasterSlide() const;
+ void setShowMasterSlide(bool show);
+ QAbstractItemModel *currentModel() { return m_CurrentModel; }
+ QSize sizeHint() const override;
+
+ Q_INVOKABLE void deselectAll();
+ Q_INVOKABLE void addNewSlide(int row);
+ Q_INVOKABLE void removeSlide(int row);
+ Q_INVOKABLE void duplicateSlide(int row);
+ Q_INVOKABLE void moveSlide(int from, int to);
+ Q_INVOKABLE void showContextMenu(int x, int y, int row);
+
+ // Presentation Change Listener
+ void OnNewPresentation() override;
+ void OnClosingPresentation() override;
+
+Q_SIGNALS:
+ void currentModelChanged();
+ void showMasterSlideChanged();
+
+
+protected:
+ // UICDM callbacks
+ virtual void OnActiveSlide(const UICDM::CUICDMSlideHandle &inMaster, int inIndex,
+ const UICDM::CUICDMSlideHandle &inSlide);
+ virtual void OnNewSlide(const UICDM::CUICDMSlideHandle &inSlide);
+ virtual void OnDeleteSlide(const UICDM::CUICDMSlideHandle &inSlide);
+ virtual void OnSlideRearranged(const UICDM::CUICDMSlideHandle &inMaster, int inOldIndex,
+ int inNewIndex);
+
+private:
+ void initialize();
+ void clearSlideList();
+ void setActiveSlide(const UICDM::CUICDMSlideHandle &inActiveSlideHandle);
+ inline CDoc *GetDoc();
+ inline CClientDataModelBridge *GetBridge();
+ inline UICDM::ISlideSystem *GetSlideSystem();
+ long GetSlideIndex(const UICDM::CUICDMSlideHandle &inSlideHandle);
+ bool isMaster(const UICDM::CUICDMSlideHandle &inSlideHandle);
+ void rebuildSlideList(const UICDM::CUICDMSlideHandle &inActiveSlideHandle);
+
+ SlideModel *m_CurrentModel = nullptr;
+ SlideModel *m_MasterSlideModel = nullptr;
+ SlideModel *m_SlidesModel = nullptr;
+ QColor m_BaseColor = QColor::fromRgb(75, 75, 75);
+ std::vector<std::shared_ptr<UICDM::ISignalConnection>>
+ m_Connections; /// connections to the UICDM
+ typedef std::unordered_map<int, int> TIntIntMap;
+ // We need to remember which slide we were on when we entered the master slide.
+ // Then, when the users leave the master slide we can go back to roughly the same
+ // state.
+ TIntIntMap m_MasterSlideReturnPointers;
+
+ UICDM::CUICDMInstanceHandle m_ActiveRoot; ///< the object containing the slides to be inspected.
+ UICDM::CUICDMSlideHandle m_ActiveSlideHandle; ///< the active slide handle
+};
+
+#endif // SLIDEVIEW_H
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.qml b/src/Authoring/Studio/Palettes/Slide/SlideView.qml
new file mode 100644
index 00000000..7bffcad3
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Slide/SlideView.qml
@@ -0,0 +1,249 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.1
+import "../controls"
+
+Rectangle {
+
+ id: root
+
+ readonly property bool masterSlide: _slideView.showMasterSlide
+
+ color: _backgroundColor
+
+ MouseArea {
+ id: mainMouseArea
+
+ propagateComposedEvents: true
+ anchors.fill: parent
+ acceptedButtons: Qt.AllButtons
+ onClicked: {
+ if (mouse.button === Qt.RightButton) {
+ _slideView.showContextMenu(mouse.x, mouse.y, -1);
+ } else {
+ root.focus = true;
+ //Unselect All element when we click outside slider item in listView.
+ //It worked as it in old version.
+ _slideView.deselectAll();
+ mouse.accepted = false
+ }
+ }
+ }
+
+ Column {
+ anchors {
+ top: parent.top
+ topMargin: 5
+ horizontalCenter: parent.horizontalCenter
+ }
+
+ spacing: 5
+
+ Column {
+ id: masterButtonColumn
+ spacing: -4
+ anchors.horizontalCenter: parent.horizontalCenter
+ Button {
+ id: masterEditButton
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ onClicked: _slideView.showMasterSlide = !_slideView.showMasterSlide
+
+ background: Rectangle {
+ color: "transparent"
+ }
+ contentItem: Image {
+ source: _resDir + "Slide-Master-Active.png"
+ }
+ }
+ StyledLabel {
+ id: masterEditLabel
+ text: _slideView.showMasterSlide ? qsTr("Leave Master") : qsTr("Edit Master")
+ font.pixelSize: _fontSize
+ color: _masterColor
+ verticalAlignment: Text.AlignVCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ }
+
+ StyledMenuSeparator {
+ id: separator
+ leftPadding: 12
+ rightPadding: 12
+ }
+
+ ListView {
+ id: slideList
+
+ ScrollBar.vertical: ScrollBar {}
+
+ width: root.width
+ height: root.height - masterButtonColumn.height
+ - separator.height - parent.spacing * 2 - 10
+ anchors.horizontalCenter: parent.horizontalCenter
+ boundsBehavior: Flickable.StopAtBounds
+ clip: true
+
+ model: _slideView.currentModel
+ spacing: 10
+
+
+ delegate: MouseArea {
+ id: delegateArea
+
+ property int dragIndex
+ property bool held : false
+
+ anchors.horizontalCenter: parent.horizontalCenter
+ height: delegateItem.height
+ width: parent.width
+
+ acceptedButtons: Qt.RightButton | Qt.LeftButton
+ drag.target: held ? delegateItem : null
+ drag.axis: Drag.YAxis
+
+
+ onPressed: {
+ dragIndex = model.index;
+ if (mouse.x > delegateItem.x && mouse.x < delegateItem.x + delegateItem.width)
+ held = true;
+ }
+ onReleased: held = false
+
+
+ onClicked: {
+ _slideView.deselectAll();
+ if (mouse.button === Qt.LeftButton) {
+ root.focus = true;
+ model.selected = true;
+ }
+ if (mouse.button === Qt.RightButton) {
+ const coords = mapToItem(root, mouse.x, mouse.y);
+ _slideView.showContextMenu(coords.x, coords.y, model.index);
+ }
+ }
+
+ Item {
+ id: delegateItem
+
+ anchors.centerIn: parent
+ height: column.implicitHeight
+ width: 100
+
+ Drag.keys: "application/x-slide"
+ Drag.active: delegateArea.held
+ Drag.hotSpot.x: width / 2
+ Drag.hotSpot.y: height / 2
+ Drag.source: delegateArea
+
+ Column {
+ id: column
+ spacing: 2
+ anchors.fill: parent
+ Image {
+ id: slideImage
+
+ source: {
+ if (masterSlide)
+ return _resDir + "Slide-Master-Active.png"
+ return model.selected ? _resDir + "Slide-Active.png"
+ : _resDir + "Slide-Normal.png";
+ }
+ }
+
+ Item {
+ anchors.horizontalCenter: slideImage.horizontalCenter
+
+ height: childrenRect.height
+ width: childrenRect.width
+ Row {
+ StyledLabel {
+ visible: !masterSlide
+ text: model.index + 1 + ": "
+ }
+
+ TextInput {
+ id: slideName
+
+ readOnly: masterSlide
+ selectByMouse: !readOnly
+ color: _textColor
+ text: model.name
+ font.pixelSize: _fontSize
+
+ onFocusChanged: {
+ if (focus && !readOnly)
+ selectAll();
+ }
+
+ onEditingFinished: {
+ model.name = text;
+ slideName.focus = false;
+ }
+
+ Keys.onEscapePressed: {
+ slideName.undo();
+ slideName.focus = false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ DropArea {
+ anchors.fill: parent
+ keys: "application/x-slide"
+ onEntered: {
+ var oldIndex = drag.source.dragIndex
+ var newIndex = model.index
+ _slideView.moveSlide(oldIndex, newIndex)
+ drag.source.dragIndex = newIndex
+ }
+ }
+
+ states: State {
+ when: held
+
+ ParentChange {
+ target: delegateItem
+ parent: slideList
+ }
+
+ PropertyChanges {
+ target: delegateItem
+ anchors.centerIn: null
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.cpp b/src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.cpp
new file mode 100644
index 00000000..48fe8993
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "AreaBoundingRect.h"
+#include "Renderer.h"
+#include "CColor.h"
+
+//=============================================================================
+/**
+ * Draws the rectangle.
+ */
+void CAreaBoundingRect::Draw(CRenderer *inRenderer)
+{
+ CPt theSize = GetSize();
+ inRenderer->PushPen(CColor(89, 120, 223));
+
+ // Removed because alpha doesn't work on Mac
+ // CColor theOverlayColor( 184, 198, 246 );
+ // inRenderer->FillSolidRect( CPt( theSize.x - 1, theSize.y - 1 ) ), theOverlayColor );
+
+ // Draw the rectangle outline
+ if (theSize.y > 1 && theSize.x > 1) {
+ inRenderer->MoveTo(CPt(0, 0));
+ inRenderer->LineTo(CPt(0, theSize.y - 1));
+ inRenderer->LineTo(CPt(theSize.x - 1, theSize.y - 1));
+ inRenderer->LineTo(CPt(theSize.x - 1, 0));
+ inRenderer->LineTo(CPt(0, 0));
+ }
+ inRenderer->PopPen();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.h b/src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.h
new file mode 100644
index 00000000..1ec98c55
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_AREA_BOUNDING_RECT
+#define INCLUDED_AREA_BOUNDING_RECT 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "OverlayControl.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CRenderer;
+
+class CAreaBoundingRect : public COverlayControl
+{
+public:
+ virtual ~CAreaBoundingRect(){}
+ void Draw(CRenderer *inRenderer) override;
+
+protected:
+};
+#endif // INCLUDED_AREA_BOUNDING_RECT
diff --git a/src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.cpp
new file mode 100644
index 00000000..c0541fac
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.cpp
@@ -0,0 +1,440 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "AssetTimelineKeyframe.h"
+#include "StateTimebarlessRow.h"
+#include "Renderer.h"
+#include "MasterP.h"
+#include "StateRow.h"
+#include "KeyframeContextMenu.h"
+#include "HotKeys.h"
+#include "ResourceCache.h"
+#include "ITimelineControl.h"
+#include "Bindings/ITimelineItemBinding.h"
+#include "StudioUtils.h"
+#include "TimeEditDlg.h"
+
+CAssetTimelineKeyframe::CAssetTimelineKeyframe(CStateTimebarlessRow *inParentRow,
+ double inTimeRatio)
+ : m_Selected(false)
+ , m_ParentRow(inParentRow)
+ , m_IsMouseDown(false)
+ , m_IsDragging(false)
+ , m_TimeRatio(inTimeRatio)
+{
+ CResourceCache *theCache = CResourceCache::GetInstance();
+ m_Icon = theCache->GetBitmap("Keyframe-Master-Normal.png");
+ m_DisabledIcon = theCache->GetBitmap("Keyframe-Master-Disabled.png");
+ m_SelectedIcon = theCache->GetBitmap("Keyframe-Master-Selected.png");
+ m_DynamicIcon = theCache->GetBitmap("Keyframe-MasterDynamic-Normal.png");
+ m_DynamicSelectedIcon = theCache->GetBitmap("Keyframe-MasterDynamic-Selected.png");
+
+ m_RightIcon = theCache->GetBitmap("Keyframe-MasterRight-Normal.png");
+ m_RightDisabledIcon = theCache->GetBitmap("Keyframe-MasterRight-disabled.png");
+ m_RightSelectedIcon = theCache->GetBitmap("Keyframe-MasterRight-Selected.png");
+ m_RightDynamicIcon = theCache->GetBitmap("Keyframe-MasterRightDynamic-Normal.png");
+ m_RightDynamicSelectedIcon = theCache->GetBitmap("Keyframe-MasterRightDynamic-Selected.png");
+
+ m_LeftIcon = theCache->GetBitmap("Keyframe-MasterLeft-Normal.png");
+ m_LeftDisabledIcon = theCache->GetBitmap("Keyframe-MasterLeft-disabled.png");
+ m_LeftSelectedIcon = theCache->GetBitmap("Keyframe-MasterLeft-Selected.png");
+ m_LeftDynamicIcon = theCache->GetBitmap("Keyframe-MasterLeftDynamic-Normal.png");
+ m_LeftDynamicSelectedIcon = theCache->GetBitmap("Keyframe-MasterLeftDynamic-Selected.png");
+
+ m_RectOverHandled = false;
+ m_PreviousSelectState = false;
+}
+
+CAssetTimelineKeyframe::~CAssetTimelineKeyframe()
+{
+}
+
+//=============================================================================
+/**
+ * SetRectOverHandled: Sets if mouse rectangle has been handled
+ * param@ inState indicates if the rectangle over has been handled.
+ * return@ NONE
+ */
+
+void CAssetTimelineKeyframe::SetRectOverHandled(bool inState)
+{
+ m_RectOverHandled = inState;
+}
+
+//=============================================================================
+/**
+ * GetRectOverHandled: GetRectOverHandled
+ * param@ NONE
+ * return@ m_RectOverHandled, which indicates if the rectangle over has been handled
+ */
+bool CAssetTimelineKeyframe::GetRectOverHandled()
+{
+ return m_RectOverHandled;
+}
+
+//=============================================================================
+/**
+ * SetPreviousSelectState: Sets if the current keyframe was previously selected
+ * param@ inState is used to set m_PreviousSelectState.
+ * return@ NONE
+ */
+void CAssetTimelineKeyframe::SetPreviousSelectState(bool inState)
+{
+ m_PreviousSelectState = inState;
+}
+
+//=============================================================================
+/**
+ * GetPreviousSelectState: Returns the keyframe's previous select state
+ * param@ NONE
+ * return@ m_PreviousSelectState that stores the select state for the keyframe
+ */
+bool CAssetTimelineKeyframe::GetPreviousSelectState()
+{
+ return m_PreviousSelectState;
+}
+
+//=============================================================================
+/**
+* Updates the ToolTip and moves it to the correct place on screen.
+* @param inPoint the point that the tooltip is supposed to be placed.
+*/
+void CAssetTimelineKeyframe::RefreshToolTip(CPt inPoint)
+{
+ Q3DStudio::CString theCommentText;
+ CStateRow *theStateRow = m_ParentRow->GetStateRow();
+ CRct theTimelineBounds(theStateRow->GetTopControl()->GetBounds());
+
+ // format label
+ theCommentText = " " + ::FormatTimeString(GetTime());
+
+ inPoint.y = GetPosition().y - GetSize().y;
+ inPoint.x = GetSize().x / 2;
+ ShowMoveableWindow(inPoint, theCommentText, theTimelineBounds);
+}
+
+//=============================================================================
+/**
+ * Gets the correct image and draws
+ */
+void CAssetTimelineKeyframe::Draw(CRenderer *inRenderer)
+{
+ inRenderer->DrawBitmap(CPt(0, 0), GetImage());
+}
+
+//=============================================================================
+/**
+ * Gets the name of the current bitmap depending on the state of the button,
+ * postion of the mouse, etc. Returns name of the image for the up state by
+ * default.
+ * @return name of the image representing current state of the button
+ */
+QPixmap CAssetTimelineKeyframe::GetImage() const
+{
+ QPixmap theImage = m_Icon;
+ long theStartTime = m_ParentRow->GetStateRow()->GetStartTime();
+ long theEndTime = m_ParentRow->GetStateRow()->GetEndTime();
+
+ if (theStartTime == m_Time) {
+ theImage = m_LeftIcon;
+ if (!IsEnabled())
+ theImage = m_LeftDisabledIcon;
+ else if (m_IsDynamic) {
+ if (m_Selected)
+ return m_LeftDynamicSelectedIcon;
+ else
+ return m_LeftDynamicIcon;
+ } else if (m_Selected)
+ theImage = m_LeftSelectedIcon;
+ } else if (theEndTime == m_Time) {
+ theImage = m_RightIcon;
+ if (!IsEnabled())
+ theImage = m_RightDisabledIcon;
+ else if (m_IsDynamic) {
+ if (m_Selected)
+ return m_RightDynamicSelectedIcon;
+ else
+ return m_RightDynamicIcon;
+ } else if (m_Selected)
+ theImage = m_RightSelectedIcon;
+ } else {
+ if (!IsEnabled())
+ theImage = m_DisabledIcon;
+ else if (m_IsDynamic) {
+ if (m_Selected)
+ return m_DynamicSelectedIcon;
+ else
+ return m_DynamicIcon;
+ } else if (m_Selected)
+ theImage = m_SelectedIcon;
+ }
+ return theImage;
+}
+
+//=============================================================================
+/**
+ * @return true if the mouse is over the keyframe
+ * @param inPoint the point where the mouse is
+ */
+bool CAssetTimelineKeyframe::HitTest(const CPt &inPoint) const
+{
+ bool theRetVal = false;
+ // If not over the control then don't bother with specific checks
+ if (CControl::HitTest(inPoint)) {
+ // If the key is at the beginning or end of the timebar then calculate the test differently
+ long theStartTime = m_ParentRow->GetStateRow()->GetStartTime();
+ long theEndTime = m_ParentRow->GetStateRow()->GetEndTime();
+ CPt thePoint = inPoint - GetPosition();
+ if (theStartTime == m_Time)
+ theRetVal = (thePoint.x > 7);
+ else if (theEndTime == m_Time)
+ theRetVal = (thePoint.x < 9);
+ else {
+ if (m_Selected)
+ theRetVal = (thePoint.x > 1 && thePoint.x < 15);
+ else
+ theRetVal = (thePoint.x > 3 && thePoint.x < 13);
+ }
+ }
+ return theRetVal;
+}
+
+//=============================================================================
+/**
+ * Handler for left mouse down events.
+ * @param inPoint the point where the mouse is
+ * @param inFlags indicates modifier keys that were down at time of the event
+ */
+bool CAssetTimelineKeyframe::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ // Store the mouse down location in screen coordinates so that we can check the dragging buffer
+ // in OnMouseMove
+ m_MouseDownLoc = inPoint;
+
+ if (!CControl::OnMouseDown(inPoint, inFlags)) {
+ bool theClearPreviouslySelectedKeys = false;
+ bool theSelectedFlag = false;
+ // If the control key is down then we change state, otherwise
+ if (!((CHotKeys::MODIFIER_CONTROL & inFlags) == CHotKeys::MODIFIER_CONTROL)) {
+ theClearPreviouslySelectedKeys = !m_Selected; // clear if not multi-selecting
+ theSelectedFlag = true;
+ } else {
+ theSelectedFlag = !m_Selected;
+ }
+ m_ParentRow->OnKeySelected(m_Time, theSelectedFlag, theClearPreviouslySelectedKeys);
+ m_Selected = theSelectedFlag; // set this after OnKeySelected, because the function may
+ // clear out all previously selected keys including this
+ // TODO : sk - 1-1 mapping of seemingly useless calls in
+ // CPropertyTimelineKeyframe::OnMouseDown, see my comments there.
+ // m_StudioDoc->UpdateClientScene( true );
+ // m_ParentRow->GetStateRow( )->GetState( )->FireAnimatedPropertiesChanged( );
+
+ m_IsMouseDown = true;
+ CStateRow *theStateRow = m_ParentRow->GetStateRow();
+ long theStartTime = theStateRow->GetStartTime();
+ long theEndTime = theStateRow->GetEndTime();
+ m_Snapper.SetStartEndTime(theStartTime, theEndTime);
+ m_Snapper.SetSource(this);
+ m_Snapper.SetKeyFrameClicked(true);
+ m_Snapper.SetSnappingSelectedKeyframes(false);
+
+ theStateRow->GetTimebar()->GetSnappingListProvider().PopulateSnappingList(&m_Snapper);
+ m_Snapper.BeginDrag(inPoint.x);
+
+ // display the time range tooltip
+ RefreshToolTip(inPoint);
+ }
+ return true;
+}
+
+//=============================================================================
+/**
+ * Handler for right mouse down events.
+ * @param inPoint the point where the mouse is
+ * @param inFlags indicates modifier keys that were down at time of the event
+ */
+bool CAssetTimelineKeyframe::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseRDown(inPoint, inFlags)) {
+ if (!m_Selected) {
+ m_Selected = true;
+ m_ParentRow->OnKeySelected(m_Time, m_Selected, true);
+ }
+ ITimelineItemProperty *iProperty = nullptr;
+ if (GetTimelineItemBinding()->GetPropertyCount() > 0) {
+ iProperty = GetTimelineItemBinding()->GetProperty(0);
+ }
+ CKeyframeContextMenu theMenu(GetTimelineItemBinding()->GetKeyframesManager(), iProperty);
+ theMenu.SetTime(GetTime());
+ DoPopup(&theMenu, inPoint);
+ }
+
+ return true;
+}
+
+//=============================================================================
+/**
+ * called when this key is selected
+ *
+ * @param inState the state this key is selected to
+ */
+void CAssetTimelineKeyframe::Select(bool inState)
+{
+ if (m_Selected != inState) {
+ m_Selected = inState;
+ Invalidate();
+ }
+}
+
+//=============================================================================
+/**
+ * handler for the mouse up event
+ * @param inFlags the state of things when the mouse button was released
+ * @param inPoint the point where the mouse is
+ */
+void CAssetTimelineKeyframe::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseUp(inPoint, inFlags);
+ m_IsMouseDown = false;
+ m_IsDragging = false;
+
+ GetTimelineItemBinding()->CommitChangedKeyframes();
+
+ HideMoveableWindow();
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * handler for the onMouse Move event. Offsets selected keys.
+ * Displays the StudioToolTip for the keyframe, showing the time it is at.
+ *
+ * @param inFlags the state of things when the mouse was moved
+ * @param inPoint the point where the mouse is
+ */
+void CAssetTimelineKeyframe::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseMove(inPoint, inFlags);
+ UICPROFILE(OnMouseMove);
+ // If the mouse is down and this is slected, then offst the keys
+ if (m_IsMouseDown && m_Selected) {
+ // If we are not yet dragging the keyframe
+ if (!m_IsDragging) {
+ long theDiff = ::abs(inPoint.x) - m_MouseDownLoc.x;
+ // Figure out if the mouse has moved far enough to start the drag, and readjust the drag
+ // postion on the snapper
+ m_IsDragging = (::abs(theDiff) > DRAGBUFFER);
+ if (m_IsDragging && (::abs(theDiff) - DRAGBUFFER) > 2) {
+ m_Snapper.BeginDrag(m_MouseDownLoc.x);
+ } else
+ m_Snapper.BeginDrag(inPoint.x);
+ }
+
+ // If we are now dragging, procceed as normal
+ if (m_IsDragging) {
+ long theNewTime = m_Snapper.ProcessDrag(m_Time, inPoint.x, inFlags);
+ long theDiffTime = theNewTime - m_Time;
+
+ if (theDiffTime != 0) {
+ // theDiffTime can get updated if its invalid.
+ theDiffTime = GetTimelineItemBinding()->OffsetSelectedKeyframes(theDiffTime);
+ // Set this key's time so it won't be recalced in Refresh keyframes in the row
+ SetTime(m_Time + theDiffTime);
+
+ Invalidate();
+ }
+ }
+
+ // display the time range tooltip
+ RefreshToolTip(inPoint);
+ }
+}
+
+//=============================================================================
+/**
+ * Sets the time ratio
+ *
+ * @param inTimeRatio the new ratio
+ */
+void CAssetTimelineKeyframe::SetTimeRatio(double inTimeRatio)
+{
+ m_TimeRatio = inTimeRatio;
+ CPt theSize = GetSize();
+ SetPosition(::TimeToPos(GetTime(), m_TimeRatio) - (theSize.x / 2), 0);
+}
+
+//=============================================================================
+/**
+ * Pass the double click notification on to the row and have it process it.
+ * The row will do object-specific actions on doubleclicks.
+ * @param inPoint the location of the mouse.
+ * @param inFlags the state of the mouse.
+ * @return true stating that the event was processed.
+ */
+bool CAssetTimelineKeyframe::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ Q_UNUSED(inPoint);
+ Q_UNUSED(inFlags);
+
+ GetTimelineItemBinding()->OnEditKeyframeTime(m_Time, ASSETKEYFRAME);
+ m_IsMouseDown = false;
+ m_IsDragging = false;
+ return true;
+}
+
+//=============================================================================
+/**
+ * @return true if selected
+ */
+bool CAssetTimelineKeyframe::IsSelected()
+{
+ return m_Selected;
+}
+
+void CAssetTimelineKeyframe::SetSize(CPt inSize)
+{
+ CControl::SetSize(inSize);
+}
+
+//=============================================================================
+/**
+ *
+ */
+ITimelineItemBinding *CAssetTimelineKeyframe::GetTimelineItemBinding() const
+{
+ return m_ParentRow->GetStateRow()->GetTimelineItemBinding();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.h
new file mode 100644
index 00000000..54a8b501
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_ASSET_TIMELINE_KEYFRAME
+#define INCLUDED_ASSET_TIMELINE_KEYFRAME 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "Control.h"
+#include "TimelineKeyframe.h"
+#include "Snapper.h"
+
+#include <QPixmap>
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CRenderer;
+class CStateTimebarlessRow;
+class ITimelineItemBinding;
+
+class CAssetTimelineKeyframe : public CControl, public CTimelineKeyframe
+{
+
+public:
+ CAssetTimelineKeyframe(CStateTimebarlessRow *inParentRow, double inTimeRatio);
+ ~CAssetTimelineKeyframe();
+
+ void Draw(CRenderer *inRenderer) override;
+
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+ void Select(bool inState);
+ void SetTimeRatio(double inTimeRatio);
+ bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool IsSelected();
+ void SetSize(CPt inSize) override;
+ bool HitTest(const CPt &inPoint) const override;
+ void SetRectOverHandled(bool inState);
+ bool GetRectOverHandled();
+ void SetPreviousSelectState(bool inState);
+ bool GetPreviousSelectState();
+
+protected:
+ void RefreshToolTip(CPt inPoint);
+ QPixmap GetImage() const;
+ ITimelineItemBinding *GetTimelineItemBinding() const;
+
+protected:
+ bool m_RectOverHandled; ///< Indicates if the mouse rect over has been handled.
+ bool m_PreviousSelectState; ///< Stores the previous select state for the keyframe.
+ bool m_Selected;
+ CStateTimebarlessRow *m_ParentRow;
+ bool m_IsMouseDown;
+ CPt m_MouseDownLoc; ///< Location of the mouse after an OnMouseDownEvent, in client coordinates
+ bool m_IsDragging; ///< Indicates whether or not the keyframe is currently being dragged,
+ ///determined by the pixel buffer
+ double m_TimeRatio;
+
+ CSnapper m_Snapper;
+ QPixmap m_Icon;
+ QPixmap m_DisabledIcon;
+ QPixmap m_SelectedIcon;
+ QPixmap m_DynamicIcon;
+ QPixmap m_DynamicSelectedIcon;
+ QPixmap m_LeftIcon;
+ QPixmap m_LeftDisabledIcon;
+ QPixmap m_LeftSelectedIcon;
+ QPixmap m_LeftDynamicIcon;
+ QPixmap m_LeftDynamicSelectedIcon;
+ QPixmap m_RightIcon;
+ QPixmap m_RightDisabledIcon;
+ QPixmap m_RightSelectedIcon;
+ QPixmap m_RightDynamicIcon;
+ QPixmap m_RightDynamicSelectedIcon;
+};
+
+#endif // INCLUDED_ASSET_TIMELINE_KEYFRAME
diff --git a/src/Authoring/Studio/Palettes/Timeline/BaseStateRow.cpp b/src/Authoring/Studio/Palettes/Timeline/BaseStateRow.cpp
new file mode 100644
index 00000000..7960ed96
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/BaseStateRow.cpp
@@ -0,0 +1,1139 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "BaseStateRow.h"
+#include "PropertyRow.h"
+#include "BaseTimelineTreeControl.h"
+#include "ToggleControl.h"
+#include "BaseTimebarlessRow.h"
+#include "ColorControl.h"
+#include "StateRowFactory.h"
+#include "TimelineTimelineLayout.h"
+#include "ComponentContextMenu.h"
+#include "ITimelineControl.h"
+#include "ResourceCache.h"
+#include "StudioUtils.h"
+#include "Bindings/ITimelineItemBinding.h"
+#include "Bindings/ITimelineTimebar.h"
+
+const long CBaseStateRow::DEFAULT_TOGGLE_LENGTH = 57;
+
+CBaseStateRow::CBaseStateRow()
+ : m_TimeRatio(0.0f)
+ , m_TreeList(true)// true to align the children in the timeline.
+ , m_TreeControl(nullptr)
+ , m_ColorControl(nullptr)
+ , m_ToggleControl(nullptr)
+ , m_TimebarControl(nullptr)
+ , m_Loaded(false)
+ , m_IsExpanded(false)
+ , m_Highlighted(false)
+ , m_Dirty(false)
+ , m_Selected(false)
+ , m_TimelineItemBinding(nullptr)
+ , m_ActiveStart(0)
+ , m_ActiveEnd(0)
+{
+}
+
+CBaseStateRow::~CBaseStateRow()
+{
+ delete m_TreeControl;
+ delete m_ColorControl;
+ delete m_ToggleControl;
+ delete m_TimebarControl;
+
+ // Go through all the state rows and delete them, this control owns all child controls.
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos)
+ (*thePos)->Dispose();
+
+ // Go through all the properties and delete them, this control owns all child controls.
+ TPropertyRowList::iterator thePropertyPos = m_PropertyRows.begin();
+ for (; thePropertyPos != m_PropertyRows.end(); ++thePropertyPos) {
+ CPropertyRow *theRow = (*thePropertyPos);
+ delete theRow;
+ }
+}
+
+void CBaseStateRow::Initialize(ITimelineItemBinding *inTimelineItemBinding)
+{
+ m_Dirty = true;
+ ASSERT(inTimelineItemBinding);
+ m_TimelineItemBinding = inTimelineItemBinding;
+
+ m_TreeControl = new CBaseTimelineTreeControl(this, GetTimelineItem()->IsMaster());
+ m_ColorControl = new CColorControl(this);
+ m_ToggleControl = CreateToggleControl();
+ m_TimebarControl = CreateTimebarRow();
+
+ long theTimebarHeight = CStudioPreferences::GetRowSize();
+ m_TreeControl->SetSize(CPt(500, theTimebarHeight));
+ m_ColorControl->SetAbsoluteSize(CPt(theTimebarHeight, theTimebarHeight));
+ m_ToggleControl->SetAbsoluteSize(CPt(DEFAULT_TOGGLE_LENGTH, theTimebarHeight));
+ m_TimebarControl->SetSize(CPt(800, theTimebarHeight));
+
+ ::CColor theColor = GetTimebarBackgroundColor(GetObjectType());
+ m_TreeControl->SetBackgroundColor(theColor);
+ m_ToggleControl->SetBackgroundColor(theColor);
+ m_TimebarControl->SetBackgroundColor(theColor);
+
+ m_ColorList.AddChild(m_ColorControl);
+ m_TreeList.AddChild(m_TreeControl);
+ m_ToggleList.AddChild(m_ToggleControl);
+ m_TimebarList.AddChild(m_TimebarControl);
+
+ // sk - I think setting controls' names is only useful for debugging.
+ /*Q3DStudio::CString theAssetName( m_Asset->GetName( ) );
+ m_TreeControl->SetName( theAssetName + "TreeControl" );
+ m_TreeList.SetName( theAssetName + "TreeList" );
+ m_ColorControl->SetName( theAssetName + "ColorControl" );
+ m_ColorList.SetName( theAssetName + "ColorList" );
+ m_ToggleControl->SetName( theAssetName + "ToggleControl" );
+ m_ToggleList.SetName( theAssetName + "ToggleList" );
+ m_TimebarControl->SetName( theAssetName + "TimebarControl" );
+ m_TimebarList.SetName( theAssetName + "TimebarList" );*/
+
+ // Bind after all the UI is setup.
+ m_TimelineItemBinding->Bind(this); // see Dispose where it properly unbinds.
+
+ ClearDirty();
+}
+
+//=============================================================================
+/**
+ * Expand this node of the tree control.
+ * This will display all children the fit the filter.
+ */
+void CBaseStateRow::Expand(bool inExpandAll /*= false*/, bool inExpandUp)
+{
+ if (!m_IsExpanded) {
+ m_Filter.SetExpanded(true);
+
+ // Expand/Collapse is done by adding and removing the children, add all the
+ // properties first so they are at the top of the list.
+ TPropertyRowList::iterator thePropPos = m_PropertyRows.begin();
+ for (; thePropPos != m_PropertyRows.end(); ++thePropPos) {
+ CPropertyRow *thePropRow = (*thePropPos);
+ if (thePropRow)
+ thePropRow->Filter(m_Filter, false);
+ }
+ // Add all the State rows after the properties.
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos) {
+ CStateRow *theRow = (*thePos);
+ theRow->Filter(m_Filter, false);
+ }
+
+ m_TreeControl->SetExpanded(true);
+ m_IsExpanded = true;
+ m_ColorControl->UpdateIconStatus();
+ }
+
+ if (inExpandAll) {
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos)
+ (*thePos)->Expand(inExpandAll);
+ }
+
+ if (inExpandUp && m_ParentRow)
+ m_ParentRow->Expand(false, inExpandUp);
+}
+
+//=============================================================================
+/**
+ * Collapse this node of the tree control.
+ * This will hide all children of this control.
+ */
+void CBaseStateRow::Collapse(bool inCollapseAll /* = false */)
+{
+ if (m_IsExpanded) {
+ CFilter theFilter = m_Filter;
+ theFilter.SetExpanded(false);
+
+ TPropertyRowList::iterator thePropPos = m_PropertyRows.begin();
+ for (; thePropPos != m_PropertyRows.end(); ++thePropPos) {
+ CPropertyRow *thePropRow = (*thePropPos);
+ if (thePropRow)
+ thePropRow->Filter(theFilter);
+ }
+
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos) {
+ CStateRow *theRow = (*thePos);
+ theRow->Filter(theFilter);
+ }
+
+ m_TimelineItemBinding->OnCollapsed();
+
+ m_TreeControl->SetExpanded(false);
+ m_IsExpanded = false;
+ m_ColorControl->UpdateIconStatus();
+ }
+
+ if (inCollapseAll) {
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos) {
+ (*thePos)->Collapse(inCollapseAll);
+ }
+ }
+}
+
+//=============================================================================
+/**
+ * Toggle the expansion state of this control.
+ * This will expand the control if it is closed, or collapse it if it is
+ * open.
+ */
+void CBaseStateRow::ToggleExpansion(CToggleButton *, CButtonControl::EButtonState inButtonState)
+{
+ if (inButtonState == CButtonControl::EBUTTONSTATE_UP)
+ Collapse();
+ else
+ Expand();
+}
+
+//=============================================================================
+/**
+ * Shows or hides rows for all children, based on the filter.
+ * @param inFilter Object specifying the filters currently applied to the timeline.
+ * @param inFilterChildren true if the filter should go recursively to children.
+ */
+void CBaseStateRow::Filter(const CFilter &inFilter, bool inFilterChildren /*= true*/)
+{
+ m_Filter = inFilter;
+
+ // For each child object
+ if (inFilterChildren) {
+ CFilter theChildFilter = inFilter;
+ theChildFilter.SetExpanded(m_IsExpanded);
+
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos) {
+ // Apply the filter
+ CStateRow *theRow = (*thePos);
+ theRow->Filter(theChildFilter);
+ }
+ }
+
+ // This flag determines whether or not the controls on this row should be shown, based on the
+ // filter
+ bool theVisibleFlag = PerformFilter(m_Filter);
+
+ m_IsViewable = theVisibleFlag;
+
+ theVisibleFlag &= inFilter.IsExpanded();
+
+ // Show or hide the controls on this row before we iterate through the properties
+ m_ColorList.SetVisible(theVisibleFlag);
+ m_TreeList.SetVisible(theVisibleFlag);
+ m_ToggleList.SetVisible(theVisibleFlag);
+ m_TimebarList.SetVisible(theVisibleFlag);
+
+ if (inFilterChildren) {
+ CFilter theChildFilter = inFilter;
+ theChildFilter.SetExpanded(m_IsExpanded);
+
+ // For each property on this object
+ TPropertyRowList::iterator thePropPos = m_PropertyRows.begin();
+ for (; thePropPos != m_PropertyRows.end(); ++thePropPos) {
+ // Apply the filter
+ CPropertyRow *thePropRow = (*thePropPos);
+ if (thePropRow)
+ thePropRow->Filter(theChildFilter);
+ }
+ }
+
+ m_TreeControl->SetToggleVisible(this->HasVisibleChildren());
+}
+
+//=============================================================================
+/**
+ * Get the color control for this row.
+ * @return the color control for this row.
+ */
+CControl *CBaseStateRow::GetColorControl()
+{
+ return &m_ColorList;
+}
+
+//=============================================================================
+/**
+ * Get the tree control for this row.
+ * @return the tree control for this row.
+ */
+CControl *CBaseStateRow::GetTreeControl()
+{
+ return &m_TreeList;
+}
+
+//=============================================================================
+/**
+ * Get the toggle control for this row.
+ * @return the toggle control for this row.
+ */
+CControl *CBaseStateRow::GetToggleControl()
+{
+ return &m_ToggleList;
+}
+
+//=============================================================================
+/**
+ * Get the timebar control for this row.
+ * @return the timebar control for this row.
+ */
+CControl *CBaseStateRow::GetTimebarControl()
+{
+ return &m_TimebarList;
+}
+
+//=============================================================================
+/**
+ * Remove a row from this control.
+ * @param inState the state of the row to be removed.
+ */
+void CBaseStateRow::RemoveRow(CStateRow *inRow)
+{
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos) {
+ CStateRow *theRow = (*thePos);
+ if (theRow == inRow) {
+ DeleteRow(theRow);
+ m_StateRows.erase(thePos);
+ break;
+ }
+ }
+ m_TreeControl->SetToggleVisible(this->HasVisibleChildren());
+}
+
+//=============================================================================
+/**
+ * Helper function to remove all controls of this property row and dispose of it.
+ */
+void CBaseStateRow::DeletePropertyRow(CPropertyRow *inPropertyRow)
+{
+ if (!inPropertyRow)
+ return;
+
+ m_ColorList.RemoveChild(inPropertyRow->GetColorControl());
+ m_TreeList.RemoveChild(inPropertyRow->GetTreeControl());
+ m_ToggleList.RemoveChild(inPropertyRow->GetToggleControl());
+ m_TimebarList.RemoveChild(inPropertyRow->GetTimebarControl());
+ delete inPropertyRow;
+}
+
+//=============================================================================
+/**
+ * By default, we don't show shy/eye/lock toggles
+ */
+CBlankToggleControl *CBaseStateRow::CreateToggleControl()
+{
+ return new CBlankToggleControl(this);
+}
+
+//=============================================================================
+/**
+ * Get the StateRow that is representing this child timeline item.
+ * @param inTimelineItem child timeline item
+ * @return the StateRow for inState.
+ */
+CStateRow *CBaseStateRow::GetRow(ITimelineItem *inTimelineItem)
+{
+ if (inTimelineItem) {
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos) {
+ if ((*thePos)->GetTimelineItem() == inTimelineItem)
+ return (*thePos);
+ }
+ }
+ return nullptr;
+}
+
+//=============================================================================
+/**
+ * Called when a row is to be completely removed from the UI
+ */
+void CBaseStateRow::DeleteRow(CStateRow *inRow)
+{
+ m_ColorList.RemoveChild(inRow->GetColorControl());
+ m_TreeList.RemoveChild(inRow->GetTreeControl());
+ m_ToggleList.RemoveChild(inRow->GetToggleControl());
+ m_TimebarList.RemoveChild(inRow->GetTimebarControl());
+
+ inRow->Dispose();
+}
+
+//=============================================================================
+/**
+ * Call from the child controls that the mouse is over one of the children.
+ * This is used to highlight the entire row on mouse over.
+ */
+void CBaseStateRow::OnMouseOver()
+{
+ if (!m_Highlighted) {
+ try {
+ // TODO: Added the try/catch block to prevent crashing when the instance handle is not
+ // found
+ // this will happen sometimes when delete the object from the timeline
+ // need to really fix this at the root.
+ ::CColor theColor = GetTimebarHighlightBackgroundColor(GetObjectType());
+ m_TreeControl->SetBackgroundColor(theColor);
+ m_ToggleControl->SetBackgroundColor(theColor);
+ m_TimebarControl->SetBackgroundColor(theColor);
+
+ m_Highlighted = true;
+ } catch (...) {
+ }
+ }
+}
+
+//=============================================================================
+/**
+ * Call from the child controls that the mouse is no longer over one of the children.
+ * This is used to highlight the entire row on mouse over.
+ */
+void CBaseStateRow::OnMouseOut()
+{
+ if (m_Highlighted) {
+ try {
+ // TODO: Added the try/catch block to prevent crashing when the instance handle is not
+ // found
+ // this will happen sometimes when delete the object from the timeline
+ // need to really fix this at the root.
+ ::CColor theColor = GetTimebarBackgroundColor(GetObjectType());
+ m_TreeControl->SetBackgroundColor(theColor);
+ m_ToggleControl->SetBackgroundColor(theColor);
+ m_TimebarControl->SetBackgroundColor(theColor);
+
+ m_Highlighted = false;
+ } catch (...) {
+ }
+ }
+}
+
+//=============================================================================
+/**
+ * Tells this that the Asset data has changed and it needs to be updated.
+ * Someone should call ClearDirty afterwards.
+ */
+void CBaseStateRow::OnDirty()
+{
+ m_Dirty = true;
+}
+
+void CBaseStateRow::ClearDirty()
+{
+ if (m_Dirty) {
+ m_TreeControl->Refresh(m_TimelineItemBinding->GetTimelineItem());
+ m_ToggleControl->Refresh();
+ m_ColorControl->Invalidate();
+ m_TimebarControl->RefreshRowMetaData();
+ m_Dirty = false;
+ }
+}
+
+//=============================================================================
+/**
+ * Recursively load the children of this control, used by derived classes
+ * This will load all the properties and states, and create controls for them.
+ */
+void CBaseStateRow::LoadChildren()
+{
+ if (!m_Loaded) {
+ m_Loaded = true;
+
+ LoadProperties();
+
+ CTimelineItemOrderedIterator theChildIter(m_TimelineItemBinding);
+ // Go through all the children and load them too.
+ for (; !theChildIter.IsDone(); ++theChildIter)
+ CreateChildRow(*theChildIter, nullptr);
+
+ GetTopControl()->OnLayoutChanged();
+ }
+}
+
+//=============================================================================
+/**
+ * Add a row that represents this child timeline item
+ * @param inNextItem indicates row to follow behind the row for inTimeLineItem, nullptr to append inRow
+ * to the end of the current list.
+ */
+void CBaseStateRow::AddChildRow(ITimelineItemBinding *inTimeLineItem,
+ ITimelineItemBinding *inNextItem)
+{
+ if (!inTimeLineItem)
+ return;
+
+ // only add if loaded, else it will get added twice.
+ if (m_Loaded) {
+ CStateRow *theStateRow = CreateChildRow(
+ inTimeLineItem, inNextItem ? GetRow(inNextItem->GetTimelineItem()) : nullptr);
+ if (theStateRow)
+ theStateRow->LoadChildren();
+ }
+ Expand(false, true);
+
+ CBaseStateRow *theRow = GetRow(inTimeLineItem->GetTimelineItem());
+ if (theRow) {
+ CControl *theTreeControl = theRow->GetTreeControl();
+ if (theTreeControl)
+ theTreeControl->EnsureVisible();
+ }
+}
+
+void CBaseStateRow::RemoveChildRow(ITimelineItemBinding *inTimelineItem)
+{
+ CStateRow *theChildRow = GetRow(inTimelineItem->GetTimelineItem());
+ inTimelineItem->SetParent(nullptr);
+ if (theChildRow) {
+ RemoveRow(theChildRow);
+ // preserving legacy behavior.
+ GetTopControl()->HideTimelineMoveableTooltip();
+ }
+}
+
+//=============================================================================
+/**
+ * Removes all child rows from this row. Called prior to a load. The load call is responsible for
+ * updating the UI.
+ */
+void CBaseStateRow::RemoveAllChildren()
+{
+ RemoveAllProperties();
+
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos)
+ DeleteRow(*thePos);
+
+ m_StateRows.clear();
+}
+
+//=============================================================================
+/**
+ * Remove all the properties from this object. Called prior to a load. The load call is responsible
+ * for updating the UI.
+ */
+void CBaseStateRow::RemoveAllProperties()
+{
+ TPropertyRowList::iterator thePropPos = m_PropertyRows.begin();
+ for (; thePropPos != m_PropertyRows.end(); ++thePropPos)
+ DeletePropertyRow(*thePropPos);
+
+ m_PropertyRows.clear();
+}
+
+//=============================================================================
+/**
+ * Set this row to selected
+ */
+void CBaseStateRow::Select(SBaseStateRowSelectionKeyState inState,
+ bool inCheckKeySelection /*= true */)
+{
+ bool alreadySelected = m_Selected;
+ m_TimelineItemBinding->SetSelected(inState.IsControlDown());
+ if (inCheckKeySelection) {
+ if (inState.IsShiftDown())
+ m_TimebarControl->SelectAllKeys();
+ else if (!alreadySelected)
+ m_TimelineItemBinding->ClearKeySelection();
+ }
+}
+
+//=============================================================================
+/**
+ * Change the selection state of the row.
+ */
+void CBaseStateRow::OnSelected(bool inSelection)
+{
+ if (inSelection == m_Selected)
+ return;
+
+ m_Selected = inSelection;
+ if (inSelection) {
+ if (m_ParentRow)
+ m_ParentRow->Expand(false, true);
+
+ m_TreeControl->EnsureVisible();
+
+ m_TreeControl->OnSelect();
+ m_ToggleControl->OnSelect();
+ m_ColorControl->OnSelect();
+ m_TimebarControl->OnSelect();
+ } else {
+ m_TreeControl->OnDeselect();
+ m_ToggleControl->OnDeselect();
+ m_ColorControl->OnDeselect();
+ m_TimebarControl->OnDeselect();
+ }
+}
+
+//=============================================================================
+/**
+ * Call to add a property row as a child of this control.
+ * @param inRow the row to be added.
+ */
+void CBaseStateRow::AddPropertyRow(CPropertyRow *inRow, CTimelineRow *inNextRow /*= nullptr */)
+{
+ m_PropertyRows.push_back(inRow);
+ InitializePropertyRow(inRow, inNextRow);
+ // For snapping timebars/keyframes
+ inRow->SetSnappingListProvider(GetSnappingListProvider());
+
+ m_TimebarControl->SetDirty(true);
+}
+
+//=============================================================================
+/**
+ * Remove the property row.
+ */
+void CBaseStateRow::RemovePropertyRow(const CPropertyRow *inRow)
+{
+ if (!inRow)
+ return;
+
+ TPropertyRowList::iterator thePropPos = m_PropertyRows.begin();
+ for (; thePropPos != m_PropertyRows.end(); ++thePropPos) {
+ CPropertyRow *theRow = *thePropPos;
+ if (theRow == inRow) {
+ DeletePropertyRow(theRow);
+ m_PropertyRows.erase(thePropPos);
+
+ // Update flippy
+ OnChildVisibilityChanged();
+ break;
+ }
+ }
+}
+
+//=============================================================================
+/**
+ * Helper function to initialize a new property row
+ * @param inRow the row to be added.
+ * @param inNextRow if specified, row that should be after inRow after
+ * insertion.
+ */
+void CBaseStateRow::InitializePropertyRow(CPropertyRow *inRow, CTimelineRow *inNextRow /*= nullptr */)
+{
+ CFilter theFilter = m_Filter;
+ theFilter.SetExpanded(m_IsExpanded);
+
+ if (!inNextRow) { // not provided, this property row would be inserted before the first
+ // non-property row.
+ CTimelineItemOrderedIterator theIterator(m_TimelineItemBinding);
+ if (!theIterator.IsDone())
+ inNextRow = GetRow(theIterator.GetCurrent()->GetTimelineItem());
+ }
+ AddRowToUILists(inRow, inNextRow, theFilter);
+}
+
+void CBaseStateRow::AddRowToUILists(CTimelineRow *inRow, CTimelineRow *inNextRow, CFilter &inFilter)
+{
+ // Default the insert locations to the end of the list.
+ CControl *theNextColorControl = nullptr;
+ CControl *theNextTreeControl = nullptr;
+ CControl *theNextToggleControl = nullptr;
+ CControl *theNextTimebarControl = nullptr;
+ if (inNextRow) {
+ theNextColorControl = inNextRow->GetColorControl();
+ theNextTreeControl = inNextRow->GetTreeControl();
+ theNextToggleControl = inNextRow->GetToggleControl();
+ theNextTimebarControl = inNextRow->GetTimebarControl();
+ }
+ inRow->SetIndent(m_Indent + CTimelineRow::TREE_INDENT);
+ inRow->SetParent(this);
+ inRow->Filter(inFilter);
+ inRow->SetTimeRatio(m_TimeRatio);
+
+ CControl *theColorControl = inRow->GetColorControl();
+ CControl *theTreeControl = inRow->GetTreeControl();
+ CControl *theToggleControl = inRow->GetToggleControl();
+ CControl *theTimebarControl = inRow->GetTimebarControl();
+
+ // If not expanded then hide the controls.
+ if (!m_IsExpanded) {
+ theColorControl->SetVisible(false);
+ theTreeControl->SetVisible(false);
+ theToggleControl->SetVisible(false);
+ theTimebarControl->SetVisible(false);
+ }
+
+ // Add the controls to the lists in the prioritized order
+ m_ColorList.AddChild(theColorControl, theNextColorControl);
+ m_TreeList.AddChild(theTreeControl, theNextTreeControl);
+ m_ToggleList.AddChild(theToggleControl, theNextToggleControl);
+ m_TimebarList.AddChild(theTimebarControl, theNextTimebarControl);
+
+ m_TreeControl->SetToggleVisible(this->HasVisibleChildren());
+}
+
+CStateRow *CBaseStateRow::CreateChildRow(ITimelineItemBinding *inChildBinding, CStateRow *inNextRow)
+{
+ CStateRow *theRow =
+ CStateRowFactory::CreateStateRow(inChildBinding, this, GetSnappingListProvider());
+ if (theRow) { // add by appending to the list
+ AddStateRow(theRow, inNextRow);
+ }
+ inChildBinding->SetParent(m_TimelineItemBinding);
+ return theRow;
+}
+
+long CBaseStateRow::GetNumNonPropertyRows() const
+{
+ return static_cast<long>(m_StateRows.size());
+}
+
+CBaseStateRow *CBaseStateRow::GetNonPropertyRow(long inIndex) const
+{
+ return m_StateRows.at(inIndex);
+}
+
+long CBaseStateRow::GetNumPropertyRows() const
+{
+ return static_cast<long>(m_PropertyRows.size());
+}
+CPropertyRow *CBaseStateRow::GetPropertyRow(long inIndex) const
+{
+ return m_PropertyRows.at(inIndex);
+}
+
+//=============================================================================
+/**
+ * Call to add a state row as a child of this control.
+ * @param inRow the row to be added.
+ * @param inNextRow row to follow behind the row that would be added, nullptr to append inRow to the
+ * end of the current list.
+ */
+void CBaseStateRow::AddStateRow(CStateRow *inRow, CStateRow *inNextRow)
+{
+ if (inNextRow != nullptr) {
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ while (thePos != m_StateRows.end()) {
+ if ((*thePos) == inNextRow) {
+ m_StateRows.insert(thePos, inRow);
+ thePos = m_StateRows.end();
+ } else
+ ++thePos;
+ }
+ } else {
+ m_StateRows.push_back(inRow);
+ }
+
+ AddRowToUILists(inRow, inNextRow, m_Filter);
+}
+
+//=============================================================================
+/**
+ * Checks to see if there are any visible children of this row.
+ * This is used for figuring out whether the expand button should be displayed
+ * or not.
+ */
+bool CBaseStateRow::HasVisibleChildren()
+{
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos) {
+ // Apply the filter
+ if ((*thePos)->IsViewable())
+ return true;
+ }
+
+ // For each property on this object
+ TPropertyRowList::iterator thePropPos = m_PropertyRows.begin();
+ for (; thePropPos != m_PropertyRows.end(); ++thePropPos) {
+ // Apply the filter
+ CPropertyRow *thePropRow = (*thePropPos);
+ if (thePropRow && thePropRow->IsViewable())
+ return true;
+ }
+ return false;
+}
+
+//=============================================================================
+/**
+ * Set the amount of time that is represented by a pixel.
+ * This modifies the length of this control.
+ * @param inTimePerPixel the time per pixel.
+ */
+void CBaseStateRow::SetTimeRatio(double inTimeRatio)
+{
+ m_TimeRatio = inTimeRatio;
+ m_TimebarControl->SetTimeRatio(inTimeRatio);
+
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos) {
+ (*thePos)->SetTimeRatio(inTimeRatio);
+ }
+
+ TPropertyRowList::iterator thePropPos = m_PropertyRows.begin();
+ for (; thePropPos != m_PropertyRows.end(); ++thePropPos) {
+ CPropertyRow *thePropRow = (*thePropPos);
+ if (thePropRow)
+ thePropRow->SetTimeRatio(inTimeRatio);
+ }
+}
+
+//=============================================================================
+/**
+ * Called when a child becomes visible/invisible.
+ */
+void CBaseStateRow::OnChildVisibilityChanged()
+{
+ m_TreeControl->SetToggleVisible(this->HasVisibleChildren());
+}
+
+//=============================================================================
+/**
+ * Called when the mouse is double clicked.
+ * @param inPoint location of the mouse at time of event
+ * @param inFlags modifier key states at time of event
+ */
+void CBaseStateRow::OnMouseDoubleClick(CPt, Qt::KeyboardModifiers inFlags)
+{
+ // Do nothing by default. Let subclasses define what to do.
+ Q_UNUSED(inFlags);
+}
+
+//=============================================================================
+/**
+ * Show context menu for this row
+ */
+void CBaseStateRow::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ Q_UNUSED(inFlags);
+
+ Select(SBaseStateRowSelectionKeyState()); // ensure this is selected, but doesn't affect any key
+ // selections, because this can be triggered from a
+ // key being selected
+ CComponentContextMenu theMenu(m_TreeControl, m_TimelineItemBinding);
+ m_TreeControl->DoPopup(&theMenu, inPoint);
+}
+
+//=============================================================================
+/**
+ * Selects keys in a given rect
+ * @param inRect the rect to use for selection
+ */
+void CBaseStateRow::SelectKeysInRect(CRct inRect, bool inModifierKeyDown,
+ bool inGlobalCommitSelectionFlag)
+{
+ CRct theOffsetRect = inRect;
+ theOffsetRect.Offset(-m_TimebarList.GetPosition());
+
+ // Commits the keyframe selection by setting the keyframes' previous state to its current state,
+ // when the user releases the mouse button.
+ // This will help the keyframes to retain their original states even though they are
+ // not in the mouse select region.
+ if (inGlobalCommitSelectionFlag) {
+ m_TimebarControl->CommitSelections();
+
+ // iterates through every property row and commits the selection states of properties
+ // keyframes
+ TPropertyRowList::iterator thePropPos = m_PropertyRows.begin();
+ for (; thePropPos != m_PropertyRows.end(); ++thePropPos) {
+ CPropertyRow *thePropRow = (*thePropPos);
+ if (thePropRow && thePropRow->IsViewable())
+ thePropRow->CommitSelections();
+ }
+ }
+
+ if (m_IsExpanded) {
+ // Iterates each property row and select the keys that are in the rectangle
+ TPropertyRowList::iterator thePropPos = m_PropertyRows.begin();
+ for (; thePropPos != m_PropertyRows.end(); ++thePropPos) {
+ CPropertyRow *thePropRow = (*thePropPos);
+ if (thePropRow && thePropRow->IsViewable())
+ thePropRow->SelectKeysInRect(theOffsetRect, inModifierKeyDown);
+ }
+
+ // Recurse the each state row (or master row) and selects the property keyframes in them
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos)
+ (*thePos)->SelectKeysInRect(theOffsetRect, inModifierKeyDown,
+ inGlobalCommitSelectionFlag);
+
+ } else {
+ // Selects all the master key frames in the rect
+ m_TimebarControl->SelectKeysInRect(theOffsetRect, inModifierKeyDown);
+ }
+}
+
+//=============================================================================
+/**
+ * Deletes all the keys for the asset that was chosen by the user
+ * @param inBatch the batch used to batch all the deletes together
+ */
+void CBaseStateRow::DeleteAllKeys()
+{
+ // Iterate through all the property rows and delete all their keys
+ TPropertyRowList::iterator thePropPos = m_PropertyRows.begin();
+ for (; thePropPos != m_PropertyRows.end(); ++thePropPos) {
+ CPropertyRow *thePropRow = (*thePropPos);
+ if (thePropRow)
+ thePropRow->DeleteAllKeys();
+ }
+}
+
+//=============================================================================
+/**
+ * Add snapping points to inSnappingList.
+ * This will add the snapping points for any visible objects to inSnappingList.
+ * @param inSnappingList the list to add the snapping points to.
+ */
+void CBaseStateRow::PopulateSnappingList(CSnapper *inSnappingList)
+{
+ inSnappingList->PushOffset(-m_TimebarList.GetPosition().y);
+ m_TimebarControl->PopulateSnappingList(inSnappingList);
+
+ if (IsExpanded()) {
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos) {
+ (*thePos)->PopulateSnappingList(inSnappingList);
+ }
+ }
+}
+
+//=============================================================================
+/**
+ * Sets all the child control enable states
+ * @param inEnabled the state to set the controls to
+ */
+void CBaseStateRow::SetEnabled(bool inEnabled)
+{
+ m_TreeControl->SetEnabled(inEnabled);
+ m_ToggleControl->SetEnabled(inEnabled);
+ m_ColorControl->SetEnabled(inEnabled);
+ m_TimebarControl->SetEnabled(inEnabled);
+}
+
+//=============================================================================
+/**
+ * Begin dragging.
+ * sk - potential spot for refactoring the Drag&Drop implementation.
+ * Right now, each IDragable is implicitly assumed to be a asset implementation. See
+ * *DropSource.cpp: each IDragable is dynamically cast to its implementation.
+ */
+void CBaseStateRow::DoStartDrag(CControlWindowListener *inWndListener)
+{
+ m_TimelineItemBinding->DoStartDrag(inWndListener);
+}
+
+void CBaseStateRow::AcceptDropAfter(bool inAccept)
+{
+ m_TreeControl->AcceptDropAfter(inAccept);
+}
+
+void CBaseStateRow::AcceptDropBefore(bool inAccept)
+{
+ m_TreeControl->AcceptDropBefore(inAccept);
+}
+
+//=============================================================================
+/**
+ * Pass through to the binding to set up the target aset for a drag&drop action on this
+ *control.
+ */
+void CBaseStateRow::SetDropTarget(CDropTarget *inDropTarget)
+{
+ m_TimelineItemBinding->SetDropTarget(inDropTarget);
+}
+
+void CBaseStateRow::SetTimelineLatestTime(long inTime)
+{
+ long theLength = ::TimeToPos(inTime, m_TimeRatio) + CTimelineTimelineLayout::END_BUFFER_SIZE;
+ m_TimebarControl->SetAbsoluteSize(CPt(theLength, m_TimebarControl->GetSize().y));
+
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos)
+ (*thePos)->SetTimelineLatestTime(inTime);
+}
+
+//=============================================================================
+/**
+ * Determines whether or not a row is expanded. A row can be expanded even if
+ * it is not visible.
+ * @return true if the row is currently expanded, otherwise false
+ */
+bool CBaseStateRow::IsExpanded()
+{
+ return m_IsExpanded;
+}
+
+//=============================================================================
+/**
+ * Determines whether or not a row is loaded. The rows are delayed loaded, i.e.
+ * it will be loaded when it's visible for the first time. Before it's loaded, any
+ * updates to the structure, say, adding dynamic properties does not need to update the
+ * timeline.
+ * @return true if the row is currently loaded, otherwise false
+ */
+bool CBaseStateRow::IsLoaded()
+{
+ return m_Loaded;
+}
+
+long CBaseStateRow::GetStartTime()
+{
+ ITimelineTimebar *theTimebar = m_TimelineItemBinding->GetTimelineItem()->GetTimebar();
+ if (theTimebar)
+ return theTimebar->GetStartTime();
+ return 0;
+}
+
+long CBaseStateRow::GetEndTime()
+{
+ ITimelineTimebar *theTimebar = m_TimelineItemBinding->GetTimelineItem()->GetTimebar();
+ if (theTimebar)
+ return theTimebar->GetEndTime();
+ return 0;
+}
+
+long CBaseStateRow::GetActiveStart()
+{
+ return m_ActiveStart;
+}
+long CBaseStateRow::GetActiveEnd()
+{
+ return m_ActiveEnd;
+}
+
+//=============================================================================
+/**
+ * Get the start time of this row, which is accumulative of all its descendants.
+ */
+long CBaseStateRow::GetEarliestStartTime()
+{
+ long theEarliestStartTime = 0;
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos) {
+ CStateRow *theRow = (*thePos);
+ long theStartTime = theRow->GetEarliestStartTime();
+ if (theStartTime < theEarliestStartTime)
+ theEarliestStartTime = theStartTime;
+ }
+ return theEarliestStartTime;
+}
+
+//=============================================================================
+/**
+ * Get the end time of this row, which is accumulative of all its descendants.
+ */
+long CBaseStateRow::GetLatestEndTime()
+{
+ long theLatestTime = 0;
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos) {
+ CStateRow *theRow = (*thePos);
+ long theEndTime = theRow->GetLatestEndTime();
+ if (theEndTime > theLatestTime)
+ theLatestTime = theEndTime;
+ }
+ return theLatestTime;
+}
+
+//=============================================================================
+/**
+ * Lame switch to get the normal state object specific icon.
+ * @return the icon to be used in the 'normal' state.
+ */
+QPixmap CBaseStateRow::GetIcon()
+{
+ return CResourceCache::GetInstance()->GetBitmap(
+ CStudioObjectTypes::GetNormalIconName(GetObjectType()));
+}
+
+//=============================================================================
+/**
+ * Lame switch to get the disabled state object specific icon.
+ * @return the icon to be used in the disabled state.
+ */
+QPixmap CBaseStateRow::GetDisabledIcon()
+{
+ return CResourceCache::GetInstance()->GetBitmap(
+ CStudioObjectTypes::GetDisabledIconName(GetObjectType()));
+}
+
+//=============================================================================
+/**
+ * @return the studio type of the object represented by this row
+ */
+EStudioObjectType CBaseStateRow::GetObjectType() const
+{
+ return GetTimelineItem()->GetObjectType();
+}
+
+ITimelineItemBinding *CBaseStateRow::GetTimelineItemBinding() const
+{
+ return m_TimelineItemBinding;
+}
+
+ITimelineItem *CBaseStateRow::GetTimelineItem() const
+{
+ return m_TimelineItemBinding->GetTimelineItem();
+}
+
+//=============================================================================
+/**
+ * When this row is no longer useful, clean up.
+ */
+void CBaseStateRow::Dispose()
+{
+ // Disconnection point
+ if (m_TimelineItemBinding)
+ m_TimelineItemBinding->Release();
+
+ CTimelineRow::Dispose();
+}
+
+void CBaseStateRow::UpdateActionStatus()
+{
+ m_ColorControl->UpdateIconStatus();
+}
+
+//=============================================================================
+/**
+ * Restores the focus state of this row.
+ */
+void CBaseStateRow::SetFocus()
+{
+ CControl *theParent = m_TreeControl->GetParent();
+ if (theParent)
+ theParent->GrabFocus(m_TreeControl);
+}
+
+CBaseTimebarlessRow *CBaseStateRow::GetTimebar() const
+{
+ return m_TimebarControl;
+}
+
+void CBaseStateRow::SetNameReadOnly(bool inReadOnly)
+{
+ m_TreeControl->SetNameReadOnly(inReadOnly);
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/BaseStateRow.h b/src/Authoring/Studio/Palettes/Timeline/BaseStateRow.h
new file mode 100644
index 00000000..5a62dfc0
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/BaseStateRow.h
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_BASE_STATE_ROW_H
+#define INCLUDED_BASE_STATE_ROW_H 1
+
+#pragma once
+
+#include "TimelineRow.h"
+#include "ListLayout.h"
+#include "ToggleButton.h"
+#include "DispatchListeners.h"
+
+class CPropertyRow;
+class CBaseTimelineTreeControl;
+class CColorControl;
+class CBlankToggleControl;
+class CBaseTimebarlessRow;
+class CStateRow;
+class CCmdBatch;
+class ITimelineItem;
+class ITimelineItemBinding;
+
+struct SBaseStateRowSelectionKeyState
+{
+ enum Enum {
+ NoKeyDown = 0,
+ ShiftKey = 1 << 0,
+ ControlKey = 1 << 1,
+ };
+ qt3ds::QT3DSU32 m_KeyState;
+ SBaseStateRowSelectionKeyState()
+ : m_KeyState(0)
+ {
+ }
+ void SetShiftDown() { m_KeyState = m_KeyState | ShiftKey; }
+ void SetControlDown() { m_KeyState = m_KeyState | ControlKey; }
+ bool IsShiftDown() const { return (m_KeyState & ShiftKey) != 0; }
+ bool IsControlDown() const { return (m_KeyState & ControlKey) != 0; }
+};
+
+class CBaseStateRow : public CTimelineRow
+{
+public:
+ typedef std::vector<CPropertyRow *> TPropertyRowList;
+ typedef std::vector<CStateRow *> TStateRowList;
+ static const long DEFAULT_TOGGLE_LENGTH;
+
+public:
+ CBaseStateRow();
+ virtual ~CBaseStateRow();
+
+ virtual void Initialize(ITimelineItemBinding *inTimelineItemBinding);
+
+ bool IsExpanded();
+ bool IsLoaded();
+ virtual void Expand(bool inExpandAll = false, bool inExpandUp = false);
+ virtual void Collapse(bool inCollapseAll = false);
+ void ToggleExpansion(CToggleButton *, CButtonControl::EButtonState);
+
+ void SetTimeRatio(double inTimePerPixel) override;
+
+ CControl *GetColorControl() override;
+ CControl *GetTreeControl() override;
+ CControl *GetToggleControl() override;
+ CControl *GetTimebarControl() override;
+
+ void Select(SBaseStateRowSelectionKeyState inKeyState, bool inCheckKeySelection = true);
+ void SelectKeysInRect(CRct inRect, bool inModifierKeyDown, bool inGlobalCommitSelectionFlag);
+ void DeleteAllKeys();
+
+ virtual void OnMouseOver();
+ virtual void OnMouseOut();
+ virtual void OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ virtual void OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ virtual void OnDirty();
+ virtual void OnSelected(bool inSelected);
+
+ void LoadChildren();
+ void AddChildRow(ITimelineItemBinding *inTimeLineItem, ITimelineItemBinding *inNextItem);
+ void RemoveChildRow(ITimelineItemBinding *inTimeLineItem);
+
+ void RemoveRow(CStateRow *inRow);
+ void AddStateRow(CStateRow *inRow, CStateRow *inNextRow);
+ void AddPropertyRow(CPropertyRow *inRow, CTimelineRow *inNextRow = nullptr);
+ void RemovePropertyRow(const CPropertyRow *inRow);
+ void RemoveAllChildren();
+ void RemoveAllProperties();
+
+ long GetNumNonPropertyRows() const;
+ CBaseStateRow *GetNonPropertyRow(long inIndex) const;
+ long GetNumPropertyRows() const;
+ CPropertyRow *GetPropertyRow(long inIndex) const;
+
+ void Filter(const CFilter &inFilter, bool inFilterChildren = true) override;
+ CFilter *GetFilter() { return &m_Filter; }
+ void OnChildVisibilityChanged() override;
+
+ virtual bool HasVisibleChildren();
+
+ void PopulateSnappingList(CSnapper *inSnappingList) override;
+
+ virtual void SetEnabled(bool inEnabled);
+
+ void DoStartDrag(CControlWindowListener *inWndListener);
+ void AcceptDropAfter(bool inAccept);
+ void AcceptDropBefore(bool inAccept);
+ void SetDropTarget(CDropTarget *inDropTarget);
+
+ // CTimelineRow
+ virtual long GetEarliestStartTime();
+ long GetLatestEndTime() override;
+
+ long GetStartTime();
+ long GetEndTime();
+ long GetActiveStart();
+ long GetActiveEnd();
+ virtual bool CalculateActiveStartTime() = 0;
+ virtual bool CalculateActiveEndTime() = 0;
+ void Dispose() override;
+
+ virtual QPixmap GetIcon();
+ virtual QPixmap GetDisabledIcon();
+
+ EStudioObjectType GetObjectType() const;
+ ITimelineItemBinding *GetTimelineItemBinding() const;
+ ITimelineItem *GetTimelineItem() const;
+
+ void UpdateActionStatus();
+ void SetFocus();
+
+ CBaseTimebarlessRow *GetTimebar() const;
+
+ void SetNameReadOnly(bool inReadOnly);
+
+ void ClearDirty();
+
+protected:
+ void DeletePropertyRow(CPropertyRow *inPropertyRow);
+ virtual CBlankToggleControl *CreateToggleControl();
+ virtual CBaseTimebarlessRow *CreateTimebarRow() = 0;
+ virtual bool PerformFilter(const CFilter &inFilter) = 0;
+ CStateRow *GetRow(ITimelineItem *inTimelineItem);
+ void DeleteRow(CStateRow *inRow);
+ void SetTimelineLatestTime(long inLength);
+
+ virtual void LoadProperties() {}
+ void InitializePropertyRow(CPropertyRow *inRow, CTimelineRow *inNextRow = nullptr);
+
+ void AddRowToUILists(CTimelineRow *inRow, CTimelineRow *inNextRow, CFilter &inFilter);
+ CStateRow *CreateChildRow(ITimelineItemBinding *inChildBinding, CStateRow *inNextRow);
+
+ double m_TimeRatio;
+ CFilter m_Filter;
+ CListLayout m_ColorList;
+ CListLayout m_TreeList;
+ CListLayout m_ToggleList;
+ CListLayout m_TimebarList;
+
+ CBaseTimelineTreeControl *m_TreeControl;
+ CColorControl *m_ColorControl;
+ CBlankToggleControl *m_ToggleControl;
+ CBaseTimebarlessRow *m_TimebarControl;
+
+ TStateRowList m_StateRows;
+ TPropertyRowList m_PropertyRows;
+
+ bool m_Loaded;
+ bool m_IsExpanded;
+ bool m_Highlighted;
+ bool m_Dirty;
+ bool m_Selected;
+
+ ITimelineItemBinding *m_TimelineItemBinding;
+
+ long m_ActiveStart;
+ long m_ActiveEnd;
+};
+#endif // INCLUDED_BASE_STATE_ROW_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.cpp b/src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.cpp
new file mode 100644
index 00000000..4ded07dd
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.cpp
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "BaseTimebarlessRow.h"
+#include "Renderer.h"
+#include "StudioPreferences.h"
+#include "BaseStateRow.h"
+
+CBaseTimebarlessRow::CBaseTimebarlessRow()
+ : m_Selected(false)
+ , m_DirtyFlag(true)
+ , m_TimeRatio(0.0f)
+{
+}
+
+CBaseTimebarlessRow::~CBaseTimebarlessRow()
+{
+}
+
+void CBaseTimebarlessRow::Draw(CRenderer *inRenderer)
+{
+ CRct theRect(GetSize());
+
+ // Fill in the background
+ if (!m_Selected)
+ inRenderer->FillSolidRect(theRect, m_BackgroundColor);
+ else
+ inRenderer->FillSolidRect(theRect, CStudioPreferences::GetTimelineSelectColor());
+
+ // Draw the line at the bottom of this control and the one on the side
+ inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor());
+ inRenderer->MoveTo(CPt(0, theRect.size.y - 1));
+ inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1));
+ inRenderer->PopPen();
+}
+
+//=============================================================================
+/**
+ * Set this control to being highlighted or not.
+ * @param inIsHighlighted true if this is to be highlighted.
+ */
+void CBaseTimebarlessRow::SetBackgroundColor(::CColor inBackgroundColor)
+{
+ if (m_BackgroundColor != inBackgroundColor) {
+ m_BackgroundColor = inBackgroundColor;
+ Invalidate();
+ }
+}
+
+void CBaseTimebarlessRow::SetTimeRatio(double inTimeRatio)
+{
+ m_TimeRatio = inTimeRatio;
+}
+
+//=============================================================================
+/**
+ * Notification that the object that this row is representing has been selected.
+ */
+void CBaseTimebarlessRow::OnSelect()
+{
+ m_Selected = true;
+
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Notification that the object that this row is representing has been deselected.
+ */
+void CBaseTimebarlessRow::OnDeselect()
+{
+ m_Selected = false;
+
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * called when meta data for this row is changed... should be overridden by the
+ * timebar row
+ */
+void CBaseTimebarlessRow::RefreshRowMetaData()
+{
+}
+
+//=============================================================================
+/**
+ * called when a child changes and the keyframes need to be refreshed
+ * @param inDirtyFlag true if this object is now dirty
+ */
+void CBaseTimebarlessRow::SetDirty(bool inDirtyFlag)
+{
+ if (m_DirtyFlag == inDirtyFlag)
+ return;
+
+ m_DirtyFlag = inDirtyFlag;
+ Invalidate();
+}
+
+void CBaseTimebarlessRow::UpdateTime(long inStartTime, long inEndTime)
+{
+ Q_UNUSED(inStartTime);
+ Q_UNUSED(inEndTime);
+}
+
+//=============================================================================
+/**
+ * OnMouseOver event, handles the highlighting of the row.
+ * @param inPoint the location of the mouse over this control.
+ * @param inFlags the mouse state flags.
+ */
+void CBaseTimebarlessRow::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOver(inPoint, inFlags);
+
+ GetBaseStateRow()->OnMouseOver();
+}
+
+//=============================================================================
+/**
+ * OnMouseOut event, handles the de-highlighting of this row.
+ * @param inPoint the location of the mouse over this control.
+ * @param inFlags the mouse state flags.
+ */
+void CBaseTimebarlessRow::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOut(inPoint, inFlags);
+
+ GetBaseStateRow()->OnMouseOut();
+}
+
+//=============================================================================
+/**
+ * OnMouseDown event, handles the selecting of this object.
+ * @param inPoint the location of the mouse over this control.
+ * @param inFlags the mouse state flags.
+ */
+bool CBaseTimebarlessRow::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ return CControl::OnMouseDown(inPoint, inFlags);
+#if 0
+ // this addition is causing 4085: Cannot do rubber band selection from sections of timeline that don't contain timebars anymore
+ bool theReturn = CControl::OnMouseDown( inPoint, inFlags );
+ if ( !theReturn )
+ {
+ // Tests if the user has pressed the modifier key, where the intention is to multi-select keyframes.
+ if ( !(inFlags & CHotKeys::MODIFIER_CONTROL ) )
+ {
+ // SK - I changed this to select the row when this is clicked, because I think its a nice feature. ie don't always have to click on the timebar (esp for those e.g. scene without one)
+ // when the modifier key is pressed.
+ GetBaseStateRow( )->Select( false );
+
+ theReturn = true;
+ }
+ }
+ return theReturn;
+#endif
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.h b/src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.h
new file mode 100644
index 00000000..9c2fbea4
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_BASE_TIMEBARLESS_ROW_H
+#define INCLUDED_BASE_TIMEBARLESS_ROW_H 1
+
+#pragma once
+
+#include "Control.h"
+#include "CColor.h"
+
+class CSnapper;
+class CBaseStateRow;
+class ISnappingListProvider;
+
+class CBaseTimebarlessRow : public CControl
+{
+public:
+ CBaseTimebarlessRow();
+ virtual ~CBaseTimebarlessRow();
+
+ void Draw(CRenderer *inRenderer) override;
+
+ virtual void SetBackgroundColor(::CColor inColor);
+ virtual void SetTimeRatio(double inTimeRatio);
+
+ virtual void RefreshRowMetaData();
+
+ virtual void OnSelect();
+ virtual void OnDeselect();
+
+ void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+ virtual void SetDirty(bool inIsDirty);
+ virtual void UpdateTime(long inStartTime, long inEndTime);
+
+ virtual void CommitSelections() = 0;
+ virtual void SelectKeysInRect(CRct inRect, bool inModifierKeyDown) = 0;
+ virtual void SelectAllKeys() = 0;
+ virtual void SelectKeysByTime(long inTime, bool inSelected) = 0;
+ virtual void PopulateSnappingList(CSnapper *inSnappingList) = 0;
+ virtual ISnappingListProvider &GetSnappingListProvider() const = 0;
+
+protected:
+ virtual CBaseStateRow *GetBaseStateRow() const = 0;
+
+ ::CColor m_BackgroundColor;
+ bool m_Selected;
+ bool m_DirtyFlag;
+ double m_TimeRatio;
+};
+#endif // INCLUDED_BASE_TIMEBARLESS_ROW_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.cpp b/src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.cpp
new file mode 100644
index 00000000..3221f6a1
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.cpp
@@ -0,0 +1,685 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "Renderer.h"
+#include "ToggleButton.h"
+#include "BaseStateRow.h"
+#include "StudioPreferences.h"
+#include "TimelineDropTarget.h"
+#include "BaseTimelineTreeControl.h"
+#include "NameEdit.h"
+#include "Bindings/ITimelineItem.h"
+#include "StudioPreferences.h"
+
+//=============================================================================
+/**
+ * Create a new tree control for the specified state row.
+ * This control contains the toggle button and item name controls.
+ * @param inStateRow the state row of which this belongs to.
+ */
+CBaseTimelineTreeControl::CBaseTimelineTreeControl(CBaseStateRow *inStateRow, bool inMaster)
+ : m_Selected(false)
+ , m_MouseDown(false)
+{
+ m_StateRow = inStateRow;
+
+ m_BackgroundColor = m_StateRow->GetTimebarBackgroundColor(m_StateRow->GetObjectType());
+
+ // Create the expand/collapse button.
+ m_ExpandButton = new CToggleButton();
+ m_ExpandButton->SetUpImage("arrow.png");
+ m_ExpandButton->SetDownImage("arrow_down.png");
+
+ // Add the button and initialize all the listeners for the events on it.
+ AddChild(m_ExpandButton);
+ m_ExpandButton->SigToggle.connect(std::bind(&CBaseStateRow::ToggleExpansion, m_StateRow,
+ std::placeholders::_1, std::placeholders::_2));
+ m_ExpandButton->SetVisible(false);
+
+ m_Icon = new CSIcon(m_StateRow->GetIcon(), m_StateRow->GetDisabledIcon());
+ AddChild(m_Icon);
+
+ // Create and add the name label.
+ m_Text = nullptr; // withdrawn from constructor to delay creation of text object
+
+ // Initialize all the component's positions to 0.
+ SetIndent(CStudioPreferences::GetRowSize());
+
+ SetMinimumSize(CPt(CBaseStateRow::DEFAULT_TOGGLE_LENGTH + m_Icon->GetPosition().x
+ + m_Icon->GetSize().x + 5,
+ CStudioPreferences::GetRowSize()));
+
+ m_TrackingPoint.x = 0;
+ m_TrackingPoint.y = 0;
+ m_DrawAcceptBefore = false;
+ m_DrawAcceptAfter = false;
+
+ // Set up default text colors
+ m_NormalTextColor = CStudioPreferences::GetNormalColor();
+ m_SelectedTextColor = CStudioPreferences::GetNormalColor();
+ if (inMaster) {
+ m_NormalTextColor = CStudioPreferences::GetMasterColor();
+ m_SelectedTextColor = CStudioPreferences::GetMasterColor();
+ }
+ m_LockedTextColor = CStudioPreferences::GetLockedTextColor();
+}
+
+CBaseTimelineTreeControl::~CBaseTimelineTreeControl()
+{
+ delete m_Icon;
+ delete m_ExpandButton;
+ delete m_Text;
+}
+
+//=============================================================================
+/**
+ * Create a new text object. For performance reasons we delay
+ * creating this object until it is needed, i.e. until the row is exposed
+ * by the user and the Draw method is called
+ */
+void CBaseTimelineTreeControl::CreateText()
+{
+ if (!m_Text) {
+ ITimelineItem *theTimelineItem = m_StateRow->GetTimelineItem();
+
+ m_Text = new CNameEdit(theTimelineItem);
+
+ m_Text->SetSize(
+ CPt(CStudioPreferences::GetTimelineNameSize(),
+ CStudioPreferences::GetRowSize() - 3)); /* m_ExpandButton->GetSize( ).y - 3*/
+ // m_Text->SetBGColorNoFocus( CStudioPreferences::GetNormalColor( ) );
+ // if ( theTimelineItem->IsMaster( ) )
+ // m_Text->SetBGColorNoFocus( CStudioPreferences::GetMasterColor( ) );
+ // m_Text->SetFillBackground( false );
+ m_Text->SetBoldText(false);
+
+ // If the object is the scene, you can't edit it's name
+ m_Text->SetEditable(m_StateRow->GetObjectType() != OBJTYPE_SCENE);
+ AddChild(m_Text);
+ m_Text->SetPosition(CPt(m_Icon->GetPosition().x + m_Icon->GetSize().x + 5, 1));
+
+ // This was disabled before Text was created.
+ if (!IsEnabled()) {
+ m_Text->SetEnabled(false);
+ m_Text->SetParentEnabled(false);
+ m_Text->SetTextColor(m_LockedTextColor);
+ } else // since we do delay-creation, "sync" with the parent's selection state
+ UpdateTextSelection();
+
+ // This is so that make the timeline scrollbar scrolls correctly
+ // ( i.e. to the end of the asset name )
+ CPt theSize(GetSize());
+ theSize.x =
+ CBaseStateRow::DEFAULT_TOGGLE_LENGTH + m_Text->GetPosition().x + m_Text->GetSize().x;
+ SetAbsoluteSize(theSize);
+ }
+}
+
+void CBaseTimelineTreeControl::UpdateTextSelection()
+{
+ // since we do delay-creation for the Text only when we have to draw it.. this checks if it is
+ // created first
+ if (m_Text) {
+ if (!IsEnabled())
+ m_Text->SetTextColor(m_LockedTextColor);
+ else
+ m_Text->SetTextColor(m_Selected ? m_SelectedTextColor : m_NormalTextColor);
+ // m_Text->SetFillBackground( m_Selected );
+ // m_Text->SetBoldText( m_Selected );
+ }
+}
+
+//=============================================================================
+/**
+ * Perform the drawing of this control.
+ * @param inRenderer the renderer to draw to.
+ */
+void CBaseTimelineTreeControl::Draw(CRenderer *inRenderer)
+{
+ CreateText(); // the row is now exposed and we can't delay creating the text object any longer
+
+ CRct theRect(GetSize());
+ // Fill in the background
+ if (!m_Selected)
+ inRenderer->FillSolidRect(theRect, m_BackgroundColor);
+ else
+ inRenderer->FillSolidRect(theRect, CStudioPreferences::GetTimelineSelectColor());
+
+ // if ( m_Text )
+ // m_Text->SetBoldText( m_Selected );
+ // m_Text->SetFillBackground( m_Selected );
+
+ // Draw the line at the bottom of this control
+ inRenderer->PushPen(CStudioPreferences::GetTreeFloorColor());
+ inRenderer->MoveTo(CPt(0, theRect.size.y - 1));
+ inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1));
+ inRenderer->PopPen();
+}
+
+//=============================================================================
+/**
+ * Override for the set parent enabled function which tells children the state of the parent
+ */
+void CBaseTimelineTreeControl::SetEnabled(bool inIsEnabled)
+{
+ CControl::SetEnabled(inIsEnabled);
+ if (m_Text) {
+ m_Text->SetEnabled(inIsEnabled);
+ if (!inIsEnabled)
+ m_Text->SetTextColor(m_LockedTextColor);
+ else
+ m_Text->SetTextColor(m_Selected ? m_SelectedTextColor : m_NormalTextColor);
+ Invalidate();
+ }
+}
+
+//=============================================================================
+/**
+ * Notification that something has changed on the asset that this
+ * represents, update it.
+ */
+void CBaseTimelineTreeControl::Refresh(ITimelineItem *inTimelineItem)
+{
+ bool theEnabled = !inTimelineItem->IsLocked();
+ if (m_Text) {
+ // Make sure the color is correct depending on if its is a master object
+ if (m_NormalTextColor != CStudioPreferences::GetMasterColor()
+ && inTimelineItem->IsMaster()) {
+ m_NormalTextColor = CStudioPreferences::GetMasterColor();
+ m_Text->SetBGColorNoFocus(CStudioPreferences::GetMasterColor());
+ if (!m_Selected)
+ m_Text->SetTextColor(m_NormalTextColor);
+ }
+
+ m_Text->SetData(inTimelineItem->GetName());
+ }
+ m_Icon->SetImage((theEnabled) ? m_StateRow->GetIcon() : m_StateRow->GetDisabledIcon());
+ SetEnabled(theEnabled);
+}
+
+//=============================================================================
+/**
+ * Set the indent of this control.
+ * The indent gives the semblance of a tree control, and causes the toggle
+ * name and icon to be pushed in some.
+ * @param inIndent the indent for this control.
+ */
+void CBaseTimelineTreeControl::SetIndent(long inIndent)
+{
+ m_Indent = inIndent;
+
+ // Set the new position for all the children.
+ m_ExpandButton->SetPosition(CPt(inIndent, 0));
+
+ m_Icon->SetPosition(CPt(m_ExpandButton->GetPosition().x + m_ExpandButton->GetSize().x, 0));
+ if (m_Text)
+ m_Text->SetPosition(CPt(m_Icon->GetPosition().x + m_Icon->GetSize().x + 5, 1));
+}
+
+//=============================================================================
+/**
+ * Get the current indent of this control.
+ */
+long CBaseTimelineTreeControl::GetIndent()
+{
+ return m_Indent;
+}
+
+//=============================================================================
+/**
+ * Set whether or not to have the toggle control visible.
+ * The toggle is turned off by the state row when there are no visible children.
+ * @param inIsToggleVisible false if the toggle is not to be visible.
+ */
+void CBaseTimelineTreeControl::SetToggleVisible(bool inIsToggleVisible)
+{
+ m_ExpandButton->SetVisible(inIsToggleVisible);
+}
+
+//=============================================================================
+/**
+ * Set whether or not this control is expanded.
+ * This is used to set the state of the expand button.
+ */
+void CBaseTimelineTreeControl::SetExpanded(bool inIsExpanded)
+{
+ m_ExpandButton->SetToggleState(inIsExpanded);
+}
+
+//=============================================================================
+/**
+ * Set the current background color for this control.
+ * The background color changes when the control gets a mouse over/mouse out.
+ */
+void CBaseTimelineTreeControl::SetBackgroundColor(CColor inColor)
+{
+ if (m_BackgroundColor == inColor)
+ return;
+
+ m_BackgroundColor = inColor;
+
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Notify the row that a mouse out occurred.
+ * The row will in turn turn off the highlighting.
+ * @param inPoint the location of the mouse.
+ * @param inFlags the state of the mouse.
+ */
+void CBaseTimelineTreeControl::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ m_DrawAcceptAfter = false;
+ m_DrawAcceptBefore = false;
+
+ CControl::OnMouseOut(inPoint, inFlags);
+
+ m_StateRow->OnMouseOut();
+
+ if (m_TimerHandler) {
+
+ // nullptr out our handle so we can create a new one.
+ m_TimerHandler = std::shared_ptr<UICDM::ISignalConnection>();
+ }
+
+ AcceptDropAfter(false);
+ AcceptDropBefore(false);
+}
+
+//=============================================================================
+/**
+ * Notify the row that a mouse over occurred.
+ * The row will in turn turn on the highlighting.
+ * @param inPoint the location of the mouse.
+ * @param inFlags the state of the mouse.
+ */
+void CBaseTimelineTreeControl::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOver(inPoint, inFlags);
+
+ m_StateRow->OnMouseOver();
+}
+
+//=============================================================================
+/**
+ * Pass the double click notification on to the row and have it process it.
+ * The row will do object-specific actions on doubleclicks.
+ * @param inPoint the location of the mouse.
+ * @param inFlags the state of the mouse.
+ * @return true stating that the event was processed.
+ */
+bool CBaseTimelineTreeControl::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseDoubleClick(inPoint, inFlags)) {
+ m_StateRow->OnMouseDoubleClick(inPoint, inFlags);
+ GrabFocus(nullptr);
+ }
+ return true;
+}
+
+//=============================================================================
+/**
+ * Handles mouse down on the this control. Flags the button as down which results
+ * in some possible drawing changes.
+ * @param inPoint location of the mouse when event occurred
+ * @param inFlags state of modifier keys when event occurred
+ * @return true
+ */
+bool CBaseTimelineTreeControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseDown(inPoint, inFlags)) {
+ SBaseStateRowSelectionKeyState theKeyState;
+ if ((CHotKeys::MODIFIER_SHIFT & inFlags) == CHotKeys::MODIFIER_SHIFT)
+ theKeyState.SetShiftDown();
+ if ((CHotKeys::MODIFIER_CONTROL & inFlags) == CHotKeys::MODIFIER_CONTROL)
+ theKeyState.SetControlDown();
+ m_StateRow->Select(theKeyState);
+
+ // Always track where the mouse is.
+ m_MouseDown = true;
+
+ Invalidate();
+ }
+
+ return true;
+}
+
+bool CBaseTimelineTreeControl::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseRDown(inPoint, inFlags))
+ m_StateRow->OnMouseRDown(inPoint, inFlags);
+
+ return true;
+}
+
+void CBaseTimelineTreeControl::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ m_MouseDown = false;
+
+ CControl::OnMouseUp(inPoint, inFlags);
+
+ AcceptDropAfter(false);
+ AcceptDropBefore(false);
+}
+
+//=============================================================================
+/**
+ * This method handles the keydown event for a StateTreeControl. It calls
+ * CControl::OnKeyDown method to make sure that the keydown event is handled
+ * by its children. If the keydown event is not handled and F2 is down, it
+ * enables text edit mode.
+ * @param inChar is the char pressed
+ * @param inFlags state of modifier keys when event occurred
+ * @return if the key was handled
+ */
+bool CBaseTimelineTreeControl::OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inFlags)
+{
+ bool theKeyWasHandled = CControl::OnKeyDown(inChar, inFlags);
+
+ if (!theKeyWasHandled && (inChar == Qt::Key_F2)) {
+ DoRename();
+ theKeyWasHandled = true;
+ }
+
+ return theKeyWasHandled;
+}
+
+//=============================================================================
+/**
+ * This is so the Gesture can this object to get something ready to Drag.
+ */
+void CBaseTimelineTreeControl::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseMove(inPoint, inFlags);
+
+ if (m_MouseDown /*&& inFlags & MOUSE_LBUTTON*/) {
+ long theDeltaX = inPoint.x - m_TrackingPoint.x;
+ long theDeltaY = inPoint.y - m_TrackingPoint.y;
+
+ if (::abs(theDeltaX) > 3 || ::abs(theDeltaY) > 3) {
+ m_TrackingPoint = inPoint;
+
+ m_StateRow->DoStartDrag(GetWindowListener());
+ }
+ }
+}
+
+//=============================================================================
+/**
+ * Notification that the state that this is displaying has been selected.
+ */
+void CBaseTimelineTreeControl::OnSelect()
+{
+ m_Selected = true;
+
+ UpdateTextSelection();
+
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Notification that the state that this is displaying has been deselected.
+ */
+void CBaseTimelineTreeControl::OnDeselect()
+{
+ m_Selected = false;
+
+ UpdateTextSelection();
+ Invalidate();
+}
+
+void CBaseTimelineTreeControl::GrabTextFocus()
+{
+ GrabFocus(m_Text);
+}
+
+//=============================================================================
+/**
+ * To enable F2 editing.
+ */
+void CBaseTimelineTreeControl::OnGainFocus()
+{
+ CControl::OnGainFocus();
+ GrabFocus(m_Text);
+}
+
+//=============================================================================
+/**
+ * Called when this control loses focus. Overridden because we need to set the
+ * text color depending on whether or not the asset for this row is still
+ * selected.
+ */
+void CBaseTimelineTreeControl::OnLoseFocus()
+{
+ CControl::OnLoseFocus();
+
+ if (m_Text) {
+ if (m_Selected) {
+ m_Text->SetTextColor(m_SelectedTextColor);
+ } else // If this asset is no longer selected
+ {
+ // If the row is enabled, use the normal text color
+ if (m_Text->IsEnabled()) {
+ m_Text->SetTextColor(m_NormalTextColor);
+ }
+ // Otherwise use the locked text color
+ else {
+ m_Text->SetTextColor(m_LockedTextColor);
+ }
+ }
+ }
+
+ AcceptDropAfter(false);
+ AcceptDropBefore(false);
+}
+
+//=============================================================================
+/**
+ * If the name is changed, the size has to be adjusted accordingly.
+ */
+void CBaseTimelineTreeControl::OnChildSizeChanged(CControl *inChild)
+{
+ CControl::OnChildSizeChanged(inChild);
+
+ if (inChild == m_Text) { // This is so that make the timeline scrollbar scrolls correctly
+ // ( i.e. to the end of the asset name )
+ CPt theSize(GetSize());
+ theSize.x =
+ CBaseStateRow::DEFAULT_TOGGLE_LENGTH + m_Text->GetPosition().x + m_Text->GetSize().x;
+ SetAbsoluteSize(theSize);
+ }
+}
+
+//=============================================================================
+/**
+ * This will do a vertical hit test on this control.
+ * This need to figure out if the point is toward teh top or toward the bottom, or on this
+ *control.
+ * @param inMousePoint the point where the dropp wants to occure.
+ * @return An enumeration representing the location of the potential drop.
+ */
+CBaseTimelineTreeControl::ECONTROLREGION CBaseTimelineTreeControl::FindHitRegion(CPt &inMousePoint)
+{
+ // Default Region is "on"
+ CBaseTimelineTreeControl::ECONTROLREGION theDropRegion =
+ CBaseTimelineTreeControl::ECONTROLREGION_ON;
+
+ CPt theSize = GetSize();
+ long theTop = 0;
+ long theBottom = theSize.y - 1;
+ long thePointY = inMousePoint.y;
+
+ // check if we are in the upper part of the control
+ if ((thePointY >= theTop) && (thePointY <= (theTop + 3))) {
+ theDropRegion = CBaseTimelineTreeControl::ECONTROLREGION_ABOVE;
+ }
+ // check if we are in the lower part of the control
+ else if ((thePointY <= (theBottom)) && (thePointY >= (theBottom - 3))) {
+ theDropRegion = CBaseTimelineTreeControl::ECONTROLREGION_BELOW;
+ }
+
+ return theDropRegion;
+}
+
+//=============================================================================
+/**
+ * Find an object under the point.
+ * If tht point is close to the top or the bottom of the control,
+ * then the Asset to use would be the parent of the current asset.
+ * @param inMousePoint the point where the Drop wants to occure.
+ */
+CDropTarget *CBaseTimelineTreeControl::BuildDropTarget(CPt &inMousePoint, Qt::KeyboardModifiers inFlags)
+{
+ Q_UNUSED(inFlags);
+
+ // This will do the hit testing to see where we are with the point.
+ ECONTROLREGION theRegion = FindHitRegion(inMousePoint);
+
+ // Make a new DropTarget to return.
+ CTimeLineDropTarget *theTarget = new CTimeLineDropTarget();
+
+ EDROPDESTINATION theDropDest = EDROPDESTINATION_ON;
+
+ switch (theRegion) {
+ case ECONTROLREGION_BELOW:
+ theDropDest = EDROPDESTINATION_BELOW;
+
+ AcceptDropAfter(true);
+ AcceptDropBefore(false);
+ break;
+
+ case ECONTROLREGION_ABOVE:
+ theDropDest = EDROPDESTINATION_ABOVE;
+
+ AcceptDropAfter(false);
+ AcceptDropBefore(true);
+ break;
+
+ case ECONTROLREGION_ON:
+
+ AcceptDropAfter(false);
+ AcceptDropBefore(false);
+ break;
+ }
+ theTarget->SetDestination(theDropDest);
+ // For insertion markers
+ theTarget->SetInsertionMarkerRow(this);
+ theTarget->SetInsertionMarkerIndent(m_Icon->GetPosition().x);
+
+ // connect the data portion of the drag&drop action
+ m_StateRow->SetDropTarget(theTarget);
+
+ return theTarget;
+}
+
+//=============================================================================
+/**
+ * This function is overriden from the CControl class.
+ * It will find an Asset that can be dropped upon. Also it will
+ * figureout if the DropTarget should contain this Asset or the parent
+ * of this Asset.
+ * @param inMousePoint the coords [in local space] of the drop action.
+ * @param inFlags the Modifier flags for the keyboard state.
+ * @return the found DropTarget or null if not found.
+ */
+CDropTarget *CBaseTimelineTreeControl::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags)
+{
+ // Make sure the Mouse Highlighting happens.
+ m_StateRow->OnMouseOver();
+
+ // This will do all of the work.
+ CDropTarget *theReturnTarget = BuildDropTarget(inMousePoint, inFlags);
+
+ // Expand the object [ once again ask CE for an explaination of this ]
+ if (!m_TimerHandler && m_ExpandButton->IsVisible() && m_ExpandButton->IsEnabled()) {
+ if (!m_DrawAcceptBefore && !m_DrawAcceptAfter)
+ m_TimerHandler = Q3DStudio::ITickTock::GetInstance().AddTimer(
+ 1000, false, std::bind(&CBaseTimelineTreeControl::OnTimer, this),
+ "CStateTreeControl::FindDropCandidate::" + GetName());
+ }
+
+ // we always return true, since we should be the only one to handle it.
+ return theReturnTarget;
+}
+
+//=============================================================================
+/**
+ * Notification that the Hover Time has expired,
+ */
+void CBaseTimelineTreeControl::OnTimer()
+{
+ // Expand the Row to show the children.
+ m_StateRow->Expand();
+}
+
+//=============================================================================
+/**
+ * This will set the Flag so we can Draw the Bottom Line.
+ * @param inAccept true to draw the line false otherwise.
+ */
+void CBaseTimelineTreeControl::AcceptDropAfter(bool inAccept)
+{
+ if (inAccept != m_DrawAcceptAfter) {
+ m_DrawAcceptAfter = inAccept;
+ }
+}
+
+//=============================================================================
+/**
+ * This will set the Flag so we can Draw the Top Line.
+ * @param inAccept true to draw the line false otherwise.
+ */
+void CBaseTimelineTreeControl::AcceptDropBefore(bool inAccept)
+{
+ if (inAccept != m_DrawAcceptBefore) {
+ m_DrawAcceptBefore = inAccept;
+ }
+}
+
+//=============================================================================
+/**
+ * Called by the state context menu to do the renaming portion of the menu
+ */
+void CBaseTimelineTreeControl::DoRename()
+{
+ CreateText();
+ m_Text->SetEditMode(true);
+ GrabFocus(m_Text);
+ m_Text->SelectAllText();
+}
+
+void CBaseTimelineTreeControl::SetNameReadOnly(bool inReadOnly)
+{
+ CreateText(); // Create the text if it's not ready.
+ m_Text->SetEditable(!inReadOnly);
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.h b/src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.h
new file mode 100644
index 00000000..e348cccf
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_BASE_TIMELINE_TREE_CONTROL_H
+#define INCLUDED_BASE_TIMELINE_TREE_CONTROL_H 1
+
+#pragma once
+
+#include "Control.h"
+#include "SIcon.h"
+#include "ToggleButton.h"
+#include "ITickTock.h"
+
+class CButtonControl;
+class CBaseStateRow;
+class CDropTarget;
+class CNameEdit;
+class CTickTockProc;
+struct STickTockHandle;
+class CPt;
+class CToggleButton;
+class ITimelineItem;
+
+class CBaseTimelineTreeControl : public CControl
+{
+
+public:
+ enum ECONTROLREGION { ECONTROLREGION_ON, ECONTROLREGION_ABOVE, ECONTROLREGION_BELOW };
+
+ CBaseTimelineTreeControl(CBaseStateRow *inStateRow, bool inMaster);
+ virtual ~CBaseTimelineTreeControl();
+
+ void Draw(CRenderer *inRenderer) override;
+ void OnChildSizeChanged(CControl *inChild) override;
+
+ void SetIndent(long inIndent);
+ long GetIndent();
+
+ void SetExpanded(bool inIsExpanded);
+
+ void SetToggleVisible(bool inIsToggleVisible);
+ void OnSelect();
+ void OnDeselect();
+ void GrabTextFocus();
+ void OnGainFocus() override;
+ void OnLoseFocus() override;
+ void SetBackgroundColor(::CColor inBackgroundColor);
+
+ void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inFlags) override;
+
+ void OnTimer();
+
+ void Refresh(ITimelineItem *inTimelineItem);
+
+ void SetEnabled(bool inIsEnabled) override;
+
+ CDropTarget *BuildDropTarget(CPt &inMousePoint, Qt::KeyboardModifiers inFlags);
+ CDropTarget *FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags) override;
+ void AcceptDropAfter(bool inAccept);
+ void AcceptDropBefore(bool inAccept);
+ void DoRename();
+
+ void SetNameReadOnly(bool inReadOnly);
+
+protected:
+ ECONTROLREGION FindHitRegion(CPt &inMousePoint);
+ void CreateText(); // delay text creation until row is exposed
+ void UpdateTextSelection();
+
+ long m_Indent;
+
+ CBaseStateRow *m_StateRow;
+
+ CToggleButton *m_ExpandButton;
+ CNameEdit *m_Text;
+
+ CSIcon *m_Icon;
+ bool m_Selected;
+
+ ::CColor m_BackgroundColor;
+
+ CPt m_TrackingPoint;
+ CPt m_MouseMovePoint;
+ bool m_MouseDown;
+ bool m_DrawAcceptBefore;
+ bool m_DrawAcceptAfter;
+ std::shared_ptr<UICDM::ISignalConnection> m_TimerHandler;
+ ::CColor m_NormalTextColor;
+ ::CColor m_SelectedTextColor;
+ ::CColor m_LockedTextColor;
+};
+#endif // INCLUDED_BASE_TIMELINE_TREE_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.cpp
new file mode 100644
index 00000000..196d345d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "BehaviorTimelineItemBinding.h"
+#include "TimelineTranslationManager.h"
+#include "StudioApp.h"
+#include "UICDMStudioSystem.h"
+#include "ClientDataModelBridge.h"
+#include "Doc.h"
+
+using namespace UICDM;
+
+CBehaviorTimelineItemBinding::CBehaviorTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ CUICDMInstanceHandle inDataHandle)
+ : CUICDMTimelineItemBinding(inMgr, inDataHandle)
+{
+}
+
+EStudioObjectType CBehaviorTimelineItemBinding::GetObjectType() const
+{
+ return OBJTYPE_BEHAVIOR;
+}
+
+//=============================================================================
+/**
+ * Open the associated item as though it was double-clicked in explorer
+ */
+bool CBehaviorTimelineItemBinding::OpenAssociatedEditor()
+{
+ return OpenSourcePathFile();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.h
new file mode 100644
index 00000000..b75d100c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_BEHAVIOR_TIMELINEITEM_BINDING_H
+#define INCLUDED_BEHAVIOR_TIMELINEITEM_BINDING_H 1
+
+#pragma once
+
+#include "UICDMTimelineItemBinding.h"
+
+//==============================================================================
+// Classes
+//==============================================================================
+class CTimelineTranslationManager;
+
+//=============================================================================
+/**
+ * Binding to a UICDM object of Behavior type
+ */
+class CBehaviorTimelineItemBinding : public CUICDMTimelineItemBinding
+{
+public:
+ CBehaviorTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ UICDM::CUICDMInstanceHandle inDataHandle);
+ ~CBehaviorTimelineItemBinding() {}
+
+ // CUICDMTimelineItemBinding
+ EStudioObjectType GetObjectType() const override;
+ bool OpenAssociatedEditor() override;
+};
+
+#endif // INCLUDED_BEHAVIOR_TIMELINEITEM_BINDING_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.cpp
new file mode 100644
index 00000000..7534fa73
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "EmptyTimelineTimebar.h"
+#include "StudioPreferences.h"
+
+CEmptyTimelineTimebar::CEmptyTimelineTimebar()
+{
+}
+
+CEmptyTimelineTimebar::~CEmptyTimelineTimebar()
+{
+}
+
+long CEmptyTimelineTimebar::GetStartTime() const
+{
+ return 0;
+}
+
+long CEmptyTimelineTimebar::GetEndTime() const
+{
+ return 0;
+}
+
+long CEmptyTimelineTimebar::GetDuration() const
+{
+ return 0;
+}
+
+bool CEmptyTimelineTimebar::ShowHandleBars() const
+{ // makes no sense to show handle bars, when this does not have start/end times.
+ return false;
+}
+
+void CEmptyTimelineTimebar::OnBeginDrag()
+{
+}
+
+void CEmptyTimelineTimebar::OffsetTime(long inDiff)
+{
+ Q_UNUSED(inDiff);
+}
+
+void CEmptyTimelineTimebar::ChangeTime(long inTime, bool inSetStart)
+{
+ Q_UNUSED(inTime);
+ Q_UNUSED(inSetStart);
+}
+
+void CEmptyTimelineTimebar::CommitTimeChange()
+{
+}
+
+void CEmptyTimelineTimebar::RollbackTimeChange()
+{
+}
+
+::CColor CEmptyTimelineTimebar::GetTimebarColor()
+{
+ return CStudioPreferences::GetObjectTimebarColor();
+}
+
+void CEmptyTimelineTimebar::SetTimebarColor(const ::CColor &inColor)
+{
+ Q_UNUSED(inColor);
+}
+
+Q3DStudio::CString CEmptyTimelineTimebar::GetTimebarComment()
+{
+ return "";
+}
+
+void CEmptyTimelineTimebar::SetTimebarComment(const Q3DStudio::CString &inComment)
+{
+ Q_UNUSED(inComment);
+}
+
+void CEmptyTimelineTimebar::SetTimebarTime(ITimeChangeCallback *inCallback /*= nullptr*/)
+{
+ Q_UNUSED(inCallback);
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.h
new file mode 100644
index 00000000..9aacb524
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#pragma once
+
+#include "ITimelineTimebar.h"
+
+//=============================================================================
+/**
+ * The current timeline UI design is such that even when no timebar shows up ( with the exception of
+ * the top row, ie the time context )
+ * there is a timebar control to store the keyframes for the animated properties.
+ * Hence, instead of return nullptr for GetTimebar for ITimelineItem, this class will ensure the UI
+ * classes still work.
+ */
+class CEmptyTimelineTimebar : public ITimelineTimebar
+{
+public:
+ CEmptyTimelineTimebar();
+ virtual ~CEmptyTimelineTimebar();
+
+ // ITimelineTimebar
+ long GetStartTime() const override;
+ long GetEndTime() const override;
+ long GetDuration() const override;
+ bool ShowHandleBars() const override;
+ void OnBeginDrag() override;
+ void OffsetTime(long inDiff) override;
+ void ChangeTime(long inTime, bool inSetStart) override;
+ void CommitTimeChange() override;
+ void RollbackTimeChange() override;
+ ::CColor GetTimebarColor() override;
+ void SetTimebarColor(const ::CColor &inColor) override;
+ Q3DStudio::CString GetTimebarComment() override;
+ void SetTimebarComment(const Q3DStudio::CString &inComment) override;
+ void SetTimebarTime(ITimeChangeCallback *inCallback = nullptr) override;
+};
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.cpp
new file mode 100644
index 00000000..322cbd33
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "GroupTimelineItemBinding.h"
+#include "BaseStateRow.h"
+#include "TimelineTranslationManager.h"
+#include "StudioApp.h"
+#include "Core.h"
+#include "Dialogs.h"
+
+// Data model specific
+#include "Doc.h"
+#include "CmdGeneric.h"
+
+#include "UICDMStudioSystem.h"
+#include "ClientDataModelBridge.h"
+#include "UICDMSlides.h"
+#include "UICDMDataCore.h"
+#include "UICFileTools.h"
+
+using namespace UICDM;
+
+CGroupTimelineItemBinding::CGroupTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ CUICDMInstanceHandle inDataHandle)
+ : CUICDMTimelineItemBinding(inMgr, inDataHandle)
+{
+}
+
+//=============================================================================
+/**
+ * Ideally we like to be able to edit the component in a different editor ( we've been hoping for
+ * that feature ) BUT we don't have that,
+ * and it has always been we 'dive' into the component within Studio.
+ */
+bool CGroupTimelineItemBinding::OpenAssociatedEditor()
+{
+ if (GetObjectType() == OBJTYPE_COMPONENT) {
+ ISlideSystem *theSlideSystem = m_StudioSystem->GetSlideSystem();
+
+ UICDM::CUICDMInstanceHandle theInstance = GetInstance();
+ Q3DStudio::CId theId = m_StudioSystem->GetClientDataModelBridge()->GetGUID(theInstance);
+ UICDM::CUICDMSlideHandle theMasterSlide =
+ theSlideSystem->GetMasterSlideByComponentGuid(GuidtoSLong4(theId));
+
+ if (theMasterSlide.Valid()) {
+ CUICDMSlideHandle theActiveSlide = theSlideSystem->GetActiveSlide(theMasterSlide);
+
+ CCmd *theCmd = new CCmdGeneric<CDoc, CUICDMSlideHandle>(
+ m_TransMgr->GetDoc(), &CDoc::NotifyActiveSlideChanged,
+ &CDoc::NotifyActiveSlideChanged, theActiveSlide, NULL, "");
+ theCmd->SetUndoable(false);
+ theCmd->SetModifiedFlag(false);
+ m_TransMgr->GetDoc()->GetCore()->ExecuteCommand(theCmd, false);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool CGroupTimelineItemBinding::IsImported() const
+{
+
+ UICDM::CUICDMInstanceHandle theInstance = GetInstance();
+ UICDM::IPropertySystem *thePropertySystem =
+ m_TransMgr->GetDoc()->GetStudioSystem()->GetPropertySystem();
+ UICDM::SValue theValue;
+ if (thePropertySystem->GetInstancePropertyValue(theInstance, m_TransMgr->GetDoc()
+ ->GetStudioSystem()
+ ->GetClientDataModelBridge()
+ ->GetSourcePathProperty(),
+ theValue)) {
+ UICDM::TDataStrPtr theSrcPath(UICDM::get<UICDM::TDataStrPtr>(theValue));
+ Q3DStudio::CFilePath theFilePath(theSrcPath->GetData());
+ if (theFilePath.GetExtension() == CDialogs::GetWideImportFileExtension())
+ return true;
+ }
+ // If it is, check to be sure that
+ // we can get to the import file.
+ // If we can, then we are imported.
+ return false;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.h
new file mode 100644
index 00000000..a9462c1c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_GROUP_TIMELINEITEM_BINDING_H
+#define INCLUDED_GROUP_TIMELINEITEM_BINDING_H 1
+
+#pragma once
+
+#include "UICDMTimelineItemBinding.h"
+
+//==============================================================================
+// Classes
+//==============================================================================
+class ITimelineItem;
+class CTimelineTranslationManager;
+class CBaseStateRow;
+
+//=============================================================================
+/**
+ * Binding to a UICDM object of Group type
+ */
+class CGroupTimelineItemBinding : public CUICDMTimelineItemBinding
+{
+public:
+ CGroupTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ UICDM::CUICDMInstanceHandle inDataHandle);
+ ~CGroupTimelineItemBinding() {}
+
+ // CUICDMTimelineItemBinding
+ bool OpenAssociatedEditor() override;
+ bool IsImported() const override;
+};
+
+#endif // INCLUDED_GROUP_TIMELINEITEM_BINDING_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/IKeyframeSelector.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/IKeyframeSelector.h
new file mode 100644
index 00000000..db8b551f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/IKeyframeSelector.h
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_IKEYFRAME_SELECTOR_H
+#define INCLUDED_IKEYFRAME_SELECTOR_H 1
+
+#pragma once
+
+//=============================================================================
+/**
+ * Interface that performs keyframe selection.
+ */
+//=============================================================================
+class IKeyframeSelector
+{
+public:
+ virtual ~IKeyframeSelector() {}
+
+ //=============================================================================
+ /**
+ * @param inTime -1 to selected (or deselect) ALL keyframes, otherwise only by time.
+ */
+ virtual void SelectKeyframes(bool inSelected, long inTime = -1) = 0;
+};
+
+#endif // INCLUDED_IKEYFRAME_SELECTOR_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItem.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItem.h
new file mode 100644
index 00000000..e5af8671
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItem.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_ITIMELINE_ITEM_H
+#define INCLUDED_ITIMELINE_ITEM_H 1
+
+#pragma once
+
+#include "INamable.h"
+#include "StudioObjectTypes.h"
+
+class ITimelineTimebar;
+
+//=============================================================================
+/**
+ * Abstraction of a data model item in the Scene. This might end up deriving from a more generic
+ * interface, so that common
+ * functions can be generalized for items in the different palettes.
+ */
+//=============================================================================
+class ITimelineItem : public INamable
+{
+public:
+ virtual ~ITimelineItem() {}
+
+ virtual EStudioObjectType GetObjectType() const = 0;
+ virtual bool IsMaster() const = 0;
+
+ virtual bool IsShy() const = 0;
+ virtual void SetShy(bool) = 0;
+ virtual bool IsLocked() const = 0;
+ virtual void SetLocked(bool) = 0;
+ virtual bool IsVisible() const = 0;
+ virtual void SetVisible(bool) = 0;
+ virtual bool IsExpanded() const = 0;
+ virtual void SetExpanded(bool) = 0;
+ virtual bool IsImported() const { return false; }
+
+ // Actions
+ virtual bool HasAction(bool inMaster) = 0;
+ virtual bool ChildrenHasAction(bool inMaster) = 0;
+ virtual bool ComponentHasAction(bool inMaster) = 0;
+
+ virtual ITimelineTimebar *GetTimebar() = 0;
+};
+
+#endif // INCLUDED_ITIMELINE_ITEM_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h
new file mode 100644
index 00000000..d251f530
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef INCLUDED_ITIMELINE_ITEM_BINDINGS_H
+#define INCLUDED_ITIMELINE_ITEM_BINDINGS_H 1
+
+#pragma once
+
+#include "ITimelineItem.h"
+#include "ITimelineItemProperty.h"
+#include "IKeyframeSelector.h"
+#include "SIterator.h"
+
+class CBaseStateRow;
+class CControlWindowListener;
+class ITimelineKeyframesManager;
+
+// Data model specific ??
+class CDropTarget;
+
+class ITimelineItemKeyframesHolder
+{
+public:
+ virtual ~ITimelineItemKeyframesHolder() {}
+
+ virtual void InsertKeyframe() = 0;
+ virtual void DeleteAllChannelKeyframes() = 0;
+ virtual long GetKeyframeCount() const = 0;
+ virtual IKeyframe *GetKeyframeByTime(long inTime) const = 0;
+ virtual IKeyframe *GetKeyframeByIndex(long inIndex) const = 0;
+ virtual long OffsetSelectedKeyframes(long inOffset) = 0;
+ virtual void CommitChangedKeyframes() = 0;
+ virtual void OnEditKeyframeTime(long inCurrentTime, long inObjectAssociation) = 0;
+};
+
+//=============================================================================
+/**
+ * Interface to encapsulate data model specific functions, that Timeline UI objects can talk to.
+ */
+//=============================================================================
+class ITimelineItemBinding : public ITimelineItemKeyframesHolder, public IKeyframeSelector
+{
+public:
+ // List of possible transactions that requires querying the data model if they are valid
+ enum EUserTransaction {
+ EUserTransaction_None,
+ EUserTransaction_Rename,
+ EUserTransaction_Duplicate,
+ EUserTransaction_Cut,
+ EUserTransaction_Copy,
+ EUserTransaction_Paste,
+ EUserTransaction_Delete,
+ EUserTransaction_MakeComponent,
+ EUserTransaction_EditComponent,
+ };
+
+public:
+ virtual ~ITimelineItemBinding() {}
+
+ virtual ITimelineItem *GetTimelineItem() = 0;
+ virtual CBaseStateRow *GetRow() = 0;
+
+ // Events
+ virtual void SetSelected(bool multiSelect) = 0;
+ virtual void OnCollapsed() = 0;
+ virtual void ClearKeySelection() = 0;
+ virtual bool OpenAssociatedEditor() = 0;
+ virtual void DoStartDrag(CControlWindowListener *inWndListener) = 0;
+ virtual void SetDropTarget(CDropTarget *inTarget) = 0;
+
+ // Hierarchy
+ virtual long GetChildrenCount() = 0;
+ virtual ITimelineItemBinding *GetChild(long inIndex) = 0;
+ virtual ITimelineItemBinding *GetParent() = 0;
+ virtual void SetParent(ITimelineItemBinding *parent) = 0;
+ // Properties
+ virtual long GetPropertyCount() = 0;
+ virtual ITimelineItemProperty *GetProperty(long inIndex) = 0;
+
+ // Eye/Lock toggles
+ virtual bool ShowToggleControls() const = 0;
+ virtual bool IsLockedEnabled() const = 0;
+ virtual bool IsVisibleEnabled() const = 0;
+
+ // Init/Cleanup
+ virtual void Bind(CBaseStateRow *inRow) = 0;
+ virtual void Release() = 0;
+
+ // ContextMenu
+ virtual bool IsValidTransaction(EUserTransaction inTransaction) = 0;
+ virtual void PerformTransaction(EUserTransaction inTransaction) = 0;
+ virtual Q3DStudio::CString GetObjectPath() = 0;
+
+ virtual bool IsExternalizeable() { return false; }
+ virtual void Externalize() {}
+ virtual bool IsInternalizeable() { return false; }
+ virtual void Internalize() {}
+
+ // Selected keyframes
+ virtual ITimelineKeyframesManager *GetKeyframesManager() const = 0;
+
+ // Properties
+ virtual void RemoveProperty(ITimelineItemProperty *inProperty) = 0;
+ virtual void LoadProperties() = 0;
+};
+
+//=============================================================================
+/**
+ * Helper iterator class that iterates over a ITimeline's children in a ordered (priority) list.
+ */
+//=============================================================================
+class CTimelineItemOrderedIterator : public CSIterator<ITimelineItemBinding *>
+{
+public:
+ CTimelineItemOrderedIterator(ITimelineItemBinding *inRootTimelineItem)
+ {
+ m_RootTimelineItem = inRootTimelineItem;
+ Reset();
+ }
+ bool IsDone() override { return (m_Index >= m_Total); }
+ void operator++() override { m_Index++; }
+ void operator+=(const long inNumToInc) override { m_Index += inNumToInc; }
+ ITimelineItemBinding *GetCurrent() override { return m_RootTimelineItem->GetChild(m_Index); }
+ virtual void Reset()
+ {
+ m_Index = 0;
+ m_Total = m_RootTimelineItem->GetChildrenCount();
+ }
+
+protected:
+ ITimelineItemBinding *m_RootTimelineItem;
+ long m_Index;
+ long m_Total;
+};
+
+//=============================================================================
+/**
+ * Helper iterator class that iterates over a ITimeline's properties
+ */
+//=============================================================================
+class CTimelineItemPropertyIterator : public CSIterator<ITimelineItemProperty *>
+{
+public:
+ CTimelineItemPropertyIterator(ITimelineItemBinding *inTimelineItem)
+ {
+ m_TimelineItem = inTimelineItem;
+ Reset();
+ }
+ bool IsDone() override { return (m_Index >= m_Total); }
+ void operator++() override { m_Index++; }
+ void operator+=(const long inNumToInc) override { m_Index += inNumToInc; }
+ ITimelineItemProperty *GetCurrent() override { return m_TimelineItem->GetProperty(m_Index); }
+ virtual void Reset()
+ {
+ m_Index = 0;
+ m_Total = m_TimelineItem->GetPropertyCount();
+ }
+
+protected:
+ ITimelineItemBinding *m_TimelineItem;
+ long m_Index;
+ long m_Total;
+};
+
+#endif // INCLUDED_ITIMELINE_ITEM_BINDINGS_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemProperty.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemProperty.h
new file mode 100644
index 00000000..c241ebfa
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemProperty.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_ITIMELINE_ITEM_PROPERTY_H
+#define INCLUDED_ITIMELINE_ITEM_PROPERTY_H 1
+
+#pragma once
+
+#include "IKeyframeSelector.h"
+#include "UICDMMetaData.h"
+#include "UICString.h"
+
+class CPropertyRow;
+class IKeyframe;
+class ITimelineKeyframesManager;
+
+//=============================================================================
+/**
+ * Abstraction of a data model item's property that is displayed in the Timeline.
+ */
+//=============================================================================
+class ITimelineItemProperty : public IKeyframeSelector
+{
+public:
+ virtual ~ITimelineItemProperty() {}
+
+ virtual Q3DStudio::CString GetName() const = 0;
+ virtual bool IsMaster() const = 0;
+ virtual UICDM::TDataTypePair GetType() const = 0;
+ virtual float GetMaximumValue() const = 0;
+ virtual float GetMinimumValue() const = 0;
+
+ virtual void SetSelected() = 0;
+ virtual void ClearKeySelection() = 0;
+ virtual void DeleteAllKeys() = 0;
+
+ virtual void Bind(CPropertyRow *inRow) = 0;
+ virtual void Release() = 0;
+ virtual CPropertyRow *GetRow() = 0;
+
+ // Keyframes
+ virtual ITimelineKeyframesManager *GetKeyframesManager() const = 0;
+ virtual IKeyframe *GetKeyframeByTime(long inTime) const = 0;
+ virtual IKeyframe *GetKeyframeByIndex(long inIndex) const = 0;
+ virtual long GetKeyframeCount() const = 0;
+ virtual long GetChannelCount() const = 0;
+ virtual float GetChannelValueAtTime(long inChannelIndex, long inTime) = 0;
+ virtual void SetChannelValueAtTime(long inChannelIndex, long inTime, float inValue) = 0;
+ virtual long OffsetSelectedKeyframes(long inOffset) = 0;
+ virtual void CommitChangedKeyframes() = 0;
+ virtual void OnEditKeyframeTime(long inCurrentTime, long inObjectAssociation) = 0;
+ virtual bool IsDynamicAnimation() = 0;
+};
+
+#endif // INCLUDED_ITIMELINE_ITEM_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h
new file mode 100644
index 00000000..e1a6914f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_ITIMELINE_KEYFRAMES_MANAGER_H
+#define INCLUDED_ITIMELINE_KEYFRAMES_MANAGER_H 1
+
+#pragma once
+
+#include "IKeyframesManager.h"
+
+//=============================================================================
+/**
+ * Interface to manage keyframes related actions in the Timeline
+ */
+//=============================================================================
+class ITimelineKeyframesManager : public IKeyframesManager
+{
+public:
+ virtual ~ITimelineKeyframesManager() {}
+
+ virtual void SetKeyframeTime(long inTime) = 0;
+ virtual void SetKeyframesDynamic(bool inDynamic) = 0;
+ virtual long OffsetSelectedKeyframes(long inOffset) = 0;
+ virtual bool CanMakeSelectedKeyframesDynamic() = 0;
+ virtual void CommitChangedKeyframes() = 0;
+ virtual void RollbackChangedKeyframes() = 0;
+};
+
+#endif // INCLUDED_IKEYFRAMES_MANAGER_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineTimebar.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineTimebar.h
new file mode 100644
index 00000000..dbeefb85
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineTimebar.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef INCLUDED_ITIMELINE_TIMEBAR_H
+#define INCLUDED_ITIMELINE_TIMEBAR_H 1
+
+#pragma once
+
+#include "UICString.h"
+
+class ITimeChangeCallback;
+
+class CColor;
+
+//=============================================================================
+/**
+ * Interface for a Timebar
+ */
+//=============================================================================
+class ITimelineTimebar
+{
+public:
+ virtual ~ITimelineTimebar() {}
+
+ virtual long GetStartTime() const = 0;
+ virtual long GetEndTime() const = 0;
+ virtual long GetDuration() const = 0;
+ virtual bool ShowHandleBars() const = 0;
+ //=============================================================================
+ /**
+ * TODO: consider refactor. drag&drop specfics should not be in the Data Model.
+ */
+ virtual void OnBeginDrag() = 0;
+ //
+ virtual void OffsetTime(long inDiff) = 0;
+ // Change the start time or the end time of the timebar. inTime: time to change to, inSetStart:
+ // true to set start time, false to set end time.
+ virtual void ChangeTime(long inTime, bool inSetStart) = 0;
+ virtual void CommitTimeChange() = 0;
+ virtual void RollbackTimeChange() = 0;
+ //
+ virtual CColor GetTimebarColor() = 0;
+ virtual void SetTimebarColor(const CColor &inColor) = 0;
+ virtual Q3DStudio::CString GetTimebarComment() = 0;
+ virtual void SetTimebarComment(const Q3DStudio::CString &inComment) = 0;
+ virtual void SetTimebarTime(ITimeChangeCallback *inCallback = nullptr) = 0;
+};
+
+#endif // INCLUDED_ITIMELINE_TIMEBAR_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.cpp
new file mode 100644
index 00000000..bf41f00d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "ImageTimelineItemBinding.h"
+#include "TimelineTranslationManager.h"
+#include "UICDMHandles.h"
+#include "BaseStateRow.h"
+#include "Doc.h"
+#include "IObjectReferenceHelper.h"
+#include "EmptyTimelineTimebar.h"
+
+using namespace UICDM;
+
+CImageTimelineItemBinding::CImageTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ CUICDMInstanceHandle inDataHandle)
+ : CUICDMTimelineItemBinding(inMgr, inDataHandle)
+{
+}
+
+CImageTimelineItemBinding::~CImageTimelineItemBinding()
+{
+}
+
+ITimelineTimebar *CImageTimelineItemBinding::GetTimebar()
+{ // No timebars on images
+ return new CEmptyTimelineTimebar();
+}
+
+Q3DStudio::CString CImageTimelineItemBinding::GetName() const
+{
+ return m_Name;
+}
+
+void CImageTimelineItemBinding::SetName(const Q3DStudio::CString &inName)
+{
+ m_Name = inName;
+}
+
+EStudioObjectType CImageTimelineItemBinding::GetObjectType() const
+{
+ return OBJTYPE_IMAGE;
+}
+
+bool CImageTimelineItemBinding::ShowToggleControls() const
+{
+ // no toggle controls, by design
+ return false;
+}
+
+void CImageTimelineItemBinding::Bind(CBaseStateRow *inRow)
+{
+ CUICDMTimelineItemBinding::Bind(inRow);
+ GetRow()->SetNameReadOnly(true);
+}
+
+//=============================================================================
+/**
+ * Open the associated item as though it was double-clicked in explorer
+ */
+bool CImageTimelineItemBinding::OpenAssociatedEditor()
+{
+ return OpenSourcePathFile();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.h
new file mode 100644
index 00000000..2c27dd2d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_IMAGE_TIMELINEITEM_BINDING_H
+#define INCLUDED_IMAGE_TIMELINEITEM_BINDING_H 1
+
+#pragma once
+
+#include "UICDMTimelineItemBinding.h"
+
+//==============================================================================
+// Classes
+//==============================================================================
+class CTimelineTranslationManager;
+class CBaseStateRow;
+class ITimelineTimebar;
+
+//=============================================================================
+/**
+ * Binding to a UICDM object of Image type
+ */
+class CImageTimelineItemBinding : public CUICDMTimelineItemBinding
+{
+public:
+ CImageTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ UICDM::CUICDMInstanceHandle inDataHandle);
+ virtual ~CImageTimelineItemBinding();
+
+ // CUICDMTimelineItemBinding
+ ITimelineTimebar *GetTimebar() override;
+ Q3DStudio::CString GetName() const override;
+ void SetName(const Q3DStudio::CString &inName) override;
+ EStudioObjectType GetObjectType() const override;
+ bool ShowToggleControls() const override;
+ void Bind(CBaseStateRow *inRow) override;
+ bool OpenAssociatedEditor() override;
+
+ void SetPropertyHandle(UICDM::CUICDMPropertyHandle inProperty)
+ {
+ m_PropertyHandle = inProperty;
+ }
+ UICDM::CUICDMPropertyHandle GetPropertyHandle() const { return m_PropertyHandle; }
+
+protected:
+ Q3DStudio::CString m_Name;
+ UICDM::CUICDMPropertyHandle m_PropertyHandle;
+};
+
+#endif // INCLUDED_IMAGE_TIMELINEITEM_BINDING_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.cpp
new file mode 100644
index 00000000..a4adefbc
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.cpp
@@ -0,0 +1,506 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+#include "KeyframesManager.h"
+#include "IDoc.h"
+#include "TimeEditDlg.h"
+#include "TimelineTranslationManager.h"
+#include "UICDMTimelineKeyframe.h"
+#include "UICDMTimelineItemBinding.h"
+#include "CmdDataModelRemoveKeyframe.h"
+#include "CmdDataModelInsertKeyframe.h"
+#include "CmdDataModelChangeKeyframe.h"
+#include "UICDMAnimation.h"
+#include "ClientDataModelBridge.h"
+#include "PasteKeyframesCommandHelper.h"
+#include "IDocumentEditor.h"
+#include "IKeyframe.h"
+#include "Dispatch.h"
+#include "StudioPreferences.h"
+
+#include "StudioApp.h" //for CommitCurrentCommand
+#include "Core.h"
+#include "Dialogs.h"
+
+using namespace UICDM;
+
+bool SortKeyframeInstancePairByTime(const CKeyframesManager::SKeyframeInstancePair &inLHS,
+ const CKeyframesManager::SKeyframeInstancePair &inRHS)
+{
+ return inLHS.m_Keyframe->GetTime() < inRHS.m_Keyframe->GetTime();
+}
+
+//==============================================================================
+// Keyframe specific.
+// UICDM selection is handled by CTimelineTranslationManager.
+//==============================================================================
+CKeyframesManager::CKeyframesManager(CTimelineTranslationManager *inTransMgr)
+ : m_TransMgr(inTransMgr)
+ , m_OffsetKeyframeCommandHelper(*(g_StudioApp.GetCore()->GetDoc()))
+ , m_PasteKeyframeCommandHelper(nullptr)
+{
+ g_StudioApp.GetCore()->GetDoc()->SetKeyframesManager(this);
+}
+
+CKeyframesManager::~CKeyframesManager()
+{
+ delete m_PasteKeyframeCommandHelper;
+}
+
+bool CKeyframesManager::HasSelectedKeyframes(bool inOnlyDynamic /*= false */)
+{
+ // specifically only to know if there are any selected keyframes that are dynamic
+ if (inOnlyDynamic) {
+ for (size_t theIndex = 0; theIndex < m_SelectedKeyframes.size(); ++theIndex)
+ if (m_SelectedKeyframes[theIndex].m_Keyframe->IsDynamic())
+ return true;
+
+ return false;
+ }
+
+ bool theRetVal = !m_SelectedKeyframes.empty();
+
+ return theRetVal;
+}
+
+bool CKeyframesManager::CanPerformKeyframeCopy()
+{
+ bool theCanCopyNewData = false;
+ // Legacy system actually prevents copy/pasting between different instances, so let's preserve
+ // that
+ if (!m_SelectedKeyframes.empty()) {
+ theCanCopyNewData = true;
+ if (m_SelectedKeyframes.size() > 1) {
+ CUICDMTimelineItemBinding *theInstance = m_SelectedKeyframes[0].m_Instance;
+ TSelectedKeyframeList::iterator theIter = m_SelectedKeyframes.begin();
+ ++theIter;
+ for (; theIter != m_SelectedKeyframes.end() && theCanCopyNewData; ++theIter) {
+ if (theIter->m_Instance != theInstance) // fail!
+ theCanCopyNewData = false;
+ }
+ }
+ }
+ return theCanCopyNewData;
+}
+
+bool CKeyframesManager::CanPerformKeyframePaste()
+{
+ if (m_PasteKeyframeCommandHelper && m_PasteKeyframeCommandHelper->HasCopiedKeyframes()) {
+ UICDM::CUICDMInstanceHandle theSelectedInstance =
+ g_StudioApp.GetCore()->GetDoc()->GetSelectedInstance();
+ if (theSelectedInstance.Valid()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void CKeyframesManager::CopyKeyframes()
+{
+ CopySelectedKeyframes();
+}
+
+// legacy stuff that we have to support for animation tracks in the old data model to work
+inline void PostExecuteCommand(IDoc *inDoc)
+{
+ CDoc *theDoc = dynamic_cast<CDoc *>(inDoc);
+ theDoc->GetCore()->CommitCurrentCommand();
+ // fire render event.
+ // theDoc->UpdateClientScene( true );
+}
+
+//@param inPerformCopy true if that is a copy/cut command. false if this is a delete.
+// Note: Keyframes are never explicitly copied to the clipboard (only as part of a asset copy),
+// hence that means that the keyframes (only) are never copied across different instances of studio.
+bool CKeyframesManager::RemoveKeyframes(bool inPerformCopy)
+{
+ bool theRetVal = HasSelectedKeyframes();
+
+ CDoc *theDoc = g_StudioApp.GetCore()->GetDoc();
+
+ if (inPerformCopy) // copy prior to removing the keyframes
+ CopySelectedKeyframes();
+
+ CCmdDataModelRemoveKeyframe *theCmd = nullptr;
+ if (!m_SelectedKeyframes.empty()) {
+ TSelectedKeyframeList::iterator theKeyIter = m_SelectedKeyframes.begin();
+ for (; theKeyIter != m_SelectedKeyframes.end(); ++theKeyIter) {
+ CUICDMTimelineKeyframe::TKeyframeHandleList theKeyframeHandles;
+ theKeyIter->m_Keyframe->GetKeyframeHandles(theKeyframeHandles);
+ ASSERT(!theKeyframeHandles.empty());
+ CUICDMTimelineKeyframe::TKeyframeHandleList::iterator theIter =
+ theKeyframeHandles.begin();
+ if (!theCmd) {
+ theCmd = new CCmdDataModelRemoveKeyframe(theDoc, *theIter);
+ ++theIter;
+ }
+ for (; theIter != theKeyframeHandles.end(); ++theIter)
+ theCmd->AddKeyframeHandle(*theIter);
+ }
+ }
+
+ if (theCmd) {
+ g_StudioApp.GetCore()->ExecuteCommand(theCmd);
+ PostExecuteCommand(theDoc);
+ }
+ return theRetVal;
+}
+
+// note: we can't paste data from old data model system to the new one, and vice versa. so either
+// the old Or the new system succeeds in pasting, never both.
+void CKeyframesManager::PasteKeyframes()
+{
+ CDoc *theDoc = g_StudioApp.GetCore()->GetDoc();
+
+ if (m_PasteKeyframeCommandHelper && m_PasteKeyframeCommandHelper->HasCopiedKeyframes()) {
+ UICDM::CUICDMInstanceHandle theSelectedInstance = theDoc->GetSelectedInstance();
+ if (theSelectedInstance.Valid()) {
+ long theCurrentViewTimeInMilliseconds = theDoc->GetCurrentViewTime();
+ CCmdDataModelInsertKeyframe *theInsertKeyframesCommand =
+ m_PasteKeyframeCommandHelper->GetCommand(theDoc, theCurrentViewTimeInMilliseconds,
+ theSelectedInstance);
+ if (theInsertKeyframesCommand)
+ g_StudioApp.GetCore()->ExecuteCommand(theInsertKeyframesCommand);
+ }
+ }
+}
+
+//=============================================================================
+/**
+ * Sets interpolation values of all selected keyframes to the values specified
+ * by the user. Pops up a dialog prompting the user to choose new ease in and
+ * ease out values. Values in the dialog are initialized to the left-most
+ * selected keyframe's interpolation values.
+ */
+void CKeyframesManager::SetKeyframeInterpolation()
+{
+ if (!HasSelectedKeyframes())
+ return;
+
+ float theEaseIn = 0;
+ float theEaseOut = 0;
+ if (CStudioPreferences::GetInterpolation())
+ theEaseIn = theEaseOut = 100;
+
+ IAnimationCore *theAnimationCore = m_TransMgr->GetStudioSystem()->GetAnimationCore();
+
+ if (!m_SelectedKeyframes.empty()) // this is a sorted list, so we only need to grab tge ease
+ // in/out values from the first item in this list.
+ {
+ CUICDMTimelineKeyframe *theTimelineKeyframe = m_SelectedKeyframes.front().m_Keyframe;
+ CUICDMTimelineKeyframe::TKeyframeHandleList theKeyframeHandles;
+ theTimelineKeyframe->GetKeyframeHandles(theKeyframeHandles);
+ TKeyframe theKeyframeData = theAnimationCore->GetKeyframeData(theKeyframeHandles[0]);
+ GetEaseInOutValues(theKeyframeData, theEaseIn, theEaseOut);
+ }
+
+ if (g_StudioApp.GetDialogs()->PromptForKeyframeInterpolation(theEaseIn, theEaseOut)) {
+ CDoc *theDoc = g_StudioApp.GetCore()->GetDoc();
+ Q3DStudio::ScopedDocumentEditor editor(*theDoc, L"Set Keyframe Interpolation", __FILE__,
+ __LINE__);
+ TSelectedKeyframeList::iterator theKeyIter = m_SelectedKeyframes.begin();
+ for (; theKeyIter != m_SelectedKeyframes.end(); ++theKeyIter) {
+ CUICDMTimelineKeyframe *theTimelineKeyframe = theKeyIter->m_Keyframe;
+ CUICDMTimelineKeyframe::TKeyframeHandleList theKeyframeHandles;
+ theTimelineKeyframe->GetKeyframeHandles(theKeyframeHandles);
+ for (size_t i = 0; i < theKeyframeHandles.size(); ++i) {
+ TKeyframe theKeyframeData =
+ theAnimationCore->GetKeyframeData(theKeyframeHandles[i]);
+ SetEaseInOutValues(theKeyframeData, theEaseIn, theEaseOut);
+ theAnimationCore->SetKeyframeData(theKeyframeHandles[i], theKeyframeData);
+ }
+ }
+ }
+}
+
+bool CKeyframesManager::HasDynamicKeyframes()
+{
+ CUICDMTimelineItemBinding *theBinding = m_TransMgr->GetSelectedBinding();
+ if (theBinding) {
+ return theBinding->HasDynamicKeyframes(-1);
+ }
+ return false;
+}
+
+void CKeyframesManager::SelectAllKeyframes()
+{
+ ITimelineItemBinding *theBinding = m_TransMgr->GetSelectedBinding();
+ if (theBinding)
+ theBinding->SelectKeyframes(true);
+}
+
+void CKeyframesManager::DeselectAllKeyframes()
+{
+ m_TransMgr->ClearBindingsKeyframeSelection();
+ m_SelectedKeyframes.clear();
+}
+
+//==============================================================================
+/**
+ * Sets keyframes on all the changed properties of the selected object.
+ * Also known as autoset keyframes, but it only applies to one object, and is
+ * the result of an F6 key press. Tells the TimelineCtrl to autoset keyframes.
+ */
+void CKeyframesManager::SetChangedKeyframes()
+{
+
+ CDoc *theDoc = g_StudioApp.GetCore()->GetDoc();
+ UICDM::CUICDMInstanceHandle theSelectedInstance = theDoc->GetSelectedInstance();
+ if (theSelectedInstance.Valid()) {
+ using namespace Q3DStudio;
+ Q3DStudio::ScopedDocumentEditor editor(*theDoc, L"Set Changed Keyframes", __FILE__,
+ __LINE__);
+ CStudioSystem *theStudioSystem = theDoc->GetStudioSystem();
+ // Get all animated properties.
+ TPropertyHandleList theProperties;
+ theStudioSystem->GetPropertySystem()->GetAggregateInstanceProperties(theSelectedInstance,
+ theProperties);
+ for (size_t thePropertyIndex = 0; thePropertyIndex < theProperties.size();
+ ++thePropertyIndex) {
+ if (theStudioSystem->GetAnimationSystem()->IsPropertyAnimated(
+ theSelectedInstance, theProperties[thePropertyIndex]))
+ editor->KeyframeProperty(theSelectedInstance, theProperties[thePropertyIndex],
+ true);
+ }
+ }
+}
+
+void CKeyframesManager::SetKeyframeTime(long inTime)
+{
+ CTimeEditDlg theTimeEditDlg;
+ theTimeEditDlg.SetKeyframesManager(this);
+ theTimeEditDlg.ShowDialog(inTime, 0, g_StudioApp.GetCore()->GetDoc(), ASSETKEYFRAME);
+}
+
+void CKeyframesManager::SetKeyframeDynamic(CUICDMTimelineKeyframe *inKeyframe, bool inDynamic)
+{
+ CDoc *theDoc = g_StudioApp.GetCore()->GetDoc();
+ UICDM::TKeyframeHandleList theKeyframeHandle;
+ CCmdDataModelChangeDynamicKeyframe *theCmd = nullptr;
+
+ if (inKeyframe != nullptr)
+ inKeyframe->GetKeyframeHandles(theKeyframeHandle);
+
+ UICDM::IAnimationCore *theAnimationCore = theDoc->GetStudioSystem()->GetAnimationCore();
+ for (size_t theKeyframe = 0; theKeyframe < theKeyframeHandle.size(); ++theKeyframe) {
+ UICDM::CUICDMAnimationHandle theAnimation(
+ theAnimationCore->GetAnimationForKeyframe(theKeyframeHandle.at(theKeyframe)));
+ if (!theCmd)
+ theCmd = new CCmdDataModelChangeDynamicKeyframe(theDoc, theAnimation, inDynamic);
+ else
+ theCmd->AddHandle(theAnimation);
+ }
+
+ if (theCmd)
+ g_StudioApp.GetCore()->ExecuteCommand(theCmd);
+}
+
+void CKeyframesManager::SetKeyframesDynamic(bool inDynamic)
+{
+
+ CUICDMTimelineKeyframe *theKeyframe;
+
+ if (m_SelectedKeyframes.size() == 0) {
+ CUICDMTimelineItemBinding *theBinding = m_TransMgr->GetSelectedBinding();
+ IKeyframe *key = theBinding->GetKeyframeByIndex(0);
+ theKeyframe = dynamic_cast<CUICDMTimelineKeyframe *>(key);
+ SetKeyframeDynamic(theKeyframe, inDynamic);
+ } else {
+ for (int i = 0; i < (int)m_SelectedKeyframes.size(); ++i) {
+ theKeyframe = m_SelectedKeyframes[i].m_Keyframe;
+ SetKeyframeDynamic(theKeyframe, inDynamic);
+ }
+ }
+}
+
+long CKeyframesManager::OffsetSelectedKeyframes(long inOffset)
+{
+ m_InstanceSet.clear();
+ m_InstanceList.clear();
+ std::set<CUICDMTimelineItemBinding *> &theInstances(m_InstanceSet);
+
+ TSelectedKeyframeList::iterator theKeyIter = m_SelectedKeyframes.begin();
+ for (; theKeyIter != m_SelectedKeyframes.end(); ++theKeyIter) {
+ // since this list is sorted by time and we are iterating from the first in the list
+ long theKeyframeTime = theKeyIter->m_Keyframe->GetTime();
+ if (inOffset < 0 && theKeyframeTime + inOffset < 0)
+ inOffset = -theKeyframeTime;
+
+ theKeyIter->m_Keyframe->UpdateKeyframesTime(&m_OffsetKeyframeCommandHelper,
+ theKeyframeTime + inOffset);
+
+ // this contains unique instancs, i.e. mulitple keyframe can map to the same instances
+ if (theInstances.insert(theKeyIter->m_Instance).second)
+ m_InstanceList.push_back(theKeyIter->m_Instance->GetInstance());
+ }
+
+ // UI update, explicitly because this doesn't generate any events till action is committed
+ std::set<CUICDMTimelineItemBinding *>::iterator theInstanceIter = theInstances.begin();
+ for (; theInstanceIter != theInstances.end(); ++theInstanceIter)
+ (*theInstanceIter)->UIRefreshPropertyKeyframe(inOffset);
+
+ if (m_InstanceList.size())
+ m_TransMgr->GetDoc()->GetCore()->GetDispatch()->FireImmediateRefreshInstance(
+ &m_InstanceList[0], (long)m_InstanceList.size());
+
+ // by contract, this functions returns the "legal" offset, ie time cannot be offset to negative.
+ return inOffset;
+}
+
+void CKeyframesManager::CommitChangedKeyframes()
+{
+ m_OffsetKeyframeCommandHelper.Finalize();
+}
+
+void CKeyframesManager::RollbackChangedKeyframes()
+{
+ m_OffsetKeyframeCommandHelper.Rollback();
+}
+
+bool CKeyframesManager::CanMakeSelectedKeyframesDynamic()
+{
+ using namespace UICDM;
+ TKeyframeHandleList theKeyframes;
+ TKeyframeHandleList allTheKeyframes;
+ IAnimationCore &theAnimationCore(
+ *g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetAnimationCore());
+ // Ensure that all keyframes selected are the first keyframes from the animation track.
+ for (size_t idx = 0, end = m_SelectedKeyframes.size(); idx < end; ++idx) {
+ theKeyframes.clear();
+ m_SelectedKeyframes.at(idx).m_Keyframe->GetKeyframeHandles(theKeyframes);
+ for (size_t specificKeyframeIdx = 0, specificKeyframeEnd = theKeyframes.size();
+ specificKeyframeIdx < specificKeyframeEnd; ++specificKeyframeIdx) {
+ CUICDMKeyframeHandle theKeyframe = theKeyframes[specificKeyframeIdx];
+ CUICDMAnimationHandle theAnimation =
+ theAnimationCore.GetAnimationForKeyframe(theKeyframe);
+ allTheKeyframes.clear();
+ theAnimationCore.GetKeyframes(theAnimation, allTheKeyframes);
+ if (allTheKeyframes[0] != theKeyframe)
+ return false;
+ }
+ }
+ return true;
+}
+
+// keeps track of selected keyframes so that we don't have to iterate through the entire hierarchy
+// to find them
+void CKeyframesManager::SetKeyframeSelected(CUICDMTimelineKeyframe *inKeyframe, bool inSelected,
+ CUICDMTimelineItemBinding *inOwningInstance /*= nullptr */)
+{
+ TSelectedKeyframeList::iterator theKeyIter = m_SelectedKeyframes.begin();
+ for (; theKeyIter != m_SelectedKeyframes.end(); ++theKeyIter) {
+ if (theKeyIter->m_Keyframe == inKeyframe)
+ break;
+ }
+ if (inSelected) {
+ ASSERT(inOwningInstance);
+ if (theKeyIter == m_SelectedKeyframes.end()) { // only this is not already selected
+ m_SelectedKeyframes.push_back(SKeyframeInstancePair(inKeyframe, inOwningInstance));
+ std::sort(m_SelectedKeyframes.begin(), m_SelectedKeyframes.end(),
+ SortKeyframeInstancePairByTime);
+ }
+ } else if (theKeyIter != m_SelectedKeyframes.end()) {
+ m_SelectedKeyframes.erase(theKeyIter);
+ }
+}
+
+UICDM::SGetOrSetKeyframeInfo SetupKeyframeInfo(UICDM::CUICDMKeyframeHandle inKeyframe,
+ UICDM::IAnimationCore &inCore)
+{
+ TKeyframe theKeyframeData = inCore.GetKeyframeData(inKeyframe);
+ SEaseInEaseOutKeyframe theKeyframe = UICDM::get<SEaseInEaseOutKeyframe>(theKeyframeData);
+ // Is this the first keyframe?
+ bool isDynamic = false;
+ if (inCore.IsFirstKeyframe(inKeyframe))
+ isDynamic = inCore.GetAnimationInfo(inCore.GetAnimationForKeyframe(inKeyframe))
+ .m_DynamicFirstKeyframe;
+
+ return SGetOrSetKeyframeInfo(theKeyframe.m_KeyframeValue, theKeyframe.m_EaseIn,
+ theKeyframe.m_EaseOut, isDynamic);
+}
+
+// only deal with this manager's selected keyframes
+void CKeyframesManager::CopySelectedKeyframes()
+{
+ if (!m_SelectedKeyframes.empty()) {
+ if (m_PasteKeyframeCommandHelper)
+ m_PasteKeyframeCommandHelper->Clear(); // clear out previously copied data
+ else
+ m_PasteKeyframeCommandHelper = new CPasteKeyframeCommandHelper();
+
+ // note: m_SelectedKeyframes is already sorted by time
+ float theEarliestKeyframeTimeInSecs =
+ CUICDMTimelineKeyframe::GetTimeInSecs(m_SelectedKeyframes[0].m_Keyframe->GetTime());
+
+ IAnimationCore *theAnimationCore = m_TransMgr->GetStudioSystem()->GetAnimationCore();
+ TSelectedKeyframeList::iterator theIter = m_SelectedKeyframes.begin();
+ for (; theIter != m_SelectedKeyframes.end(); ++theIter) {
+ CUICDMTimelineKeyframe *theKeyframe = (*theIter).m_Keyframe;
+ CUICDMTimelineKeyframe::TKeyframeHandleList theKeyframeHandles;
+ theKeyframe->GetKeyframeHandles(theKeyframeHandles);
+ UICDM::SGetOrSetKeyframeInfo theInfos[3];
+ size_t theValidInfos = 0;
+ if (!theKeyframeHandles.empty()) {
+ // TODO: need to figure out a good way to convert from individual keyframes back to
+ // SValue
+ SValue theValue;
+ switch (theKeyframeHandles.size()) {
+ case 1: {
+ theInfos[0] = SetupKeyframeInfo(theKeyframeHandles[0], *theAnimationCore);
+ theValidInfos = 1;
+
+ } break;
+ case 3: {
+ theInfos[0] = SetupKeyframeInfo(theKeyframeHandles[0], *theAnimationCore);
+ theInfos[1] = SetupKeyframeInfo(theKeyframeHandles[1], *theAnimationCore);
+ theInfos[2] = SetupKeyframeInfo(theKeyframeHandles[2], *theAnimationCore);
+ theValidInfos = 3;
+ } break;
+ default: // not handled
+ break;
+ }
+ // time is relative to the earliest keyframe time.
+ float theRelativeTimeInSecs =
+ CUICDMTimelineKeyframe::GetTimeInSecs(theKeyframe->GetTime())
+ - theEarliestKeyframeTimeInSecs;
+
+ CUICDMAnimationHandle theAnimation =
+ theAnimationCore->GetAnimationForKeyframe(theKeyframeHandles[0]);
+ m_PasteKeyframeCommandHelper->AddKeyframeData(
+ theAnimationCore->GetAnimationInfo(theAnimation).m_Property,
+ theRelativeTimeInSecs, theInfos, theValidInfos);
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.h
new file mode 100644
index 00000000..61ac2740
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_KEYFRAMES_MANAGER_H
+#define INCLUDED_KEYFRAMES_MANAGER_H 1
+
+#pragma once
+
+#include "ITimelineKeyframesManager.h"
+#include "OffsetKeyframesCommandHelper.h"
+
+class CTimelineTranslationManager;
+class CUICDMTimelineKeyframe;
+class CUICDMTimelineItemBinding;
+class CPasteKeyframeCommandHelper;
+
+//=============================================================================
+/**
+ * Abstraction layer to the class that manages both selected keyframes.
+ */
+//=============================================================================
+class CKeyframesManager : public ITimelineKeyframesManager
+{
+public:
+ CKeyframesManager(CTimelineTranslationManager *inTransMgr);
+ virtual ~CKeyframesManager();
+
+ // IKeyframesManager
+ bool HasSelectedKeyframes(bool inOnlyDynamic = false) override;
+ bool HasDynamicKeyframes() override;
+ bool CanPerformKeyframeCopy() override;
+ bool CanPerformKeyframePaste() override;
+ void CopyKeyframes() override;
+ bool RemoveKeyframes(bool inPerformCopy) override;
+ void PasteKeyframes() override;
+ void SetKeyframeInterpolation() override;
+ void DeselectAllKeyframes() override;
+ void SelectAllKeyframes() override;
+ void SetChangedKeyframes() override;
+ // ITimelineKeyframesManager
+ void SetKeyframeTime(long inTime) override;
+ void SetKeyframesDynamic(bool inDynamic) override;
+ bool CanMakeSelectedKeyframesDynamic() override;
+ long OffsetSelectedKeyframes(long inOffset) override;
+ void CommitChangedKeyframes() override;
+ void RollbackChangedKeyframes() override;
+
+ void SetKeyframeSelected(CUICDMTimelineKeyframe *inKeyframe, bool inSelected,
+ CUICDMTimelineItemBinding *inOwningInstance = nullptr);
+
+protected:
+ void SetKeyframeDynamic(CUICDMTimelineKeyframe *inKeyframe, bool inDynamic);
+ void CopySelectedKeyframes();
+
+public:
+ struct SKeyframeInstancePair
+ {
+ CUICDMTimelineKeyframe *m_Keyframe;
+ CUICDMTimelineItemBinding *m_Instance;
+
+ SKeyframeInstancePair(CUICDMTimelineKeyframe *inKeyframe,
+ CUICDMTimelineItemBinding *inInstance)
+ {
+ m_Keyframe = inKeyframe;
+ m_Instance = inInstance;
+ }
+ };
+
+protected:
+ typedef std::vector<SKeyframeInstancePair> TSelectedKeyframeList; ///< handle multiple keyframes
+ ///manipulation, e.g.
+ ///offsetting by dragging
+
+ CTimelineTranslationManager *m_TransMgr;
+ TSelectedKeyframeList m_SelectedKeyframes;
+ COffsetKeyframesCommandHelper m_OffsetKeyframeCommandHelper; // so that we can commit on mouseup
+ CPasteKeyframeCommandHelper *m_PasteKeyframeCommandHelper;
+ std::set<CUICDMTimelineItemBinding *> m_InstanceSet;
+ std::vector<UICDM::CUICDMInstanceHandle> m_InstanceList;
+};
+
+#endif // INCLUDED_IKEYFRAMES_MANAGER_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.cpp
new file mode 100644
index 00000000..73d5d5d2
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.cpp
@@ -0,0 +1,317 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "LayerTimelineItemBinding.h"
+#include "TimelineTranslationManager.h"
+#include "BaseStateRow.h"
+#include "ImageTimelineItemBinding.h"
+#include "EmptyTimelineTimebar.h"
+
+// Data model specific
+#include "IDoc.h"
+#include "ClientDataModelBridge.h"
+#include "DropSource.h"
+#include "Doc.h"
+
+#include "UICDMHandles.h"
+#include "UICDMStudioSystem.h"
+
+#include "UICDMMetaData.h"
+#include "UICDMDataCore.h"
+#include "StudioFullSystem.h"
+#include "StudioCoreSystem.h"
+#include "UICDMSlides.h"
+
+using namespace UICDM;
+
+namespace {
+
+bool ImageSlotIsFilled(UICDM::IPropertySystem *inPropertySystem, CUICDMInstanceHandle inInstance,
+ const TCharStr &inStr)
+{
+ CUICDMPropertyHandle theProperty =
+ inPropertySystem->GetAggregateInstancePropertyByName(inInstance, inStr);
+ SValue theValue;
+ inPropertySystem->GetInstancePropertyValue(inInstance, theProperty, theValue);
+
+ SLong4 theLong4 = UICDM::get<SLong4>(theValue);
+ bool theReturn = theLong4.m_Longs[0] != 0 || theLong4.m_Longs[1] != 0
+ || theLong4.m_Longs[2] != 0 || theLong4.m_Longs[3] != 0;
+
+ return theReturn;
+}
+
+// helper function to find the image binding class that 'represents' this property
+inline CImageTimelineItemBinding *FindImageBindingByProperty(CBaseStateRow *inRow,
+ CUICDMPropertyHandle inProperty)
+{
+ if (!inRow || !inProperty.Valid())
+ return nullptr;
+
+ CImageTimelineItemBinding *theInvalidImageBinding = nullptr;
+ for (long theIndex = 0; theIndex < inRow->GetNumNonPropertyRows(); ++theIndex) {
+ CImageTimelineItemBinding *theImageBinding = dynamic_cast<CImageTimelineItemBinding *>(
+ inRow->GetNonPropertyRow(theIndex)->GetTimelineItemBinding());
+ if (theImageBinding && theImageBinding->GetPropertyHandle() == inProperty) {
+ theInvalidImageBinding = theImageBinding;
+ break;
+ }
+ }
+ return theInvalidImageBinding;
+}
+}
+
+CLayerTimelineItemBinding::CLayerTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ UICDM::CUICDMInstanceHandle inDataHandle)
+ : CUICDMTimelineItemBinding(inMgr, inDataHandle)
+{
+ UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem();
+ TPropertyHandleList theProperties;
+ thePropertySystem->GetAggregateInstanceProperties(inDataHandle, theProperties);
+
+ size_t thePropertyCount = theProperties.size();
+ for (size_t thePropertyIndex = 0; thePropertyIndex < thePropertyCount; ++thePropertyIndex) {
+ CUICDMPropertyHandle theProperty = theProperties[thePropertyIndex];
+
+ AdditionalMetaDataType::Value theAdditionalMetaDataType =
+ thePropertySystem->GetAdditionalMetaDataType(inDataHandle, theProperty);
+
+ if (theAdditionalMetaDataType == AdditionalMetaDataType::Image) {
+ TCharStr theName(thePropertySystem->GetName(theProperty));
+ TCharStr theFormalName(thePropertySystem->GetFormalName(inDataHandle, theProperty));
+ TNameFormalNamePair thePair =
+ std::make_tuple(theName, theFormalName, theProperty);
+ m_ImageNameFormalNamePairs.push_back(thePair);
+ }
+ }
+}
+
+CLayerTimelineItemBinding::~CLayerTimelineItemBinding()
+{
+}
+
+EStudioObjectType CLayerTimelineItemBinding::GetObjectType() const
+{
+ return OBJTYPE_LAYER;
+}
+
+ITimelineItemBinding *CLayerTimelineItemBinding::GetChild(long inIndex)
+{
+ static const TCharStr theLayerPrefix(L"Layer_");
+ UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem();
+
+ UICDM::CUICDMInstanceHandle theInstance = GetInstance();
+ if (theInstance.Valid()) {
+ Q3DStudio::CGraphIterator theChildren;
+ CUICDMSlideHandle theActiveSlide = m_TransMgr->GetDoc()->GetActiveSlide();
+ GetAssetChildrenInTimeParent(theInstance, m_TransMgr->GetDoc(), AmITimeParent(),
+ theChildren, theActiveSlide);
+ theChildren += inIndex;
+
+ UICDM::CUICDMInstanceHandle theChildInstance = theChildren.GetCurrent();
+ if (theChildInstance.Valid()) {
+ std::shared_ptr<IDataCore> theDataCore =
+ m_TransMgr->GetStudioSystem()->GetFullSystem()->GetCoreSystem()->GetDataCore();
+ ISlideSystem *theSlideSystem = m_TransMgr->GetStudioSystem()->GetSlideSystem();
+ ISlideCore *theSlideCore = m_TransMgr->GetStudioSystem()->GetSlideCore();
+
+ size_t theSlotCursor = (size_t)-1;
+ {
+
+ UICDM::IPropertySystem *thePropertySystem =
+ m_TransMgr->GetStudioSystem()->GetPropertySystem();
+ UICDM::SLong4 theGuid;
+ {
+ CUICDMPropertyHandle theTypeProperty =
+ thePropertySystem->GetAggregateInstancePropertyByName(theChildInstance,
+ L"id");
+ SValue theIdValue;
+ thePropertySystem->GetInstancePropertyValue(theChildInstance, theTypeProperty,
+ theIdValue);
+ theGuid = UICDM::get<UICDM::SLong4>(theIdValue);
+ }
+ for (size_t theSlotIndex = 0, theSlotCount = m_ImageNameFormalNamePairs.size();
+ theSlotIndex < theSlotCount; ++theSlotIndex) {
+ bool theIsMatch = false;
+ UICDM::CUICDMPropertyHandle theProperty =
+ std::get<2>(m_ImageNameFormalNamePairs[theSlotIndex]);
+ SValue theValue;
+ const SUICDMPropertyDefinition &theDefinition(
+ theDataCore->GetProperty(theProperty));
+ if (theDefinition.m_Type == DataModelDataType::Long4) {
+ SValue theDCValue;
+ if (theDataCore->GetInstancePropertyValue(theInstance, theProperty,
+ theDCValue)) {
+ SLong4 thePropGuid = get<SLong4>(theDCValue);
+ if (thePropGuid == theGuid)
+ theIsMatch = true;
+ }
+ CUICDMSlideHandle theSlide =
+ theSlideSystem->GetAssociatedSlide(theChildInstance);
+ CUICDMSlideHandle theMasterSlide = theSlideSystem->GetMasterSlide(theSlide);
+ if (theIsMatch == false && theSlide.Valid()
+ && theSlideCore->GetSpecificInstancePropertyValue(
+ theSlide, theInstance, theProperty, theValue)) {
+ SLong4 thePropGuid = get<SLong4>(theValue);
+ if (thePropGuid == theGuid)
+ theIsMatch = true;
+ }
+ }
+ if (theIsMatch) {
+ theSlotCursor = theSlotIndex;
+ break;
+ }
+ }
+ }
+ if (theSlotCursor != (size_t)-1) {
+ CUICDMPropertyHandle theImageProperty =
+ thePropertySystem->GetAggregateInstancePropertyByName(
+ m_DataHandle, std::get<0>(m_ImageNameFormalNamePairs[theSlotCursor]));
+ return GetOrCreateImageBinding(
+ theImageProperty,
+ std::get<1>(m_ImageNameFormalNamePairs[theSlotCursor]).wide_str());
+ } else
+ return m_TransMgr->GetOrCreate(theChildInstance);
+ }
+ }
+ return nullptr;
+}
+
+void CLayerTimelineItemBinding::OnAddChild(UICDM::CUICDMInstanceHandle inInstance)
+{
+ using namespace UICDM;
+ CClientDataModelBridge *theBridge = m_TransMgr->GetStudioSystem()->GetClientDataModelBridge();
+ // This is handled via the OnPropertyChanged call below
+ if (theBridge->IsImageInstance(inInstance))
+ return;
+ else
+ CUICDMTimelineItemBinding::OnAddChild(inInstance);
+}
+
+void CLayerTimelineItemBinding::OnPropertyChanged(CUICDMPropertyHandle inPropertyHandle)
+{
+ bool theHandled = false;
+ if (m_Row) {
+ UICDM::IPropertySystem *thePropertySystem =
+ m_TransMgr->GetStudioSystem()->GetPropertySystem();
+ CClientDataModelBridge *theBridge =
+ m_TransMgr->GetStudioSystem()->GetClientDataModelBridge();
+ UICDM::TCharStr thePropertyName = thePropertySystem->GetName(inPropertyHandle);
+ size_t theSlotCount = m_ImageNameFormalNamePairs.size();
+ for (size_t theSlotIndex = 0; theSlotIndex < theSlotCount; ++theSlotIndex) {
+ UICDM::TCharStr thePropName = std::get<0>(m_ImageNameFormalNamePairs[theSlotIndex]);
+ if (thePropertyName == thePropName) {
+ if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, thePropName)) {
+ // already created, bail!
+ if (m_TransMgr->GetBinding(GetImage(inPropertyHandle)))
+ return;
+
+ // Image property was changed from one non-zero guid value to another, delete
+ // the old and and create a new one
+ CImageTimelineItemBinding *theReplacedImageBinding =
+ FindImageBindingByProperty(m_Row, inPropertyHandle);
+ if (theReplacedImageBinding)
+ m_Row->RemoveChildRow(theReplacedImageBinding);
+
+ ITimelineItemBinding *theNextImageBinding = nullptr;
+ // Determine if this is inserted somewhere in the existing list.
+ for (size_t theNextImage = theSlotIndex + 1; theNextImage < theSlotCount;
+ ++theNextImage) {
+ UICDM::TCharStr theTempName =
+ std::get<0>(m_ImageNameFormalNamePairs[theNextImage]);
+ if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, theTempName)) {
+ CUICDMPropertyHandle theNextImageProperty =
+ theBridge->GetAggregateInstancePropertyByName(m_DataHandle,
+ theTempName);
+ theNextImageBinding =
+ m_TransMgr->GetBinding(GetImage(theNextImageProperty));
+ break;
+ }
+ }
+ m_Row->AddChildRow(
+ GetOrCreateImageBinding(
+ inPropertyHandle,
+ std::get<1>(m_ImageNameFormalNamePairs[theSlotIndex]).wide_str()),
+ theNextImageBinding);
+ } else // check for delete
+ {
+ // GetImage will not return anything valid since the value is nuked.
+ // From the UI end, there is no way we can tell which image is associated with
+ // this property, since that is "encapsulated" in the property value.
+ CImageTimelineItemBinding *theInvalidImageBinding =
+ FindImageBindingByProperty(m_Row, inPropertyHandle);
+ if (theInvalidImageBinding)
+ m_Row->RemoveChildRow(theInvalidImageBinding);
+ }
+ theHandled = true;
+ break;
+ }
+ }
+ }
+ if (!theHandled)
+ CUICDMTimelineItemBinding::OnPropertyChanged(inPropertyHandle);
+}
+
+UICDM::CUICDMInstanceHandle
+CLayerTimelineItemBinding::GetImage(UICDM::CUICDMPropertyHandle inPropertyHandle)
+{
+ UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem();
+ SValue theImageValue;
+ thePropertySystem->GetInstancePropertyValue(m_DataHandle, inPropertyHandle, theImageValue);
+ SLong4 theImageLong4 = UICDM::get<SLong4>(theImageValue);
+ return m_TransMgr->GetStudioSystem()->GetClientDataModelBridge()->GetImageInstanceByGUID(
+ theImageLong4);
+}
+
+ITimelineItemBinding *
+CLayerTimelineItemBinding::GetOrCreateImageBinding(UICDM::CUICDMPropertyHandle inPropertyHandle,
+ const wchar_t *inName)
+{
+ UICDM::CUICDMInstanceHandle theImageInstance = GetImage(inPropertyHandle);
+ ITimelineItemBinding *theImageTimelineRow = m_TransMgr->GetBinding(theImageInstance);
+ if (!theImageTimelineRow) // create
+ {
+ theImageTimelineRow = m_TransMgr->GetOrCreate(theImageInstance);
+ // Set the name, by spec: the nice name.
+ theImageTimelineRow->GetTimelineItem()->SetName(inName);
+ CImageTimelineItemBinding *theImageBinding =
+ dynamic_cast<CImageTimelineItemBinding *>(theImageTimelineRow);
+ if (theImageBinding)
+ theImageBinding->SetPropertyHandle(inPropertyHandle);
+ }
+ return theImageTimelineRow;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.h
new file mode 100644
index 00000000..d4826f2f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_LAYER_TIMELINEITEM_BINDING_H
+#define INCLUDED_LAYER_TIMELINEITEM_BINDING_H 1
+
+#pragma once
+
+#include "UICDMTimelineItemBinding.h"
+
+namespace UICDM {
+class CStudioSystem;
+}
+
+//=============================================================================
+/**
+ * Binding to generic UICDM object
+ */
+class CLayerTimelineItemBinding : public CUICDMTimelineItemBinding
+{
+public: // Types
+ typedef std::tuple<UICDM::TCharStr, UICDM::TCharStr, UICDM::CUICDMPropertyHandle>
+ TNameFormalNamePair;
+ typedef std::vector<TNameFormalNamePair> TNameFormalNamePairList;
+
+protected: // Members
+ TNameFormalNamePairList m_ImageNameFormalNamePairs;
+
+public: // Construction
+ CLayerTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ UICDM::CUICDMInstanceHandle inDataHandle);
+ virtual ~CLayerTimelineItemBinding();
+
+public: // CUICDMTimelineItemBinding
+ EStudioObjectType GetObjectType() const override;
+ // Hierarchy
+ ITimelineItemBinding *GetChild(long inIndex) override;
+ void OnAddChild(UICDM::CUICDMInstanceHandle inInstance) override;
+ // Event callback
+ void OnPropertyChanged(UICDM::CUICDMPropertyHandle inPropertyHandle) override;
+
+protected:
+ UICDM::CUICDMInstanceHandle GetImage(UICDM::CUICDMPropertyHandle inPropertyHandle);
+ ITimelineItemBinding *GetOrCreateImageBinding(UICDM::CUICDMPropertyHandle inPropertyHandle,
+ const wchar_t *inName);
+};
+
+#endif // INCLUDED_LAYER_TIMELINEITEM_BINDING_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.cpp
new file mode 100644
index 00000000..eb91714e
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.cpp
@@ -0,0 +1,336 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "MaterialTimelineItemBinding.h"
+#include "TimelineTranslationManager.h"
+#include "BaseStateRow.h"
+#include "ImageTimelineItemBinding.h"
+#include "EmptyTimelineTimebar.h"
+
+// Data model specific
+#include "IDoc.h"
+#include "ClientDataModelBridge.h"
+#include "DropSource.h"
+
+#include "UICDMHandles.h"
+#include "UICDMStudioSystem.h"
+
+#include "UICDMMetaData.h"
+#include "UICDMDataCore.h"
+#include "StudioFullSystem.h"
+#include "StudioCoreSystem.h"
+
+using namespace UICDM;
+
+CMaterialTimelineItemBinding::CMaterialTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ CUICDMInstanceHandle inDataHandle)
+ : CUICDMTimelineItemBinding(inMgr, inDataHandle)
+{
+ UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem();
+ TPropertyHandleList theProperties;
+ thePropertySystem->GetAggregateInstanceProperties(inDataHandle, theProperties);
+
+ size_t thePropertyCount = theProperties.size();
+ for (size_t thePropertyIndex = 0; thePropertyIndex < thePropertyCount; ++thePropertyIndex) {
+ CUICDMPropertyHandle theProperty = theProperties[thePropertyIndex];
+
+ AdditionalMetaDataType::Value theAdditionalMetaDataType =
+ thePropertySystem->GetAdditionalMetaDataType(inDataHandle, theProperty);
+
+ if (theAdditionalMetaDataType == AdditionalMetaDataType::Image) {
+ TCharStr theName(thePropertySystem->GetName(theProperty));
+ TCharStr theFormalName(thePropertySystem->GetFormalName(inDataHandle, theProperty));
+ TNameFormalNamePair thePair = std::make_tuple(theName, theFormalName);
+ m_ImageNameFormalNamePairs.push_back(thePair);
+ }
+ }
+}
+
+CMaterialTimelineItemBinding::~CMaterialTimelineItemBinding()
+{
+}
+
+ITimelineTimebar *CMaterialTimelineItemBinding::GetTimebar()
+{ // No timebars on materials
+ return new CEmptyTimelineTimebar();
+}
+
+EStudioObjectType CMaterialTimelineItemBinding::GetObjectType() const
+{
+ return OBJTYPE_MATERIAL;
+}
+
+bool CMaterialTimelineItemBinding::ShowToggleControls() const
+{
+ // Materials have no toggle controls, by design
+ return false;
+}
+
+bool ImageSlotIsFilled(UICDM::IPropertySystem *inPropertySystem, CUICDMInstanceHandle inInstance,
+ const TCharStr &inStr)
+{
+ CUICDMPropertyHandle theProperty =
+ inPropertySystem->GetAggregateInstancePropertyByName(inInstance, inStr);
+ SValue theValue;
+ inPropertySystem->GetInstancePropertyValue(inInstance, theProperty, theValue);
+
+ // Prevent assertion down the path when changing from edited standard material to reference material
+ if (UICDM::GetValueType(theValue) == DataModelDataType::None)
+ return false;
+
+ SLong4 theLong4 = UICDM::get<SLong4>(theValue);
+ bool theReturn = theLong4.m_Longs[0] != 0 || theLong4.m_Longs[1] != 0
+ || theLong4.m_Longs[2] != 0 || theLong4.m_Longs[3] != 0;
+
+ return theReturn;
+}
+
+long CMaterialTimelineItemBinding::GetChildrenCount()
+{
+ long theReturnCount = 0;
+ if (m_TransMgr->GetStudioSystem()->IsInstance(m_DataHandle)) {
+ UICDM::IPropertySystem *thePropertySystem =
+ m_TransMgr->GetStudioSystem()->GetPropertySystem();
+ size_t theSlotCount = m_ImageNameFormalNamePairs.size();
+ for (size_t theSlotIndex = 0; theSlotIndex < theSlotCount; ++theSlotIndex) {
+ if (ImageSlotIsFilled(thePropertySystem, m_DataHandle,
+ std::get<0>(m_ImageNameFormalNamePairs[theSlotIndex]))) {
+ ++theReturnCount;
+ }
+ }
+ }
+
+ return theReturnCount;
+}
+
+ITimelineItemBinding *CMaterialTimelineItemBinding::GetChild(long inIndex)
+{
+ UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem();
+
+ size_t theSlotCursor = 0;
+ size_t theSlotCount = m_ImageNameFormalNamePairs.size();
+ for (size_t theSlotIndex = 0; theSlotIndex < theSlotCount; ++theSlotIndex) {
+ if (ImageSlotIsFilled(thePropertySystem, m_DataHandle,
+ std::get<0>(m_ImageNameFormalNamePairs[theSlotIndex]))) {
+ inIndex--;
+
+ if (inIndex < 0) {
+ theSlotCursor = theSlotIndex;
+ break;
+ }
+ }
+ }
+ CUICDMPropertyHandle theImageProperty = thePropertySystem->GetAggregateInstancePropertyByName(
+ m_DataHandle, std::get<0>(m_ImageNameFormalNamePairs[theSlotCursor]));
+ return GetOrCreateImageBinding(
+ theImageProperty, std::get<1>(m_ImageNameFormalNamePairs[theSlotCursor]).wide_str());
+}
+
+void CMaterialTimelineItemBinding::OnAddChild(UICDM::CUICDMInstanceHandle inInstance)
+{
+ using namespace UICDM;
+ CClientDataModelBridge *theBridge = m_TransMgr->GetStudioSystem()->GetClientDataModelBridge();
+ // This is handled via the OnPropertyChanged call below
+ if (theBridge->IsImageInstance(inInstance))
+ return;
+ else
+ CUICDMTimelineItemBinding::OnAddChild(inInstance);
+}
+
+// helper function to find the image binding class that 'represents' this property
+inline CImageTimelineItemBinding *FindImageBindingByProperty(CBaseStateRow *inRow,
+ CUICDMPropertyHandle inProperty)
+{
+ if (!inRow || !inProperty.Valid())
+ return nullptr;
+
+ CImageTimelineItemBinding *theInvalidImageBinding = nullptr;
+ for (long theIndex = 0; theIndex < inRow->GetNumNonPropertyRows(); ++theIndex) {
+ CImageTimelineItemBinding *theImageBinding = dynamic_cast<CImageTimelineItemBinding *>(
+ inRow->GetNonPropertyRow(theIndex)->GetTimelineItemBinding());
+ if (theImageBinding && theImageBinding->GetPropertyHandle() == inProperty) {
+ theInvalidImageBinding = theImageBinding;
+ break;
+ }
+ }
+ return theInvalidImageBinding;
+}
+
+void CMaterialTimelineItemBinding::OnPropertyChanged(CUICDMPropertyHandle inPropertyHandle)
+{
+ bool theHandled = false;
+ if (m_Row) {
+ UICDM::IPropertySystem *thePropertySystem =
+ m_TransMgr->GetStudioSystem()->GetPropertySystem();
+ CClientDataModelBridge *theBridge =
+ m_TransMgr->GetStudioSystem()->GetClientDataModelBridge();
+ UICDM::TCharStr thePropertyName = thePropertySystem->GetName(inPropertyHandle);
+ size_t theSlotCount = m_ImageNameFormalNamePairs.size();
+ for (size_t theSlotIndex = 0; theSlotIndex < theSlotCount; ++theSlotIndex) {
+ UICDM::TCharStr thePropName = std::get<0>(m_ImageNameFormalNamePairs[theSlotIndex]);
+ if (thePropertyName == thePropName) {
+ if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, thePropName)) {
+ // already created, bail!
+ if (m_TransMgr->GetBinding(GetImage(inPropertyHandle)))
+ return;
+
+ // Image property was changed from one non-zero guid value to another, delete
+ // the old and and create a new one
+ CImageTimelineItemBinding *theReplacedImageBinding =
+ FindImageBindingByProperty(m_Row, inPropertyHandle);
+ if (theReplacedImageBinding)
+ m_Row->RemoveChildRow(theReplacedImageBinding);
+
+ ITimelineItemBinding *theNextImageBinding = nullptr;
+ // Determine if this is inserted somewhere in the existing list.
+ for (size_t theNextImage = theSlotIndex + 1; theNextImage < theSlotCount;
+ ++theNextImage) {
+ UICDM::TCharStr theTempName =
+ std::get<0>(m_ImageNameFormalNamePairs[theNextImage]);
+ if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, theTempName)) {
+ CUICDMPropertyHandle theNextImageProperty =
+ theBridge->GetAggregateInstancePropertyByName(m_DataHandle,
+ theTempName);
+ theNextImageBinding =
+ m_TransMgr->GetBinding(GetImage(theNextImageProperty));
+ break;
+ }
+ }
+ m_Row->AddChildRow(
+ GetOrCreateImageBinding(
+ inPropertyHandle,
+ std::get<1>(m_ImageNameFormalNamePairs[theSlotIndex]).wide_str()),
+ theNextImageBinding);
+ } else // check for delete
+ {
+ // GetImage will not return anything valid since the value is nuked.
+ // From the UI end, there is no way we can tell which image is associated with
+ // this property, since that is "encapsulated" in the property value.
+ CImageTimelineItemBinding *theInvalidImageBinding =
+ FindImageBindingByProperty(m_Row, inPropertyHandle);
+ if (theInvalidImageBinding)
+ m_Row->RemoveChildRow(theInvalidImageBinding);
+ }
+ theHandled = true;
+ break;
+ }
+ }
+ }
+ if (!theHandled)
+ CUICDMTimelineItemBinding::OnPropertyChanged(inPropertyHandle);
+}
+
+void CMaterialTimelineItemBinding::OnPropertyLinked(CUICDMPropertyHandle inPropertyHandle)
+{
+ bool theHandled = false;
+ if (m_Row) {
+ UICDM::IPropertySystem *thePropertySystem =
+ m_TransMgr->GetStudioSystem()->GetPropertySystem();
+ CClientDataModelBridge *theBridge =
+ m_TransMgr->GetStudioSystem()->GetClientDataModelBridge();
+ UICDM::TCharStr thePropertyName = thePropertySystem->GetName(inPropertyHandle);
+ size_t theSlotCount = m_ImageNameFormalNamePairs.size();
+ for (size_t theSlotIndex = 0; theSlotIndex < theSlotCount; ++theSlotIndex) {
+ UICDM::TCharStr thePropName = std::get<0>(m_ImageNameFormalNamePairs[theSlotIndex]);
+ if (thePropertyName == thePropName) {
+ // Refresh image child row by delete and recreate
+ CImageTimelineItemBinding *theInvalidImageBinding =
+ FindImageBindingByProperty(m_Row, inPropertyHandle);
+ if (theInvalidImageBinding)
+ m_Row->RemoveChildRow(theInvalidImageBinding);
+
+ if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, thePropName)) {
+ ITimelineItemBinding *theNextImageBinding = nullptr;
+ // Determine if this is inserted somewhere in the existing list.
+ for (size_t theNextImage = theSlotIndex + 1; theNextImage < theSlotCount;
+ ++theNextImage) {
+ UICDM::TCharStr theTempName =
+ std::get<0>(m_ImageNameFormalNamePairs[theNextImage]);
+ if (ImageSlotIsFilled(thePropertySystem, m_DataHandle, theTempName)) {
+ CUICDMPropertyHandle theNextImageProperty =
+ theBridge->GetAggregateInstancePropertyByName(m_DataHandle,
+ theTempName);
+ theNextImageBinding =
+ m_TransMgr->GetBinding(GetImage(theNextImageProperty));
+ break;
+ }
+ }
+ m_Row->AddChildRow(
+ GetOrCreateImageBinding(
+ inPropertyHandle,
+ std::get<1>(m_ImageNameFormalNamePairs[theSlotIndex]).wide_str()),
+ theNextImageBinding);
+ }
+
+ theHandled = true;
+ break;
+ }
+ }
+ }
+ if (!theHandled)
+ CUICDMTimelineItemBinding::OnPropertyLinked(inPropertyHandle);
+}
+
+UICDM::CUICDMInstanceHandle
+CMaterialTimelineItemBinding::GetImage(UICDM::CUICDMPropertyHandle inPropertyHandle)
+{
+ UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem();
+ SValue theImageValue;
+ thePropertySystem->GetInstancePropertyValue(m_DataHandle, inPropertyHandle, theImageValue);
+ SLong4 theImageLong4 = UICDM::get<SLong4>(theImageValue);
+ return m_TransMgr->GetStudioSystem()->GetClientDataModelBridge()->GetImageInstanceByGUID(
+ theImageLong4);
+}
+
+ITimelineItemBinding *
+CMaterialTimelineItemBinding::GetOrCreateImageBinding(UICDM::CUICDMPropertyHandle inPropertyHandle,
+ const wchar_t *inName)
+{
+ UICDM::CUICDMInstanceHandle theImageInstance = GetImage(inPropertyHandle);
+ ITimelineItemBinding *theImageTimelineRow = m_TransMgr->GetBinding(theImageInstance);
+ if (!theImageTimelineRow) // create
+ {
+ theImageTimelineRow = m_TransMgr->GetOrCreate(theImageInstance);
+ // Set the name, by spec: the nice name.
+ theImageTimelineRow->GetTimelineItem()->SetName(inName);
+ CImageTimelineItemBinding *theImageBinding =
+ dynamic_cast<CImageTimelineItemBinding *>(theImageTimelineRow);
+ if (theImageBinding)
+ theImageBinding->SetPropertyHandle(inPropertyHandle);
+ }
+ return theImageTimelineRow;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.h
new file mode 100644
index 00000000..e1c2188d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_MATERIAL_TIMELINEITEM_BINDING_H
+#define INCLUDED_MATERIAL_TIMELINEITEM_BINDING_H 1
+
+#pragma once
+
+#include "UICDMTimelineItemBinding.h"
+#include "UICDMDataTypes.h"
+
+//==============================================================================
+// Classes
+//==============================================================================
+class CTimelineTranslationManager;
+class CBaseStateRow;
+
+//=============================================================================
+/**
+ * Binding to a UICDM object of Material type
+ */
+class CMaterialTimelineItemBinding : public CUICDMTimelineItemBinding
+{
+public: // Types
+ typedef std::tuple<UICDM::TCharStr, UICDM::TCharStr> TNameFormalNamePair;
+ typedef std::vector<TNameFormalNamePair> TNameFormalNamePairList;
+
+protected: // Members
+ TNameFormalNamePairList m_ImageNameFormalNamePairs;
+
+public: // Construction
+ CMaterialTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ UICDM::CUICDMInstanceHandle inDataHandle);
+ virtual ~CMaterialTimelineItemBinding();
+
+public: // CUICDMTimelineItemBinding
+ ITimelineTimebar *GetTimebar() override;
+ EStudioObjectType GetObjectType() const override;
+ bool ShowToggleControls() const override;
+ // Hierarchy
+ long GetChildrenCount() override;
+ ITimelineItemBinding *GetChild(long inIndex) override;
+ void OnAddChild(UICDM::CUICDMInstanceHandle inInstance) override;
+ // Event callback
+ void OnPropertyChanged(UICDM::CUICDMPropertyHandle inPropertyHandle) override;
+ void OnPropertyLinked(UICDM::CUICDMPropertyHandle inPropertyHandle) override;
+
+protected:
+ UICDM::CUICDMInstanceHandle GetImage(UICDM::CUICDMPropertyHandle inPropertyHandle);
+ ITimelineItemBinding *GetOrCreateImageBinding(UICDM::CUICDMPropertyHandle inPropertyHandle,
+ const wchar_t *inName);
+};
+
+#endif // INCLUDED_MATERIAL_TIMELINEITEM_BINDING_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.cpp
new file mode 100644
index 00000000..374c123b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "OffsetKeyframesCommandHelper.h"
+#include "Core.h"
+
+// Data model specific
+#include "IDoc.h"
+#include "CmdDataModelChangeKeyframe.h"
+#include "IDocumentEditor.h"
+
+#include "UICDMTimelineKeyframe.h" //TODO: remove once we resolve the precision issue
+
+using namespace UICDM;
+
+COffsetKeyframesCommandHelper::COffsetKeyframesCommandHelper(CDoc &inDoc)
+ : Q3DStudio::CUpdateableDocumentEditor(inDoc)
+ , m_Doc(inDoc)
+{
+}
+
+COffsetKeyframesCommandHelper::~COffsetKeyframesCommandHelper()
+{
+ Finalize();
+}
+
+//@param inTime time in millisecs
+void COffsetKeyframesCommandHelper::SetCommandTime(UICDM::CUICDMKeyframeHandle inKeyframe,
+ long inTime)
+{
+ // The UICDM system will take care of merging these under the hood.
+ ENSURE_EDITOR(L"Set Keyframe Time").SetKeyframeTime(inKeyframe, inTime);
+}
+
+// equivalent to commit (onmouseup)
+void COffsetKeyframesCommandHelper::Finalize()
+{
+ CommitEditor();
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.h
new file mode 100644
index 00000000..3a58e672
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_OFFSET_KEYFRAMES_COMMAND_HELPER_H
+#define INCLUDED_OFFSET_KEYFRAMES_COMMAND_HELPER_H 1
+
+#pragma once
+
+// Data model
+#include "UICDMHandles.h"
+#include "IDocumentEditor.h"
+
+namespace Q3DStudio {
+class IDocumentEditor;
+}
+
+//==============================================================================
+// Classes
+//==============================================================================
+class CCmdDataModelSetKeyframeTime;
+
+class COffsetKeyframesCommandHelper : public Q3DStudio::CUpdateableDocumentEditor
+{
+protected:
+ CDoc &m_Doc;
+
+public:
+ COffsetKeyframesCommandHelper(CDoc &inDoc);
+ ~COffsetKeyframesCommandHelper();
+
+ void SetCommandTime(UICDM::CUICDMKeyframeHandle inKeyframe, long inTime);
+ void Finalize();
+ void Rollback() { RollbackEditor(); }
+};
+
+#endif \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/PasteKeyframesCommandHelper.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/PasteKeyframesCommandHelper.h
new file mode 100644
index 00000000..130f6d20
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/PasteKeyframesCommandHelper.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_PASTE_KEYFRAME_COMMAND_HELPER_H
+#define INCLUDED_PASTE_KEYFRAME_COMMAND_HELPER_H 1
+
+#pragma once
+
+//==============================================================================
+// Include
+//==============================================================================
+#include "CmdDataModelInsertKeyframe.h"
+#include "UICDMPropertyDefinition.h"
+#include "UICDMDataCore.h"
+
+// This caches all copied keyframes' time and data, for a paste action.
+// This has to deal with the actual data and not keyframe handles, because a prior Cut can
+// invalidate those handles.
+class CPasteKeyframeCommandHelper
+{
+protected:
+ typedef std::vector<CCmdDataModelInsertKeyframe::STimeKeyframeData> TCopiedKeyframeList;
+ TCopiedKeyframeList m_CopiedKeyframeList;
+
+public: // Construction
+ CPasteKeyframeCommandHelper() {}
+ ~CPasteKeyframeCommandHelper() {}
+
+ // inTime should be relative to the earliest keyframe time in this list
+ void AddKeyframeData(UICDM::CUICDMPropertyHandle inProperty, float inKeyframeTime,
+ UICDM::SGetOrSetKeyframeInfo *inInfos, size_t inInfoCount)
+ {
+ m_CopiedKeyframeList.push_back(CCmdDataModelInsertKeyframe::STimeKeyframeData(
+ inProperty, inKeyframeTime, inInfos, inInfoCount));
+ }
+
+ bool HasCopiedKeyframes() const { return !m_CopiedKeyframeList.empty(); }
+
+ // Triggered by a "Paste Keyframe" action
+ // Note: The logic is based on what the Animation Manager in the old system used to do.
+ // 1. The condition for paste to occur is that the property name matches.
+ // The old data model has a limitation that if the destination property is a linked property,
+ // the source has to come from the same instance, most likely a easy way out than to deal with
+ // with having to 'sync' all linked animation tracks.
+ // but that is not an issue in the new data model.
+ //
+ // 2. The first pasted keyframe is at current view time and the rest are offset accordingly.
+ CCmdDataModelInsertKeyframe *GetCommand(CDoc *inDoc, long inTimeOffsetInMilliseconds,
+ UICDM::CUICDMInstanceHandle inTargetInstance)
+ {
+ using namespace UICDM;
+
+ CCmdDataModelInsertKeyframe *theInsertKeyframesCommand = nullptr;
+ TCopiedKeyframeList::iterator theIter = m_CopiedKeyframeList.begin();
+ UICDM::IPropertySystem *thePropertySystem = inDoc->GetStudioSystem()->GetPropertySystem();
+ CClientDataModelBridge *theBridge = inDoc->GetStudioSystem()->GetClientDataModelBridge();
+
+ for (; theIter != m_CopiedKeyframeList.end(); ++theIter) {
+ TCharStr thePropertyName = thePropertySystem->GetName(theIter->m_Property);
+ DataModelDataType::Value thePropertyType =
+ thePropertySystem->GetDataType(theIter->m_Property);
+ CUICDMPropertyHandle theTargetPropertyHandle =
+ theBridge->GetAggregateInstancePropertyByName(inTargetInstance, thePropertyName);
+ if (theTargetPropertyHandle.Valid()) // property exists on target
+ {
+ // sanity check for type match
+ DataModelDataType::Value theTargetPropertyType =
+ thePropertySystem->GetDataType(theTargetPropertyHandle);
+ if (theTargetPropertyType == thePropertyType) {
+ // 2. Offset keyframe time by current view time
+ double milliseconds = theIter->m_KeyframeTime * 1000.0;
+ double theTimeInMilliseconds = milliseconds + inTimeOffsetInMilliseconds;
+ float theTimeInSeconds = static_cast<float>(theTimeInMilliseconds / 1000.0);
+
+ if (!theInsertKeyframesCommand)
+ theInsertKeyframesCommand = new CCmdDataModelInsertKeyframe(
+ inDoc, inTargetInstance, theTargetPropertyHandle, theTimeInSeconds,
+ theIter->m_Infos, theIter->m_ValidInfoCount);
+ else
+ theInsertKeyframesCommand->AddKeyframeData(
+ theTargetPropertyHandle, theTimeInSeconds, theIter->m_Infos,
+ theIter->m_ValidInfoCount);
+ }
+ }
+ }
+ return theInsertKeyframesCommand;
+ }
+
+ void Clear() { m_CopiedKeyframeList.clear(); }
+};
+
+#endif
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.cpp
new file mode 100644
index 00000000..286a899f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.cpp
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "stdafx.h"
+#include "PathAnchorPointTimelineItemBinding.h"
+#include "EmptyTimelineTimebar.h"
+
+using namespace UICDM;
+
+CPathAnchorPointTimelineItemBinding::CPathAnchorPointTimelineItemBinding(
+ CTimelineTranslationManager *inMgr, CUICDMInstanceHandle inDataHandle)
+ : CUICDMTimelineItemBinding(inMgr, inDataHandle)
+{
+}
+
+ITimelineTimebar *CPathAnchorPointTimelineItemBinding::GetTimebar()
+{
+ return new CEmptyTimelineTimebar();
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.h
new file mode 100644
index 00000000..2bc3f8d6
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef PATH_ANCHOR_POINT_TIMELINE_ITEM_BINDING
+#define PATH_ANCHOR_POINT_TIMELINE_ITEM_BINDING
+#pragma once
+
+#include "UICDMTimelineItemBinding.h"
+#include "UICDMDataTypes.h"
+#include <boost/tuple/tuple.hpp>
+
+//==============================================================================
+// Classes
+//==============================================================================
+class CTimelineTranslationManager;
+class CBaseStateRow;
+
+//=============================================================================
+/**
+ * Binding to a UICDM object of Material type
+ */
+class CPathAnchorPointTimelineItemBinding : public CUICDMTimelineItemBinding
+{
+public: // Construction
+ CPathAnchorPointTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ UICDM::CUICDMInstanceHandle inDataHandle);
+
+ bool ShowToggleControls() const override { return false; }
+ bool IsVisible() const override { return true; }
+ void SetVisible(bool) override {}
+ ITimelineTimebar *GetTimebar() override;
+ bool IsLocked() const override { return false; }
+ void SetLocked(bool) override {}
+ bool IsShy() const override { return false; }
+ void SetShy(bool) override {}
+ Q3DStudio::CString GetName() const override { return L"Anchor Point"; }
+ void SetName(const Q3DStudio::CString &) override {}
+};
+
+#endif
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.cpp
new file mode 100644
index 00000000..3fbed168
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.cpp
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "stdafx.h"
+#include "PathTimelineItemBinding.h"
+#include "TimelineTranslationManager.h"
+#include "Doc.h"
+
+bool CPathTimelineItemBinding::IsExternalizeable()
+{
+ // If this path has subpath children, then it is externalizeable.
+ return m_TransMgr->GetDoc()->GetDocumentReader().IsPathExternalizeable(GetInstance());
+}
+
+void CPathTimelineItemBinding::Externalize()
+{
+ Q3DStudio::ScopedDocumentEditor(*m_TransMgr->GetDoc(), L"Externalize Path Buffer", __FILE__,
+ __LINE__)
+ ->ExternalizePath(GetInstance());
+}
+
+bool CPathTimelineItemBinding::IsInternalizeable()
+{
+ // If this path has a sourcepath, then it might be internalizeable
+ return m_TransMgr->GetDoc()->GetDocumentReader().IsPathInternalizeable(GetInstance());
+}
+
+void CPathTimelineItemBinding::Internalize()
+{
+ Q3DStudio::ScopedDocumentEditor(*m_TransMgr->GetDoc(), L"Internalize Path Buffer", __FILE__,
+ __LINE__)
+ ->InternalizePath(GetInstance());
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.h
new file mode 100644
index 00000000..1be4b2e1
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef PATH_TIMELINE_ITEM_BINDING
+#define PATH_TIMELINE_ITEM_BINDING
+#pragma once
+#include "UICDMTimelineItemBinding.h"
+#include "UICDMDataTypes.h"
+#include <boost/tuple/tuple.hpp>
+
+//==============================================================================
+// Classes
+//==============================================================================
+class CTimelineTranslationManager;
+class CBaseStateRow;
+
+//=============================================================================
+/**
+ * Binding to a UICDM object of Material type
+ */
+class CPathTimelineItemBinding : public CUICDMTimelineItemBinding
+{
+public: // Construction
+ CPathTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ UICDM::CUICDMInstanceHandle inDataHandle)
+ : CUICDMTimelineItemBinding(inMgr, inDataHandle)
+ {
+ }
+
+ bool IsExternalizeable() override;
+ void Externalize() override;
+ bool IsInternalizeable() override;
+ void Internalize() override;
+};
+
+#endif
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.cpp
new file mode 100644
index 00000000..ce381f44
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.cpp
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "SlideTimelineItemBinding.h"
+#include "BaseStateRow.h"
+
+// Data model specific
+#include "Doc.h"
+#include "CmdGeneric.h"
+#include "EmptyTimelineTimebar.h"
+
+#include "UICDMStudioSystem.h"
+#include "UICDMSlides.h"
+#include "ClientDataModelBridge.h"
+
+using namespace UICDM;
+
+CSlideTimelineItemBinding::CSlideTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ CUICDMInstanceHandle inDataHandle)
+ : CUICDMTimelineItemBinding(inMgr)
+{
+ UICDM::CUICDMSlideHandle theSlideHandle =
+ m_StudioSystem->GetSlideSystem()->GetSlideByInstance(inDataHandle);
+
+ // Get the owning component of m_SlideHandle.
+ // This should return CAsset OBJTYPE_SCENE or OBJTYPE_COMPONENT.
+ UICDM::CUICDMInstanceHandle theInstance =
+ m_StudioSystem->GetClientDataModelBridge()->GetOwningComponentInstance(theSlideHandle);
+ SetInstanceHandle(theInstance);
+
+ // Listen to change on Asset name
+ IStudioFullSystemSignalProvider *theEngine = m_StudioSystem->GetFullSystemSignalProvider();
+ std::function<void(CUICDMInstanceHandle, CUICDMPropertyHandle)> theSetter(
+ std::bind(&CSlideTimelineItemBinding::OnPropertyChanged, this, std::placeholders::_2));
+ m_Connection = theEngine->ConnectInstancePropertyValue(
+ std::bind(UICDM::MaybackCallbackInstancePropertyValue<std::function<void(
+ CUICDMInstanceHandle, CUICDMPropertyHandle)>>,
+ std::placeholders::_1, std::placeholders::_2, theInstance,
+ m_StudioSystem->GetClientDataModelBridge()->GetNameProperty(), theSetter));
+}
+
+ITimelineTimebar *CSlideTimelineItemBinding::GetTimebar()
+{ // No timebars on slides
+ return new CEmptyTimelineTimebar();
+}
+
+void CSlideTimelineItemBinding::SetName(const Q3DStudio::CString & /*inName*/)
+{
+ // Do nothing because name is read only
+}
+
+void CSlideTimelineItemBinding::Bind(CBaseStateRow *inRow)
+{
+ CUICDMTimelineItemBinding::Bind(inRow);
+ GetRow()->SetNameReadOnly(true);
+}
+
+bool CSlideTimelineItemBinding::IsValidTransaction(EUserTransaction inTransaction)
+{
+ UICDM::CUICDMInstanceHandle theInstance = GetInstance();
+ switch (inTransaction) {
+ // Disable the following context menus
+ case EUserTransaction_Rename:
+ case EUserTransaction_MakeComponent:
+ case EUserTransaction_EditComponent:
+ return false;
+ }
+
+ return CUICDMTimelineItemBinding::IsValidTransaction(inTransaction);
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.h
new file mode 100644
index 00000000..759fdfb9
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_SLIDE_TIMELINEITEM_BINDING_H
+#define INCLUDED_SLIDE_TIMELINEITEM_BINDING_H 1
+
+#pragma once
+
+#include "UICDMTimelineItemBinding.h"
+
+//==============================================================================
+// Classes
+//==============================================================================
+class ITimelineItem;
+class CTimelineTranslationManager;
+class CBaseStateRow;
+
+//=============================================================================
+/**
+ * Binding to a UICDM object of Slide type
+ */
+class CSlideTimelineItemBinding : public CUICDMTimelineItemBinding
+{
+public:
+ CSlideTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ UICDM::CUICDMInstanceHandle inDataHandle);
+ ~CSlideTimelineItemBinding() {}
+
+ // CUICDMTimelineItemBinding
+ ITimelineTimebar *GetTimebar() override;
+ void SetName(const Q3DStudio::CString &inName) override;
+ void Bind(CBaseStateRow *inRow) override;
+ bool IsValidTransaction(EUserTransaction inTransaction) override;
+
+ // No properties
+ long GetPropertyCount() override { return 0; }
+ ITimelineItemProperty *GetProperty(long) override { return nullptr; }
+ void LoadProperties() override {}
+
+ // Eye/Lock toggles are not applicable
+ bool ShowToggleControls() const override { return false; }
+ bool IsLockedEnabled() const override { return false; }
+ bool IsVisibleEnabled() const override { return false; }
+
+ // Shy, Locked, Visible are not applicable
+ bool IsShy() const override { return false; }
+ void SetShy(bool) override {}
+ bool IsLocked() const override { return false; }
+ void SetLocked(bool) override {}
+ bool IsVisible() const override { return true; }
+ void SetVisible(bool) override {}
+
+ // Keyframes, not applicable to a Slide
+ void InsertKeyframe() override {}
+ void DeleteAllChannelKeyframes() override {}
+ long GetKeyframeCount() const override { return 0; }
+ IKeyframe *GetKeyframeByTime(long) const override { return nullptr; }
+ IKeyframe *GetKeyframeByIndex(long) const override { return nullptr; }
+ long OffsetSelectedKeyframes(long) override { return 0; }
+ void CommitChangedKeyframes() override {}
+ void OnEditKeyframeTime(long, long) override {}
+ // IKeyframeSelector
+ void SelectKeyframes(bool, long inTime = -1) override { Q_UNUSED(inTime); }
+
+ // Keyframe manipulation, not applicable
+ void UIRefreshPropertyKeyframe(long inOffset) override { Q_UNUSED(inOffset); }
+ bool HasDynamicKeyframes(long inTime) override
+ {
+ Q_UNUSED(inTime);
+ return false;
+ }
+ void SetDynamicKeyframes(long inTime, bool inDynamic) override
+ {
+ Q_UNUSED(inTime);
+ Q_UNUSED(inDynamic);
+ }
+ void DoSelectKeyframes(bool inSelected, long inTime, bool inUpdateUI) override
+ {
+ Q_UNUSED(inSelected);
+ Q_UNUSED(inTime);
+ Q_UNUSED(inUpdateUI);
+ }
+ void OnPropertySelection(long inTime) override { Q_UNUSED(inTime); }
+
+protected:
+ std::shared_ptr<UICDM::ISignalConnection>
+ m_Connection; // Callback when the Asset name changes
+
+ bool AmITimeParent() const override { return true; }
+};
+
+#endif // INCLUDED_SLIDE_TIMELINEITEM_BINDING_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.cpp
new file mode 100644
index 00000000..4bd1fc01
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.cpp
@@ -0,0 +1,239 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+#include "TimelineBreadCrumbProvider.h"
+#include "Core.h"
+
+// Link to data model
+#include "Doc.h"
+#include "StudioApp.h"
+#include "Cmd.h"
+#include "ResourceCache.h"
+#include "Strings.h"
+#include "StringLoader.h"
+#include "CColor.h"
+
+#include "ClientDataModelBridge.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMSlides.h"
+#include "CmdActivateSlide.h"
+
+using namespace UICDM;
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CTimelineBreadCrumbProvider::CTimelineBreadCrumbProvider(CDoc *inDoc)
+ : m_Doc(inDoc)
+{
+}
+
+//=============================================================================
+/**
+ */
+CTimelineBreadCrumbProvider::~CTimelineBreadCrumbProvider()
+{
+}
+
+//=============================================================================
+/**
+ * determine the color and text string for this breadcrumb
+ */
+static inline void FillBreadCrumb(SBreadCrumb &outBreadCrumb,
+ UICDM::CUICDMInstanceHandle inInstance, CDoc *inDoc)
+{
+ // Get the MasterSlide Handle associated with inAsset
+ CClientDataModelBridge *theBridge = inDoc->GetStudioSystem()->GetClientDataModelBridge();
+ ISlideSystem *theSlideSystem = inDoc->GetStudioSystem()->GetSlideSystem();
+ Q3DStudio::CId theId = theBridge->GetGUID(inInstance);
+ UICDM::CUICDMSlideHandle theMasterSlide =
+ theSlideSystem->GetMasterSlideByComponentGuid(GuidtoSLong4(theId));
+ ASSERT(theMasterSlide.Valid()); // it should be valid because inAsset should be OBJTYPE_SCENE or
+ // non-library OBJTYPE_COMPONENT
+
+ // Get the active slide index of the master slide. Master Slide always has index 0
+ long theActiveIndex = theSlideSystem->GetActiveSlideIndex(theMasterSlide);
+ bool theIsMaster = (theActiveIndex == 0);
+
+ // Determine the color
+ outBreadCrumb.m_Color =
+ theIsMaster ? CColor(0, 0, 255) : CColor(0, 0, 0); // blue for master, black otherwise
+
+ // Determine the text string
+ outBreadCrumb.m_String = theBridge->GetName(inInstance).toQString();
+ outBreadCrumb.m_String += " (";
+ if (theIsMaster)
+ outBreadCrumb.m_String += ::LoadResourceString(IDS_OBJTYPE_MASTER).toQString();
+ else {
+ CUICDMSlideHandle theActiveSlide =
+ theSlideSystem->GetSlideByIndex(theMasterSlide, theActiveIndex);
+ CUICDMInstanceHandle theInstanceHandle = theSlideSystem->GetSlideInstance(theActiveSlide);
+ ASSERT(theInstanceHandle.Valid());
+ outBreadCrumb.m_String += theBridge->GetName(theInstanceHandle).toQString();
+ }
+ outBreadCrumb.m_String += ")";
+}
+
+//=============================================================================
+/**
+ * return the trail of breadcrumb.
+ * This constructs a list of the "time context tree" from Scene down to the current active time
+ * context.
+ * @param inRefresh true to refresh the list, false to get existing.
+ */
+CTimelineBreadCrumbProvider::TTrailList
+CTimelineBreadCrumbProvider::GetTrail(bool inRefresh /*= true */)
+{
+ if (inRefresh)
+ RefreshSlideList();
+
+ TTrailList theList;
+ for (size_t theIndex = 0; theIndex < m_BreadCrumbList.size(); ++theIndex) {
+ SBreadCrumb theBreadCrumb;
+ FillBreadCrumb(theBreadCrumb, m_BreadCrumbList[theIndex], m_Doc);
+ theList.push_back(theBreadCrumb);
+ }
+ return theList;
+}
+
+//=============================================================================
+/**
+ * switch current time context to the one 'represented' by the breadcrumbs.
+ * @param inTrailIndex index into the trail list
+ */
+void CTimelineBreadCrumbProvider::OnBreadCrumbClicked(long inTrailIndex)
+{
+ if (inTrailIndex >= 0 && inTrailIndex < (long)m_BreadCrumbList.size()) {
+ CCmdActivateSlide *theCmd = new CCmdActivateSlide(m_Doc, m_BreadCrumbList[inTrailIndex]);
+ theCmd->SetForceRefresh(false);
+ m_Doc->GetCore()->ExecuteCommand(theCmd, false);
+ }
+}
+
+QPixmap CTimelineBreadCrumbProvider::GetRootImage() const
+{
+ return CResourceCache::GetInstance()->GetBitmap("breadcrumb_component_scene.png");
+}
+
+QPixmap CTimelineBreadCrumbProvider::GetBreadCrumbImage() const
+{
+ return CResourceCache::GetInstance()->GetBitmap("breadcrumb_component_button.png");
+}
+
+QPixmap CTimelineBreadCrumbProvider::GetSeparatorImage() const
+{
+ return CResourceCache::GetInstance()->GetBitmap("breadcrumb_component_colon_button.png");
+}
+
+QPixmap CTimelineBreadCrumbProvider::GetActiveBreadCrumbImage() const
+{
+ return CResourceCache::GetInstance()->GetBitmap("breadcrumb_component_grey_button.png");
+}
+
+//=============================================================================
+/**
+ * Called when active time context is changed.
+ */
+void CTimelineBreadCrumbProvider::RefreshSlideList()
+{
+ ClearSlideList();
+
+ UICDM::CUICDMInstanceHandle theActiveRoot = m_Doc->GetActiveRootInstance();
+ if (!theActiveRoot.Valid())
+ return;
+ FillSlideList(theActiveRoot);
+}
+
+//=============================================================================
+/**
+ * Callback that inAsset has its name changed, fire off a signal to the UI control.
+ * All the assets' signals are connected to this object and we'll let the UI control check iterate
+ * through the list for changes and refresh.
+ * Alternative we can set up additional classes that listens to specific assets and only the asset
+ * affected refreshed. the former is easier for now.
+ */
+void CTimelineBreadCrumbProvider::OnNameDirty()
+{
+ SigBreadCrumbUpdate();
+}
+
+void CTimelineBreadCrumbProvider::ClearSlideList()
+{
+ m_Connections.clear();
+ m_BreadCrumbList.clear();
+}
+
+//=============================================================================
+/**
+ * This will recurse up the time context tree, so that we can fill the list in a top-down (i.e
+ * Scene) first manner
+ */
+void CTimelineBreadCrumbProvider::FillSlideList(UICDM::CUICDMInstanceHandle inInstance)
+{
+ if (!inInstance.Valid())
+ return;
+
+ CClientDataModelBridge *theBridge = m_Doc->GetStudioSystem()->GetClientDataModelBridge();
+ ISlideSystem *theSlideSystem = m_Doc->GetStudioSystem()->GetSlideSystem();
+ Q3DStudio::CId theId = theBridge->GetGUID(inInstance);
+
+ // Recurse
+ FillSlideList(theBridge->GetParentComponent(inInstance));
+
+ m_BreadCrumbList.push_back(inInstance);
+
+ CUICDMPropertyHandle theNameProp =
+ m_Doc->GetStudioSystem()->GetClientDataModelBridge()->GetNameProperty();
+ IStudioFullSystemSignalProvider *theEngine =
+ m_Doc->GetStudioSystem()->GetFullSystemSignalProvider();
+ std::function<void(CUICDMInstanceHandle, CUICDMPropertyHandle)> theSetter(
+ std::bind(&CTimelineBreadCrumbProvider::OnNameDirty, this));
+
+ // Listen to name changes on the Asset
+ m_Connections.push_back(theEngine->ConnectInstancePropertyValue(
+ std::bind(UICDM::MaybackCallbackInstancePropertyValue<std::function<void(
+ CUICDMInstanceHandle, CUICDMPropertyHandle)>>,
+ std::placeholders::_1, std::placeholders::_2, inInstance, theNameProp, theSetter)));
+
+ // Listen to name changes on the non-master Slides
+ UICDM::CUICDMSlideHandle theMasterSlide =
+ theSlideSystem->GetMasterSlideByComponentGuid(GuidtoSLong4(theId));
+ long theSlideCount = (long)theSlideSystem->GetSlideCount(theMasterSlide);
+
+ for (long theIndex = 1; theIndex < theSlideCount; ++theIndex) {
+ CUICDMSlideHandle theSlide = theSlideSystem->GetSlideByIndex(theMasterSlide, theIndex);
+ CUICDMInstanceHandle theSlideInstance = theSlideSystem->GetSlideInstance(theSlide);
+ m_Connections.push_back(theEngine->ConnectInstancePropertyValue(
+ std::bind(UICDM::MaybackCallbackInstancePropertyValue<std::function<void(
+ CUICDMInstanceHandle, CUICDMPropertyHandle)>>,
+ std::placeholders::_1, std::placeholders::_2, theSlideInstance, theNameProp, theSetter)));
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.h
new file mode 100644
index 00000000..d71b57b9
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_BREADCRUMBPROVIDER_H
+#define INCLUDED_BREADCRUMBPROVIDER_H 1
+
+#pragma once
+
+#include "IBreadCrumbProvider.h"
+#include "UICDMSignals.h"
+
+// Link to data model
+class CDoc;
+class CTimelineBreadCrumbProvider;
+
+//=============================================================================
+/**
+ * Bread crumb provider for displaying a trail of time contexts
+ */
+class CTimelineBreadCrumbProvider : public IBreadCrumbProvider
+{
+public:
+ CTimelineBreadCrumbProvider(CDoc *inDoc);
+ virtual ~CTimelineBreadCrumbProvider();
+
+ TTrailList GetTrail(bool inRefresh = true) override;
+ void OnBreadCrumbClicked(long inTrailIndex) override;
+
+ QPixmap GetRootImage() const override;
+ QPixmap GetBreadCrumbImage() const override;
+ QPixmap GetSeparatorImage() const override;
+ QPixmap GetActiveBreadCrumbImage() const override;
+
+ void RefreshSlideList();
+ void OnNameDirty();
+
+protected:
+ void ClearSlideList();
+ void FillSlideList(UICDM::CUICDMInstanceHandle inInstance);
+
+protected:
+ std::vector<UICDM::CUICDMInstanceHandle> m_BreadCrumbList;
+ CDoc *m_Doc;
+ std::vector<std::shared_ptr<UICDM::ISignalConnection>>
+ m_Connections; /// connections to the UICDM
+};
+
+#endif // INCLUDED_BREADCRUMBPROVIDER_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.cpp
new file mode 100644
index 00000000..cc28b0cc
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.cpp
@@ -0,0 +1,599 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "TimelineTranslationManager.h"
+#include "SlideTimelineItemBinding.h"
+#include "GroupTimelineItemBinding.h"
+#include "BehaviorTimelineItemBinding.h"
+#include "MaterialTimelineItemBinding.h"
+#include "ImageTimelineItemBinding.h"
+#include "PathAnchorPointTimelineItemBinding.h"
+#include "PathTimelineItemBinding.h"
+#include "LayerTimelineItemBinding.h"
+#include "KeyframesManager.h"
+#include "TimelineBreadCrumbProvider.h"
+#include "BaseStateRow.h"
+#include "PropertyRow.h"
+#include "IDoc.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMSlides.h"
+#include "UICDMSignals.h"
+
+// Link to Data model
+#include "ClientDataModelBridge.h"
+#include "UICDMDataCore.h"
+#include "Doc.h" //Because we need to access Client Data Model Bridge
+#include "StudioApp.h"
+#include "Core.h"
+
+using namespace UICDM;
+
+CTimelineTranslationManager::CTimelineTranslationManager()
+{
+ m_KeyframesManager = new CKeyframesManager(this);
+ m_BreadCrumbProvider = new CTimelineBreadCrumbProvider(g_StudioApp.GetCore()->GetDoc());
+}
+
+CTimelineTranslationManager::~CTimelineTranslationManager()
+{
+ // clean up all bindings
+ Clear();
+ m_Connections.clear();
+ delete m_KeyframesManager;
+ delete m_BreadCrumbProvider;
+}
+
+ITimelineItemBinding *CTimelineTranslationManager::GetOrCreate(CUICDMInstanceHandle inInstance)
+{
+ ITimelineItemBinding *theBinding = GetBinding(inInstance);
+ if (!theBinding) {
+ CUICDMTimelineItemBinding *theReturn = nullptr;
+ UICDM::IPropertySystem *thePropertySystem = GetStudioSystem()->GetPropertySystem();
+ CUICDMPropertyHandle theTypeProperty =
+ thePropertySystem->GetAggregateInstancePropertyByName(inInstance, L"type");
+
+ SValue theTypeValue;
+ thePropertySystem->GetInstancePropertyValue(inInstance, theTypeProperty, theTypeValue);
+
+ std::wstring theWideTypeString(UICDM::get<TDataStrPtr>(theTypeValue)->GetData());
+
+ if (theWideTypeString == L"Material" || theWideTypeString == L"CustomMaterial"
+ || theWideTypeString == L"ReferencedMaterial")
+ theReturn = new CMaterialTimelineItemBinding(this, inInstance);
+ else if (theWideTypeString == L"Image")
+ theReturn = new CImageTimelineItemBinding(this, inInstance);
+ else if (theWideTypeString == L"Group" || theWideTypeString == L"Component")
+ theReturn = new CGroupTimelineItemBinding(this, inInstance);
+ else if (theWideTypeString == L"Behavior")
+ theReturn = new CBehaviorTimelineItemBinding(this, inInstance);
+ else if (theWideTypeString == L"Slide")
+ theReturn = new CSlideTimelineItemBinding(this, inInstance);
+ else if (theWideTypeString == L"PathAnchorPoint")
+ theReturn = new CPathAnchorPointTimelineItemBinding(this, inInstance);
+ else if (theWideTypeString == L"Path")
+ theReturn = new CPathTimelineItemBinding(this, inInstance);
+ else if (theWideTypeString == L"Layer")
+ theReturn = new CLayerTimelineItemBinding(this, inInstance);
+ else if (theWideTypeString == L"Model" || theWideTypeString == L"Text"
+ || theWideTypeString == L"Camera" || theWideTypeString == L"Effect"
+ || theWideTypeString == L"Light" || theWideTypeString == L"RenderPlugin"
+ || theWideTypeString == L"Alias" || theWideTypeString == L"SubPath")
+ theReturn = new CUICDMTimelineItemBinding(this, inInstance);
+ else {
+ // Add support for additional UICDM types here.
+ ASSERT(0);
+ }
+
+ m_InstanceHandleBindingMap.insert(
+ std::make_pair(theReturn->GetInstanceHandle(), theReturn));
+ m_InstanceHandleExpandedMap.insert(std::make_pair(theReturn->GetInstanceHandle(), false));
+ theBinding = theReturn;
+ }
+
+ return theBinding;
+}
+
+//==============================================================================
+/**
+ * Create a new CPropertyRow that maps to this ITimelineItemProperty.
+ * The caller is assumed to have ensured that this is only called once per property binding.
+ */
+void CTimelineTranslationManager::CreateNewPropertyRow(
+ ITimelineItemProperty *inTimelineItemPropertyBinding, CBaseStateRow *inParentRow,
+ CPropertyRow *inNextRow)
+{
+ if (!inParentRow || !inTimelineItemPropertyBinding)
+ return;
+
+ CPropertyRow *theNewRow = new CPropertyRow(inTimelineItemPropertyBinding);
+ inParentRow->AddPropertyRow(theNewRow, inNextRow);
+ inTimelineItemPropertyBinding->Bind(theNewRow);
+}
+
+//==============================================================================
+/**
+ * Does the reverse of CreateNewPropertyRow, when a property has been de-animated.
+ */
+void CTimelineTranslationManager::RemovePropertyRow(
+ ITimelineItemProperty *inTimelineItemPropertyBinding)
+{
+ CPropertyRow *theRow = nullptr;
+ if (!inTimelineItemPropertyBinding
+ || (theRow = inTimelineItemPropertyBinding->GetRow()) == nullptr)
+ return;
+
+ CBaseStateRow *theParentRow = theRow->GetParentRow();
+ if (theParentRow) {
+ inTimelineItemPropertyBinding->Release();
+ theParentRow->RemovePropertyRow(theRow); // this implicitly delete the row
+ }
+}
+
+//==============================================================================
+/**
+ * Clear all bindings, typically when a presentation is closed.
+ */
+void CTimelineTranslationManager::Clear()
+{
+ // clean up all bindings
+ m_InstanceHandleBindingMap.clear();
+}
+
+//==============================================================================
+/**
+ * Called when the associated UI is no longer valid.
+ */
+void CTimelineTranslationManager::Unregister(ITimelineItemBinding *inTimelineItem)
+{
+ // UICDM
+ bool theDeselectItem = false;
+ TInstanceHandleBindingMap::iterator theInstanceIter = m_InstanceHandleBindingMap.begin();
+ for (; theInstanceIter != m_InstanceHandleBindingMap.end(); ++theInstanceIter) {
+ if (theInstanceIter->second == inTimelineItem) {
+ // If this is the currently selected object and make sure that is cleared.
+ UICDM::CUICDMInstanceHandle theSelectedInstance =
+ g_StudioApp.GetCore()->GetDoc()->GetSelectedInstance();
+ if (theSelectedInstance.Valid() && theSelectedInstance == theInstanceIter->first)
+ theDeselectItem = true;
+
+ m_InstanceHandleBindingMap.erase(theInstanceIter);
+ break;
+ }
+ }
+
+ delete inTimelineItem;
+}
+
+CKeyframesManager *CTimelineTranslationManager::GetKeyframesManager() const
+{
+ return m_KeyframesManager;
+}
+
+IBreadCrumbProvider *CTimelineTranslationManager::GetBreadCrumbProvider() const
+{
+ return m_BreadCrumbProvider;
+}
+
+CBaseStateRow *CTimelineTranslationManager::GetSelectedRow() const
+{
+ ITimelineItemBinding *theBinding = GetSelectedBinding();
+ if (theBinding)
+ return theBinding->GetRow();
+ return nullptr;
+}
+
+long CTimelineTranslationManager::GetCurrentViewTime() const
+{
+ return g_StudioApp.GetCore()->GetDoc()->GetCurrentViewTime();
+}
+
+//==============================================================================
+/**
+ * @return the Binding object that corresponds to this instance.
+ */
+CUICDMTimelineItemBinding *
+CTimelineTranslationManager::GetBinding(CUICDMInstanceHandle inHandle) const
+{
+ TInstanceHandleBindingMap::const_iterator theIter = m_InstanceHandleBindingMap.find(inHandle);
+ if (theIter != m_InstanceHandleBindingMap.end())
+ return theIter->second;
+ return nullptr;
+}
+
+CUICDMTimelineItemBinding *CTimelineTranslationManager::GetSelectedBinding() const
+{
+ UICDM::CUICDMInstanceHandle theSelectedInstance =
+ g_StudioApp.GetCore()->GetDoc()->GetSelectedInstance();
+ if (theSelectedInstance.Valid()) {
+ CUICDMTimelineItemBinding *theBinding = GetBinding(theSelectedInstance);
+ return theBinding;
+ }
+ return nullptr;
+}
+
+//==============================================================================
+/**
+ * Triggered from individual binding classes, to clear all keyframe selection
+ */
+void CTimelineTranslationManager::ClearKeyframeSelection()
+{
+ m_KeyframesManager->DeselectAllKeyframes();
+}
+
+//==============================================================================
+/**
+ * Set up callbacks for animation changes
+ */
+void CTimelineTranslationManager::OnNewPresentation()
+{
+ m_Connections.clear();
+ m_InstanceHandleExpandedMap.clear();
+
+ IStudioFullSystemSignalProvider *theSignalProvider =
+ g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetFullSystemSignalProvider();
+ m_Connections.push_back(theSignalProvider->ConnectAnimationCreated(
+ std::bind(&CTimelineTranslationManager::OnAnimationCreated, this,
+ std::placeholders::_2, std::placeholders::_3)));
+ m_Connections.push_back(theSignalProvider->ConnectAnimationDeleted(
+ std::bind(&CTimelineTranslationManager::OnAnimationDeleted, this,
+ std::placeholders::_2, std::placeholders::_3)));
+ m_Connections.push_back(theSignalProvider->ConnectPropertyLinked(
+ std::bind(&CTimelineTranslationManager::OnPropertyLinked, this,
+ std::placeholders::_2, std::placeholders::_3)));
+ m_Connections.push_back(theSignalProvider->ConnectPropertyUnlinked(
+ std::bind(&CTimelineTranslationManager::OnPropertyUnlinked, this,
+ std::placeholders::_2, std::placeholders::_3)));
+ m_Connections.push_back(theSignalProvider->ConnectKeyframeInserted(
+ std::bind(&CTimelineTranslationManager::OnKeyframeInserted, this,
+ std::placeholders::_1, std::placeholders::_2)));
+ m_Connections.push_back(theSignalProvider->ConnectKeyframeErased(
+ std::bind(&CTimelineTranslationManager::OnKeyframeDeleted, this,
+ std::placeholders::_1, std::placeholders::_2)));
+ m_Connections.push_back(theSignalProvider->ConnectKeyframeUpdated(
+ std::bind(&CTimelineTranslationManager::OnKeyframeUpdated, this, std::placeholders::_1)));
+ m_Connections.push_back(theSignalProvider->ConnectInstancePropertyValue(
+ std::bind(&CTimelineTranslationManager::OnPropertyChanged, this,
+ std::placeholders::_1, std::placeholders::_2)));
+ m_Connections.push_back(theSignalProvider->ConnectFirstKeyframeDynamicSet(
+ std::bind(&CTimelineTranslationManager::OnDynamicKeyframeChanged, this,
+ std::placeholders::_1, std::placeholders::_2)));
+
+ m_Connections.push_back(theSignalProvider->ConnectInstanceCreated(
+ std::bind(&CTimelineTranslationManager::OnAssetCreated, this, std::placeholders::_1)));
+ m_Connections.push_back(theSignalProvider->ConnectInstanceDeleted(
+ std::bind(&CTimelineTranslationManager::OnAssetDeleted, this, std::placeholders::_1)));
+
+ m_Connections.push_back(theSignalProvider->ConnectActionCreated(
+ std::bind(&CTimelineTranslationManager::OnActionEvent, this,
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)));
+ m_Connections.push_back(theSignalProvider->ConnectActionDeleted(
+ std::bind(&CTimelineTranslationManager::OnActionEvent, this,
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)));
+
+ Q3DStudio::CGraph &theGraph(*g_StudioApp.GetCore()->GetDoc()->GetAssetGraph());
+ m_Connections.push_back(theGraph.ConnectChildAdded(
+ std::bind(&CTimelineTranslationManager::OnChildAdded, this,
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)));
+ m_Connections.push_back(theGraph.ConnectChildRemoved(
+ std::bind(&CTimelineTranslationManager::OnChildRemoved, this,
+ std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)));
+ m_Connections.push_back(theGraph.ConnectChildMoved(
+ std::bind(&CTimelineTranslationManager::OnChildMoved, this, std::placeholders::_1,
+ std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)));
+}
+
+//==============================================================================
+/**
+ * Selection events on the old data model was triggered via signals on the actual objects.
+ * For the new data model, it would be via this OnSelectionChange event.
+ */
+void CTimelineTranslationManager::OnSelectionChange(Q3DStudio::SSelectedValue inNewSelectable)
+{
+ // Deselect all items
+ TInstanceHandleBindingMap::const_iterator theIter = m_InstanceHandleBindingMap.begin();
+ for (; theIter != m_InstanceHandleBindingMap.end(); ++theIter) {
+ ITimelineItemBinding *theBinding = theIter->second;
+ CBaseStateRow *theRow = theBinding->GetRow();
+ if (theRow)
+ theRow->OnSelected(false);
+ }
+
+ // Select new
+ if (inNewSelectable)
+ SetSelected(inNewSelectable, true);
+}
+
+CDoc *CTimelineTranslationManager::GetDoc() const
+{
+ return dynamic_cast<CDoc *>(g_StudioApp.GetCore()->GetDoc());
+}
+
+CStudioSystem *CTimelineTranslationManager::GetStudioSystem() const
+{
+ // TODO: figure if we can just deal with IDoc instead of CDoc
+ return g_StudioApp.GetCore()->GetDoc()->GetStudioSystem();
+}
+
+void CTimelineTranslationManager::OnAnimationCreated(CUICDMInstanceHandle inInstance,
+ CUICDMPropertyHandle inProperty)
+{
+ CUICDMTimelineItemBinding *theTimelineBinding =
+ dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(inInstance));
+ if (theTimelineBinding)
+ theTimelineBinding->AddPropertyRow(inProperty);
+}
+
+void CTimelineTranslationManager::OnAnimationDeleted(CUICDMInstanceHandle inInstance,
+ CUICDMPropertyHandle inProperty)
+{
+ CUICDMTimelineItemBinding *theTimelineBinding =
+ dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(inInstance));
+ if (theTimelineBinding)
+ theTimelineBinding->RemovePropertyRow(inProperty);
+}
+
+void CTimelineTranslationManager::OnPropertyLinked(CUICDMInstanceHandle inInstance,
+ CUICDMPropertyHandle inProperty)
+{
+ CUICDMTimelineItemBinding *theTimelineBinding =
+ dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(inInstance));
+ if (theTimelineBinding)
+ theTimelineBinding->OnPropertyLinked(inProperty);
+}
+
+void CTimelineTranslationManager::OnPropertyUnlinked(CUICDMInstanceHandle inInstance,
+ CUICDMPropertyHandle inProperty)
+{
+ OnPropertyLinked(inInstance, inProperty);
+}
+
+void CTimelineTranslationManager::RefreshKeyframe(CUICDMAnimationHandle inAnimation,
+ CUICDMKeyframeHandle inKeyframe,
+ ETimelineKeyframeTransaction inTransaction)
+{
+ CUICDMTimelineItemBinding *theTimelineBinding = nullptr;
+ if (GetStudioSystem()->GetAnimationCore()->AnimationValid(inAnimation)) {
+ SAnimationInfo theAnimationInfo =
+ GetStudioSystem()->GetAnimationCore()->GetAnimationInfo(inAnimation);
+ theTimelineBinding =
+ dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(theAnimationInfo.m_Instance));
+
+ if (theTimelineBinding)
+ theTimelineBinding->RefreshPropertyKeyframe(theAnimationInfo.m_Property, inKeyframe,
+ inTransaction);
+ }
+ // else, animation has been nuked, ignore this event, we'll get a AnimationDelete
+}
+
+void CTimelineTranslationManager::OnKeyframeInserted(CUICDMAnimationHandle inAnimation,
+ CUICDMKeyframeHandle inKeyframe)
+{
+ RefreshKeyframe(inAnimation, inKeyframe, ETimelineKeyframeTransaction_Add);
+}
+
+void CTimelineTranslationManager::OnKeyframeDeleted(CUICDMAnimationHandle inAnimation,
+ CUICDMKeyframeHandle inKeyframe)
+{
+ RefreshKeyframe(inAnimation, inKeyframe, ETimelineKeyframeTransaction_Delete);
+}
+
+void CTimelineTranslationManager::OnKeyframeUpdated(CUICDMKeyframeHandle inKeyframe)
+{
+ IAnimationCore *theAnimationCore = GetStudioSystem()->GetAnimationCore();
+ if (theAnimationCore->KeyframeValid(inKeyframe)) {
+ CUICDMAnimationHandle theAnimationHandle =
+ theAnimationCore->GetAnimationForKeyframe(inKeyframe);
+ RefreshKeyframe(theAnimationHandle, inKeyframe, ETimelineKeyframeTransaction_Update);
+ }
+ // else, keyframe has been nuked, ignore this event, we'll get a KeyframeDeleted
+}
+
+void CTimelineTranslationManager::OnPropertyChanged(UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMPropertyHandle inProperty)
+{
+ CUICDMTimelineItemBinding *theTimelineBinding =
+ dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(inInstance));
+ if (theTimelineBinding)
+ theTimelineBinding->OnPropertyChanged(inProperty);
+}
+
+void CTimelineTranslationManager::OnDynamicKeyframeChanged(UICDM::CUICDMAnimationHandle inAnimation,
+ bool inDynamic)
+{
+ Q_UNUSED(inDynamic);
+
+ CUICDMTimelineItemBinding *theTimelineBinding = nullptr;
+ if (GetStudioSystem()->GetAnimationCore()->AnimationValid(inAnimation)) {
+ SAnimationInfo theAnimationInfo =
+ GetStudioSystem()->GetAnimationCore()->GetAnimationInfo(inAnimation);
+ theTimelineBinding =
+ dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(theAnimationInfo.m_Instance));
+ if (theTimelineBinding)
+ theTimelineBinding->RefreshPropertyKeyframe(
+ theAnimationInfo.m_Property, 0, ETimelineKeyframeTransaction_DynamicChanged);
+ }
+}
+
+void CTimelineTranslationManager::OnAssetCreated(UICDM::CUICDMInstanceHandle inInstance)
+{
+ CClientDataModelBridge *theDataModelBridge = GetStudioSystem()->GetClientDataModelBridge();
+
+ if (theDataModelBridge->IsSceneGraphInstance(inInstance))
+ EnsureLoaded(inInstance);
+}
+
+void CTimelineTranslationManager::OnAssetDeleted(UICDM::CUICDMInstanceHandle inInstance)
+{
+ // You can't assume the instance is valid. Someone may have deleted a large number of items
+ // from the model and then decided to send notifications after the fact.
+ // if the created asset is library asset, do nothing
+ // start to add the scene asset to the timeline
+ CUICDMTimelineItemBinding *theItemBinding =
+ dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(inInstance));
+ if (theItemBinding) {
+ CUICDMTimelineItemBinding *theParentBinding =
+ dynamic_cast<CUICDMTimelineItemBinding *>(theItemBinding->GetParent());
+ if (theParentBinding)
+ theParentBinding->OnDeleteChild(inInstance);
+ }
+}
+
+void CTimelineTranslationManager::OnChildAdded(int /*inParent*/, int inChild, long /*inIndex*/)
+{
+ OnAssetCreated(inChild);
+}
+void CTimelineTranslationManager::OnChildRemoved(int /*inParent*/, int inChild, long /*inIndex*/)
+{
+ OnAssetDeleted(inChild);
+}
+void CTimelineTranslationManager::OnChildMoved(int /*inParent*/, int inChild, long /*inOldIndex*/,
+ long /*inNewIndex*/)
+{
+ OnAssetDeleted(inChild);
+ OnAssetCreated(inChild);
+}
+
+//==============================================================================
+/**
+ * Callback method whenever an action is either created or removed.
+ * Basically, it tells the owner of the action to update its timeline control to
+ * update the icon that shows action association status
+ */
+void CTimelineTranslationManager::OnActionEvent(UICDM::CUICDMActionHandle inAction,
+ UICDM::CUICDMSlideHandle inSlide,
+ UICDM::CUICDMInstanceHandle inOwner)
+{
+ Q_UNUSED(inAction);
+
+ // the slide that action is added to is the current slide or
+ // is added to the master slide of the current slide
+ CUICDMTimelineItemBinding *theTimelineBinding =
+ dynamic_cast<CUICDMTimelineItemBinding *>(GetBinding(inOwner));
+ if (theTimelineBinding)
+ theTimelineBinding->UpdateActionStatus();
+}
+
+//==============================================================================
+/**
+ * Helper functions to go through ALL binding and clear any keyframes selection.
+ */
+void CTimelineTranslationManager::ClearBindingsKeyframeSelection()
+{
+ // UICDM bindings handle their own selections
+ TInstanceHandleBindingMap::const_iterator theIter = m_InstanceHandleBindingMap.begin();
+ for (; theIter != m_InstanceHandleBindingMap.end(); ++theIter)
+ theIter->second->DoSelectKeyframes(false, -1, true);
+}
+
+//==============================================================================
+/**
+ * Helper function to find the binding that corresponds to inSelectable and set its selection state
+ */
+void CTimelineTranslationManager::SetSelected(Q3DStudio::SSelectedValue inSelectable,
+ bool inSelected)
+{
+ UICDM::TInstanceHandleList theInstances = inSelectable.GetSelectedInstances();
+ for (size_t idx = 0, end = theInstances.size(); idx < end; ++idx) {
+ CUICDMInstanceHandle theInstance(theInstances[idx]);
+ if (GetStudioSystem()->IsInstance(theInstance)) {
+ ITimelineItemBinding *theBinding = EnsureLoaded(theInstance);
+ if (theBinding) {
+ CBaseStateRow *theRow = theBinding->GetRow();
+ if (theRow)
+ theRow->OnSelected(inSelected);
+ }
+ }
+ }
+}
+
+ITimelineItemBinding *CTimelineTranslationManager::EnsureLoaded(CUICDMInstanceHandle inHandle)
+{
+ ITimelineItemBinding *theBinding = GetBinding(inHandle);
+ bool rowLoaded = theBinding != nullptr && theBinding->GetRow() != nullptr;
+ if (rowLoaded == false) {
+ // tell my parent to load me
+ CClientDataModelBridge *theDataModelBridge = GetStudioSystem()->GetClientDataModelBridge();
+ CUICDMInstanceHandle theParent = theDataModelBridge->GetParentInstance(inHandle);
+ if (theParent.Valid()) {
+ ITimelineItemBinding *theParentBinding = EnsureLoaded(theParent);
+ if (theParentBinding)
+ theParentBinding->GetRow()->LoadChildren();
+
+ // The LoadChildren has an optimzation such that if it's already loaded, it won't
+ // recreate again
+ // So, if we still can't get the binding after LoadChildren, it very likely means that
+ // this is newly added
+ // so call OnAddChild to let it just add this.
+ theBinding = GetBinding(inHandle);
+ bool rowLoaded = theBinding != nullptr && theBinding->GetRow() != nullptr;
+ if (theParentBinding && rowLoaded == false) {
+ // start to add the scene asset to the timeline
+ CUICDMTimelineItemBinding *theUICDMBinding =
+ dynamic_cast<CUICDMTimelineItemBinding *>(theParentBinding);
+ theUICDMBinding->OnAddChild(inHandle);
+ theBinding = GetBinding(inHandle);
+ }
+ }
+ }
+ return theBinding;
+}
+
+//==============================================================================
+/**
+ * remember the expanded state for the current presentation
+ */
+bool CTimelineTranslationManager::IsExpanded(CUICDMInstanceHandle inInstance) const
+{
+ TInstanceHandleExpandedMap::const_iterator theIter =
+ m_InstanceHandleExpandedMap.find(inInstance);
+ if (theIter != m_InstanceHandleExpandedMap.end()) {
+ return theIter->second;
+ }
+ return false;
+}
+
+//==============================================================================
+/**
+ * remember the expanded state for the current presentation
+ */
+void CTimelineTranslationManager::SetExpanded(CUICDMInstanceHandle inInstance, bool inExpanded)
+{
+ TInstanceHandleExpandedMap::iterator theIter = m_InstanceHandleExpandedMap.find(inInstance);
+ if (theIter != m_InstanceHandleExpandedMap.end()) {
+ theIter->second = inExpanded;
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.h
new file mode 100644
index 00000000..48f7bebe
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.h
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_TIMELINE_TRANSLATIONMANAGER_H
+#define INCLUDED_TIMELINE_TRANSLATIONMANAGER_H 1
+
+#pragma once
+
+#include "UICDMHandles.h"
+#include "UICDMTimeline.h"
+
+#include "Doc.h"
+
+//==============================================================================
+// Classes
+//==============================================================================
+class ITimelineItemBinding;
+class ITimelineItemProperty;
+class CUICDMTimelineItemBinding;
+class CBaseStateRow;
+class CPropertyRow;
+class CKeyframesManager;
+class IBreadCrumbProvider;
+
+// Link to data model
+class CAsset;
+class IUICDMSelectable;
+class CClientDataModelBridge;
+
+// UICDM
+namespace UICDM {
+class CStudioSystem;
+class ISignalConnection;
+}
+
+class CDoc;
+
+//=============================================================================
+/**
+ * There is a TranslationManager per presentation (project)
+ */
+class CTimelineTranslationManager
+{
+protected: // Typedefs
+ // UICDM support
+ typedef std::map<UICDM::CUICDMInstanceHandle, CUICDMTimelineItemBinding *>
+ TInstanceHandleBindingMap;
+
+ // Store expanded state
+ typedef std::map<UICDM::CUICDMInstanceHandle, bool> TInstanceHandleExpandedMap; // UICDM support
+
+protected: // Properties
+ // UICDM support
+ TInstanceHandleBindingMap m_InstanceHandleBindingMap;
+
+ CKeyframesManager *m_KeyframesManager;
+ IBreadCrumbProvider *m_BreadCrumbProvider;
+ std::vector<std::shared_ptr<UICDM::ISignalConnection>>
+ m_Connections; /// connections to the UICDM
+
+ TInstanceHandleExpandedMap m_InstanceHandleExpandedMap;
+
+public:
+ CTimelineTranslationManager();
+ ~CTimelineTranslationManager();
+
+public:
+ ITimelineItemBinding *GetOrCreate(UICDM::CUICDMInstanceHandle inInstance);
+ void CreateNewPropertyRow(ITimelineItemProperty *inTimelineItemPropertyBinding,
+ CBaseStateRow *inParentRow, CPropertyRow *inNextRow);
+ void RemovePropertyRow(ITimelineItemProperty *inTimelineItemPropertyBinding);
+
+ void Clear();
+ void Unregister(ITimelineItemBinding *inTimelineItem);
+
+ CKeyframesManager *GetKeyframesManager() const;
+ IBreadCrumbProvider *GetBreadCrumbProvider() const;
+ CBaseStateRow *GetSelectedRow() const;
+ long GetCurrentViewTime() const;
+ CUICDMTimelineItemBinding *GetBinding(UICDM::CUICDMInstanceHandle inHandle) const;
+ CUICDMTimelineItemBinding *GetSelectedBinding() const;
+
+ void ClearKeyframeSelection();
+ void OnNewPresentation();
+ void OnSelectionChange(Q3DStudio::SSelectedValue inNewSelectable);
+
+ UICDM::CStudioSystem *GetStudioSystem() const;
+
+ // UICDM callback
+ void OnAnimationCreated(UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMPropertyHandle inProperty);
+ void OnAnimationDeleted(UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMPropertyHandle inProperty);
+ void OnPropertyLinked(UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMPropertyHandle inProperty);
+ void OnPropertyUnlinked(UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMPropertyHandle inProperty);
+ void RefreshKeyframe(UICDM::CUICDMAnimationHandle inAnimation,
+ UICDM::CUICDMKeyframeHandle inKeyframe,
+ ETimelineKeyframeTransaction inTransaction);
+ void OnKeyframeInserted(UICDM::CUICDMAnimationHandle inAnimation,
+ UICDM::CUICDMKeyframeHandle inKeyframe);
+ void OnKeyframeDeleted(UICDM::CUICDMAnimationHandle inAnimation,
+ UICDM::CUICDMKeyframeHandle inKeyframe);
+ void OnKeyframeUpdated(UICDM::CUICDMKeyframeHandle inKeyframe);
+ void OnPropertyChanged(UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMPropertyHandle inProperty);
+ void OnDynamicKeyframeChanged(UICDM::CUICDMAnimationHandle inAnimation, bool inDynamic);
+
+ void OnAssetCreated(UICDM::CUICDMInstanceHandle inInstance);
+ void OnAssetDeleted(UICDM::CUICDMInstanceHandle inInstance);
+ void OnChildAdded(int inParent, int inChild, long inIndex);
+ void OnChildRemoved(int inParent, int inChild, long inIndex);
+ void OnChildMoved(int inParent, int inChild, long inOldIndex, long inNewIndex);
+
+ void OnActionEvent(UICDM::CUICDMActionHandle inAction, UICDM::CUICDMSlideHandle inSlide,
+ UICDM::CUICDMInstanceHandle inOwner);
+
+ // Helper function to iterate over all bindings
+ void ClearBindingsKeyframeSelection();
+ CDoc *GetDoc() const;
+
+ // Store expanded state
+ bool IsExpanded(UICDM::CUICDMInstanceHandle inInstance) const;
+ void SetExpanded(UICDM::CUICDMInstanceHandle inInstance, bool inExpanded);
+
+protected:
+ void SetSelected(Q3DStudio::SSelectedValue inSelectable, bool inSelected);
+ ITimelineItemBinding *EnsureLoaded(UICDM::CUICDMInstanceHandle inHandle);
+};
+
+#endif // INCLUDED_TIMELINE_TRANSLATIONMANAGER_H \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.cpp
new file mode 100644
index 00000000..4eb0f906
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+#include "UICDMAssetTimelineKeyframe.h"
+#include "UICDMTimelineItemBinding.h"
+
+using namespace UICDM;
+
+CUICDMAssetTimelineKeyframe::CUICDMAssetTimelineKeyframe(CUICDMTimelineItemBinding *inOwningBinding,
+ long inTime)
+ : m_OwningBinding(inOwningBinding)
+ , m_Time(inTime)
+ , m_Selected(false)
+{
+}
+
+CUICDMAssetTimelineKeyframe::~CUICDMAssetTimelineKeyframe()
+{
+}
+
+bool CUICDMAssetTimelineKeyframe::IsSelected() const
+{
+ return m_Selected;
+}
+
+long CUICDMAssetTimelineKeyframe::GetTime() const
+{
+ return m_Time;
+}
+
+void CUICDMAssetTimelineKeyframe::SetTime(const long inNewTime)
+{
+ Q_UNUSED(inNewTime);
+ // note: this is not used. because setting time is currently only done through offsetting by
+ // moving keyframes OR using the edit time dialog.
+ ASSERT(0);
+}
+
+void CUICDMAssetTimelineKeyframe::SetDynamic(bool inIsDynamic)
+{
+ m_OwningBinding->SetDynamicKeyframes(m_Time, inIsDynamic);
+}
+
+bool CUICDMAssetTimelineKeyframe::IsDynamic() const
+{
+ // return true if any of its property keyframes is dynamic
+ return m_OwningBinding->HasDynamicKeyframes(m_Time);
+}
+
+void CUICDMAssetTimelineKeyframe::SetSelected(bool inSelected)
+{
+ m_Selected = inSelected;
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.h
new file mode 100644
index 00000000..e8cf6870
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef INCLUDED_UICDMASSETKEYFRAME_H
+#define INCLUDED_UICDMASSETKEYFRAME_H 1
+
+#pragma once
+
+#include "IKeyframe.h"
+
+// Data model specific
+#include "UICDMHandles.h"
+
+class CUICDMTimelineItemBinding;
+
+//==============================================================================
+/**
+ * Represents a keyframe displayed for a Asset( e.g. material ), for all keyframes (of the
+ *animated properties) at time t.
+ */
+//==============================================================================
+class CUICDMAssetTimelineKeyframe : public IKeyframe
+{
+protected:
+ CUICDMTimelineItemBinding *m_OwningBinding;
+ long m_Time;
+ bool m_Selected;
+
+public:
+ CUICDMAssetTimelineKeyframe(CUICDMTimelineItemBinding *inOwningBinding, long inTime);
+ virtual ~CUICDMAssetTimelineKeyframe();
+
+ // IKeyframe
+ bool IsSelected() const override;
+ long GetTime() const override;
+ void SetTime(const long inNewTime) override;
+ void SetDynamic(bool inIsDynamic) override;
+ bool IsDynamic() const override;
+
+ void SetSelected(bool inSelected);
+ void UpdateTime(const long inTime) { m_Time = inTime; }
+};
+
+#endif // INCLUDED_UICDMKEYFRAME_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimeline.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimeline.h
new file mode 100644
index 00000000..7989956f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimeline.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_UICDMTIMELINE_H
+#define INCLUDED_UICDMTIMELINE_H 1
+
+#pragma once
+
+enum ETimelineKeyframeTransaction {
+ ETimelineKeyframeTransaction_Add,
+ ETimelineKeyframeTransaction_Delete,
+ ETimelineKeyframeTransaction_Update,
+ ETimelineKeyframeTransaction_DynamicChanged,
+};
+
+#endif
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.cpp
new file mode 100644
index 00000000..b6dd94d9
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.cpp
@@ -0,0 +1,1260 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "UICDMTimelineItemBinding.h"
+#include "TimelineTranslationManager.h"
+#include "TimeEditDlg.h"
+#include "EmptyTimelineTimebar.h"
+#include "UICDMTimelineTimebar.h"
+#include "BaseStateRow.h"
+#include "BaseTimebarlessRow.h"
+#include "PropertyTimebarRow.h"
+#include "PropertyRow.h"
+#include "KeyframesManager.h"
+#include "StudioApp.h"
+#include "Core.h"
+#include "Dialogs.h"
+#include "GraphUtils.h"
+#include "UICDMDataCore.h"
+#include "Strings.h"
+#include "StringLoader.h"
+
+// Data model specific
+#include "IDoc.h"
+#include "ClientDataModelBridge.h"
+#include "Dispatch.h"
+#include "DropSource.h"
+#include "UICDMTimelineItemProperty.h"
+#include "UICDMSlides.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMSlideGraphCore.h"
+#include "UICDMActionCore.h"
+#include "UICDMAnimation.h"
+#include "CmdDataModelChangeKeyframe.h"
+#include "RelativePathTools.h"
+#include "IDocumentEditor.h"
+#include "UICFileTools.h"
+#include "ImportUtils.h"
+
+#include <QMessageBox>
+
+using namespace UICDM;
+
+CUICDMTimelineItemBinding::CUICDMTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ CUICDMInstanceHandle inDataHandle)
+ : m_Row(nullptr)
+ , m_TransMgr(inMgr)
+ , m_DataHandle(inDataHandle)
+ , m_Parent(nullptr)
+ , m_TimelineTimebar(nullptr)
+
+{
+ m_StudioSystem = m_TransMgr->GetStudioSystem();
+ m_TransMgr->GetDoc()->GetCore()->GetDispatch()->AddDataModelListener(this);
+}
+
+CUICDMTimelineItemBinding::CUICDMTimelineItemBinding(CTimelineTranslationManager *inMgr)
+ : m_Row(nullptr)
+ , m_TransMgr(inMgr)
+ , m_DataHandle(0)
+ , m_Parent(nullptr)
+ , m_TimelineTimebar(nullptr)
+{
+ m_StudioSystem = m_TransMgr->GetStudioSystem();
+ m_TransMgr->GetDoc()->GetCore()->GetDispatch()->AddDataModelListener(this);
+}
+
+CUICDMTimelineItemBinding::~CUICDMTimelineItemBinding()
+{
+ RemoveAllPropertyBindings();
+ delete m_TimelineTimebar;
+ m_TransMgr->GetDoc()->GetCore()->GetDispatch()->RemoveDataModelListener(this);
+}
+
+// helpers
+bool CUICDMTimelineItemBinding::UICDMGetBoolean(UICDM::CUICDMPropertyHandle inProperty) const
+{
+ UICDM::IPropertySystem *thePropertySystem = m_StudioSystem->GetPropertySystem();
+ SValue theValue;
+ thePropertySystem->GetInstancePropertyValue(m_DataHandle, inProperty, theValue);
+ return UICDM::get<bool>(theValue);
+}
+
+void CUICDMTimelineItemBinding::UICDMSetBoolean(UICDM::CUICDMPropertyHandle inProperty,
+ bool inValue, const QString &inNiceText) const
+{
+ CDoc *theDoc = dynamic_cast<CDoc *>(g_StudioApp.GetCore()->GetDoc());
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*theDoc, inNiceText)
+ ->SetInstancePropertyValue(m_DataHandle, inProperty, inValue);
+}
+
+void CUICDMTimelineItemBinding::SetInstanceHandle(UICDM::CUICDMInstanceHandle inDataHandle)
+{
+ m_DataHandle = inDataHandle;
+}
+
+EStudioObjectType CUICDMTimelineItemBinding::GetObjectType() const
+{
+ return m_StudioSystem->GetClientDataModelBridge()->GetObjectType(m_DataHandle);
+}
+
+bool CUICDMTimelineItemBinding::IsMaster() const
+{
+ CDoc *theDoc = dynamic_cast<CDoc *>(g_StudioApp.GetCore()->GetDoc());
+ Q3DStudio::IDocumentReader &theReader(theDoc->GetDocumentReader());
+ if (GetObjectType() == OBJTYPE_IMAGE) {
+ CClientDataModelBridge *theBridge = m_StudioSystem->GetClientDataModelBridge();
+ CUICDMInstanceHandle theParent;
+ CUICDMPropertyHandle theProperty;
+ bool isPropertyLinked;
+
+ theBridge->GetMaterialFromImageInstance(GetInstance(), theParent, theProperty);
+ isPropertyLinked = theReader.IsPropertyLinked(theParent, theProperty);
+
+ // Also check light probe
+ if (!isPropertyLinked) {
+ theBridge->GetLayerFromImageProbeInstance(GetInstance(), theParent, theProperty);
+ isPropertyLinked = theReader.IsPropertyLinked(theParent, theProperty);
+ }
+
+ return isPropertyLinked;
+ }
+ CUICDMInstanceHandle theQueryHandle(m_DataHandle);
+ if (GetObjectType() == OBJTYPE_PATHANCHORPOINT)
+ theQueryHandle = theReader.GetParent(m_DataHandle);
+
+ // logic: you can't unlink name, so if name is linked then, this is master.
+ CUICDMPropertyHandle theNamePropHandle =
+ m_StudioSystem->GetPropertySystem()->GetAggregateInstancePropertyByName(theQueryHandle,
+ L"name");
+ return theReader.IsPropertyLinked(theQueryHandle, theNamePropHandle);
+}
+
+bool CUICDMTimelineItemBinding::IsShy() const
+{
+ return UICDMGetBoolean(m_StudioSystem->GetClientDataModelBridge()->GetSceneAsset().m_Shy);
+}
+void CUICDMTimelineItemBinding::SetShy(bool inShy)
+{
+ UICDMSetBoolean(m_StudioSystem->GetClientDataModelBridge()->GetSceneAsset().m_Shy, inShy,
+ QObject::tr("Shy Toggle"));
+}
+bool CUICDMTimelineItemBinding::IsLocked() const
+{
+ return UICDMGetBoolean(m_StudioSystem->GetClientDataModelBridge()->GetSceneAsset().m_Locked);
+}
+
+void ToggleChildrenLock(Q3DStudio::ScopedDocumentEditor &scopedDocEditor,
+ CUICDMTimelineItemBinding *inTimelineItemBinding,
+ SDataModelSceneAsset inSceneAsset, bool inLocked)
+{
+ scopedDocEditor->SetInstancePropertyValue(inTimelineItemBinding->GetInstanceHandle(),
+ inSceneAsset.m_Locked, inLocked);
+ long childrenCount = inTimelineItemBinding->GetChildrenCount();
+ if (childrenCount == 0)
+ return;
+ for (long i = 0; i < childrenCount; ++i) {
+ CUICDMTimelineItemBinding *child =
+ static_cast<CUICDMTimelineItemBinding *>(inTimelineItemBinding->GetChild(i));
+ ToggleChildrenLock(scopedDocEditor, child, inSceneAsset, inLocked);
+ }
+}
+
+void CUICDMTimelineItemBinding::SetLocked(bool inLocked)
+{
+ CDoc *theDoc = dynamic_cast<CDoc *>(g_StudioApp.GetCore()->GetDoc());
+ Q3DStudio::ScopedDocumentEditor scopedDocEditor(*theDoc, L"SetLock", __FILE__, __LINE__);
+
+ SDataModelSceneAsset sceneAsset = m_StudioSystem->GetClientDataModelBridge()->GetSceneAsset();
+ ToggleChildrenLock(scopedDocEditor, this, sceneAsset, inLocked);
+
+ if (inLocked)
+ g_StudioApp.GetCore()->GetDoc()->NotifySelectionChanged();
+}
+
+bool CUICDMTimelineItemBinding::IsVisible() const
+{
+ return UICDMGetBoolean(m_StudioSystem->GetClientDataModelBridge()->GetSceneAsset().m_Eyeball);
+}
+
+void CUICDMTimelineItemBinding::SetVisible(bool inVisible)
+{
+ UICDMSetBoolean(m_StudioSystem->GetClientDataModelBridge()->GetSceneAsset().m_Eyeball,
+ inVisible, QObject::tr("Visibility Toggle"));
+}
+
+// remember the expanded state for the current presentation
+bool CUICDMTimelineItemBinding::IsExpanded() const
+{
+ return m_TransMgr->IsExpanded(m_DataHandle);
+}
+// remember the expanded state for the current presentation
+void CUICDMTimelineItemBinding::SetExpanded(bool inExpanded)
+{
+ m_TransMgr->SetExpanded(m_DataHandle, inExpanded);
+}
+
+bool CUICDMTimelineItemBinding::HasAction(bool inMaster)
+{
+ TActionHandleList theActions;
+ CDoc *theDoc = g_StudioApp.GetCore()->GetDoc();
+
+ CUICDMSlideHandle theSlide = theDoc->GetActiveSlide();
+ UICDM::ISlideCore &theSlideCore(*m_StudioSystem->GetSlideCore());
+ if (theSlideCore.IsSlide(theSlide)) {
+ if (inMaster)
+ theSlide =
+ m_StudioSystem->GetSlideSystem()->GetMasterSlide(theSlide); // use the master slide
+
+ m_StudioSystem->GetActionCore()->GetActions(theSlide, m_DataHandle, theActions);
+ }
+ return theActions.size() > 0;
+}
+
+bool CUICDMTimelineItemBinding::ChildrenHasAction(bool inMaster)
+{
+ // Get all the instances in this slidegraph
+ // check whehter it's an action instance and is in the slide of interst
+ // check also it's owner is a descendent of the viewed instances
+ CDoc *theDoc = g_StudioApp.GetCore()->GetDoc();
+ IActionCore *theActionCore(m_StudioSystem->GetActionCore());
+ CClientDataModelBridge *theBridge(m_StudioSystem->GetClientDataModelBridge());
+
+ CUICDMSlideHandle theSlide = theDoc->GetActiveSlide();
+ UICDM::ISlideCore &theSlideCore(*m_StudioSystem->GetSlideCore());
+ if (theSlideCore.IsSlide(theSlide)) {
+ if (inMaster)
+ theSlide =
+ m_StudioSystem->GetSlideSystem()->GetMasterSlide(theSlide); // use the master slide
+
+ TSlideInstancePairList theGraphInstances;
+ m_StudioSystem->GetSlideSystem()->GetAssociatedInstances(theSlide, theGraphInstances);
+
+ UICDM::CUICDMInstanceHandle theObservedInstance = GetInstance();
+ if (theObservedInstance.Valid()) {
+ for (TSlideInstancePairList::const_iterator theIter = theGraphInstances.begin();
+ theIter != theGraphInstances.end(); ++theIter) {
+ if (theIter->first == theSlide && theBridge->IsActionInstance(theIter->second)) {
+ CUICDMActionHandle theAction =
+ theActionCore->GetActionByInstance(theIter->second);
+ SActionInfo theActionInfo = theActionCore->GetActionInfo(theAction);
+ CUICDMInstanceHandle theAcionOwner = theActionInfo.m_Owner;
+ if (theAcionOwner.Valid()
+ && IsAscendant(theAcionOwner, theObservedInstance, theDoc->GetAssetGraph()))
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool CUICDMTimelineItemBinding::ComponentHasAction(bool inMaster)
+{
+ // Get all the instances in this component slidegraph
+ // check whether the instance is an action instance
+ // if inMaster is true, we only interest with those that are in the master slide, else we want
+ // those that are not in the master slide
+ CClientDataModelBridge *theBridge(m_StudioSystem->GetClientDataModelBridge());
+ if (!theBridge->IsComponentInstance(m_DataHandle))
+ return false;
+
+ Q3DStudio::CId theAssetId = theBridge->GetGUID(m_DataHandle);
+ CUICDMSlideHandle theMasterSlide =
+ m_StudioSystem->GetSlideSystem()->GetMasterSlideByComponentGuid(GuidtoSLong4(theAssetId));
+
+ TSlideInstancePairList theGraphInstances;
+ m_StudioSystem->GetSlideSystem()->GetAssociatedInstances(theMasterSlide, theGraphInstances);
+
+ for (TSlideInstancePairList::const_iterator theIter = theGraphInstances.begin();
+ theIter != theGraphInstances.end(); ++theIter) {
+ if (((inMaster && theIter->first == theMasterSlide)
+ || (!inMaster && theIter->first != theMasterSlide))
+ && theBridge->IsActionInstance(theIter->second))
+ return true;
+ }
+ return false;
+}
+
+ITimelineTimebar *CUICDMTimelineItemBinding::GetTimebar()
+{
+ if (!m_TimelineTimebar)
+ m_TimelineTimebar = CreateTimelineTimebar();
+ return m_TimelineTimebar;
+}
+
+Q3DStudio::CString CUICDMTimelineItemBinding::GetName() const
+{
+ if (m_StudioSystem->IsInstance(m_DataHandle) == false)
+ return L"";
+ CUICDMPropertyHandle theNamePropHandle =
+ m_StudioSystem->GetPropertySystem()->GetAggregateInstancePropertyByName(m_DataHandle,
+ L"name");
+ SValue theNameValue;
+ m_StudioSystem->GetPropertySystem()->GetInstancePropertyValue(m_DataHandle, theNamePropHandle,
+ theNameValue);
+ TDataStrPtr theName = UICDM::get<TDataStrPtr>(theNameValue);
+
+ return (theName) ? Q3DStudio::CString(theName->GetData()) : "";
+}
+
+void CUICDMTimelineItemBinding::SetName(const Q3DStudio::CString &inName)
+{
+ // Display warning dialog if user tried to enter an empty string
+ if (inName.IsEmpty()) {
+ Q3DStudio::CString theTitle(::LoadResourceString(IDS_ERROR_OBJECT_RENAME_TITLE));
+ Q3DStudio::CString theString(::LoadResourceString(IDS_ERROR_OBJECT_RENAME_EMPTY_STRING));
+ g_StudioApp.GetDialogs()->DisplayMessageBox(theTitle, theString, CUICMessageBox::ICON_ERROR,
+ false);
+
+ return;
+ }
+
+ CClientDataModelBridge *theBridge = m_StudioSystem->GetClientDataModelBridge();
+ if (!theBridge->CheckNameUnique(m_DataHandle, inName)) {
+ Q3DStudio::CString theTitle(::LoadResourceString(IDS_ERROR_OBJECT_RENAME_TITLE));
+ Q3DStudio::CString theString(
+ ::LoadResourceString(IDS_ERROR_OBJECT_RENAME_DUPLICATED_STRING));
+ int theUserChoice = g_StudioApp.GetDialogs()->DisplayChoiceBox(
+ theTitle, theString, CUICMessageBox::ICON_WARNING);
+ if (theUserChoice == QMessageBox::Yes) {
+ // Set with the unique name
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*m_TransMgr->GetDoc(), QObject::tr("Set Name"))
+ ->SetName(m_DataHandle, inName, true);
+ return;
+ }
+ }
+ // Set the name no matter it's unique or not
+ CUICDMPropertyHandle theNamePropHandle =
+ m_StudioSystem->GetPropertySystem()->GetAggregateInstancePropertyByName(m_DataHandle,
+ L"name");
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*m_TransMgr->GetDoc(), QObject::tr("Set Name"))
+ ->SetInstancePropertyValue(m_DataHandle, theNamePropHandle,
+ std::make_shared<CDataStr>(inName));
+}
+
+ITimelineItem *CUICDMTimelineItemBinding::GetTimelineItem()
+{
+ return this;
+}
+
+CBaseStateRow *CUICDMTimelineItemBinding::GetRow()
+{
+ return m_Row;
+}
+
+void CUICDMTimelineItemBinding::SetSelected(bool inMultiSelect)
+{
+ if (!inMultiSelect)
+ g_StudioApp.GetCore()->GetDoc()->SelectUICDMObject(m_DataHandle);
+ else
+ g_StudioApp.GetCore()->GetDoc()->ToggleUICDMObjectToSelection(m_DataHandle);
+}
+
+void CUICDMTimelineItemBinding::OnCollapsed()
+{
+ // Preserves legacy behavior where collapsing a tree will select that root, if any of its
+ // descendant was selected
+ // TODO: This won't work for Image (because Image is Material's property, not child)
+ UICDM::CUICDMInstanceHandle theInstance = GetInstance();
+ if (theInstance.Valid()) {
+ CDoc *theDoc = m_TransMgr->GetDoc();
+ UICDM::CUICDMInstanceHandle theSelectedInstance = theDoc->GetSelectedInstance();
+ if (theSelectedInstance.Valid()
+ && IsAscendant(theSelectedInstance, theInstance, theDoc->GetAssetGraph()))
+ SetSelected(false);
+ }
+}
+
+void CUICDMTimelineItemBinding::ClearKeySelection()
+{
+ m_TransMgr->ClearKeyframeSelection();
+}
+
+bool CUICDMTimelineItemBinding::OpenAssociatedEditor()
+{
+ return false; // nothing to do by default
+}
+
+void CUICDMTimelineItemBinding::DoStartDrag(CControlWindowListener *inWndListener)
+{
+ inWndListener->DoStartDrag(this);
+}
+
+inline UICDM::CUICDMInstanceHandle CUICDMTimelineItemBinding::GetInstance() const
+{
+ return m_DataHandle;
+}
+
+void CUICDMTimelineItemBinding::SetDropTarget(CDropTarget *inTarget)
+{
+ UICDM::CUICDMInstanceHandle theInstance = GetInstance();
+ inTarget->SetInstance(theInstance);
+}
+
+long CUICDMTimelineItemBinding::GetChildrenCount()
+{
+ UICDM::CUICDMInstanceHandle theInstance = GetInstance();
+ if (theInstance.Valid()) {
+ Q3DStudio::CGraphIterator theChildren;
+ CUICDMSlideHandle theActiveSlide = m_TransMgr->GetDoc()->GetActiveSlide();
+ GetAssetChildrenInTimeParent(theInstance, m_TransMgr->GetDoc(), AmITimeParent(),
+ theChildren, theActiveSlide);
+ return (long)theChildren.GetCount();
+ }
+ return 0;
+}
+
+ITimelineItemBinding *CUICDMTimelineItemBinding::GetChild(long inIndex)
+{
+ UICDM::CUICDMInstanceHandle theInstance = GetInstance();
+ if (theInstance.Valid()) {
+ Q3DStudio::CGraphIterator theChildren;
+ CUICDMSlideHandle theActiveSlide = m_TransMgr->GetDoc()->GetActiveSlide();
+ GetAssetChildrenInTimeParent(theInstance, m_TransMgr->GetDoc(), AmITimeParent(),
+ theChildren, theActiveSlide);
+ theChildren += inIndex;
+
+ UICDM::CUICDMInstanceHandle theChildInstance = theChildren.GetCurrent();
+ if (theChildInstance.Valid())
+ return m_TransMgr->GetOrCreate(theChildInstance);
+ }
+ return nullptr;
+}
+
+ITimelineItemBinding *CUICDMTimelineItemBinding::GetParent()
+{
+ return m_Parent;
+}
+void CUICDMTimelineItemBinding::SetParent(ITimelineItemBinding *parent)
+{
+ if (parent != m_Parent) {
+ ASSERT(parent == nullptr || m_Parent == nullptr);
+ m_Parent = parent;
+ }
+}
+
+long CUICDMTimelineItemBinding::GetPropertyCount()
+{
+ long theCount = 0;
+ if (m_StudioSystem->IsInstance(m_DataHandle)) {
+ TPropertyHandleList theProperties;
+ m_StudioSystem->GetPropertySystem()->GetAggregateInstanceProperties(m_DataHandle,
+ theProperties);
+ for (size_t thePropertyIndex = 0; thePropertyIndex < theProperties.size();
+ ++thePropertyIndex) {
+ if (m_StudioSystem->GetAnimationSystem()->IsPropertyAnimated(
+ m_DataHandle, theProperties[thePropertyIndex]))
+ ++theCount;
+ }
+ }
+ return theCount;
+}
+
+ITimelineItemProperty *CUICDMTimelineItemBinding::GetProperty(long inIndex)
+{
+ TPropertyHandleList theProperties;
+ m_StudioSystem->GetPropertySystem()->GetAggregateInstanceProperties(m_DataHandle,
+ theProperties);
+ long theIndex = -1;
+ size_t thePropertyIndex = 0;
+ for (; thePropertyIndex < theProperties.size(); ++thePropertyIndex) {
+ if (m_StudioSystem->GetAnimationSystem()->IsPropertyAnimated(
+ m_DataHandle, theProperties[thePropertyIndex])) {
+ ++theIndex;
+ if (theIndex == inIndex)
+ break;
+ }
+ }
+ ASSERT(thePropertyIndex < theProperties.size()); // no reason why this would be out of range!!
+ return GetOrCreatePropertyBinding(theProperties[thePropertyIndex]);
+}
+
+bool CUICDMTimelineItemBinding::ShowToggleControls() const
+{
+ return true;
+}
+bool CUICDMTimelineItemBinding::IsLockedEnabled() const
+{
+ return IsLocked();
+}
+bool CUICDMTimelineItemBinding::IsVisibleEnabled() const
+{
+ // You can only toggle visible if you aren't on the master slide.
+ return m_StudioSystem->GetSlideSystem()->GetSlideIndex(m_TransMgr->GetDoc()->GetActiveSlide())
+ != 0;
+}
+
+void CUICDMTimelineItemBinding::Bind(CBaseStateRow *inRow)
+{
+ ASSERT(!m_Row);
+ m_Row = inRow;
+
+ // Because children(properties included) may only be loaded later, check if there are any
+ // keyframes without having to have the UI created.
+ TPropertyHandleList theProperties;
+ m_StudioSystem->GetPropertySystem()->GetAggregateInstanceProperties(m_DataHandle,
+ theProperties);
+ for (size_t thePropertyIndex = 0; thePropertyIndex < theProperties.size(); ++thePropertyIndex) {
+ if (m_StudioSystem->GetAnimationSystem()->IsPropertyAnimated(
+ m_DataHandle, theProperties[thePropertyIndex]))
+ AddKeyframes(GetOrCreatePropertyBinding(theProperties[thePropertyIndex]));
+ }
+
+ // Set selection status
+ CUICDMInstanceHandle theSelectedInstance = m_TransMgr->GetDoc()->GetSelectedInstance();
+ m_Row->OnSelected(m_DataHandle == theSelectedInstance);
+}
+
+void CUICDMTimelineItemBinding::Release()
+{
+ m_Row = nullptr;
+ RemoveAllPropertyBindings();
+ m_TransMgr->Unregister(this);
+}
+
+bool CUICDMTimelineItemBinding::IsValidTransaction(EUserTransaction inTransaction)
+{
+ UICDM::CUICDMInstanceHandle theInstance = GetInstance();
+ switch (inTransaction) {
+ case EUserTransaction_Rename:
+ return (GetObjectType() != OBJTYPE_SCENE && GetObjectType() != OBJTYPE_IMAGE);
+
+ case EUserTransaction_Duplicate:
+ if (theInstance.Valid())
+ return m_StudioSystem->GetClientDataModelBridge()->IsDuplicateable(theInstance);
+ break;
+
+ case EUserTransaction_Cut:
+ return g_StudioApp.CanCut();
+
+ case EUserTransaction_Copy:
+ return g_StudioApp.CanCopy();
+
+ case EUserTransaction_Paste:
+ return m_TransMgr->GetDoc()->CanPasteObject();
+
+ case EUserTransaction_Delete:
+ if (theInstance.Valid())
+ return m_StudioSystem->GetClientDataModelBridge()->CanDelete(theInstance);
+ break;
+
+ case EUserTransaction_MakeComponent: {
+ bool theCanMakeFlag = false;
+ if (theInstance.Valid()) {
+ CClientDataModelBridge *theBridge = m_StudioSystem->GetClientDataModelBridge();
+ EStudioObjectType theObjectType = theBridge->GetObjectType(theInstance);
+
+ if (!IsLocked()) {
+ // Any assets that are attached to the Scene directly must not be wrapped in a
+ // component.
+ // This may include behavior assets which may be directly attached to the Scene.
+ // This is because by principal, components cannot exist on the Scene directly.
+ UICDM::CUICDMInstanceHandle theParentInstance =
+ theBridge->GetParentInstance(theInstance);
+ if (theObjectType != OBJTYPE_LAYER && theObjectType != OBJTYPE_SCENE
+ && theObjectType != OBJTYPE_MATERIAL && theObjectType != OBJTYPE_IMAGE
+ && theObjectType != OBJTYPE_EFFECT
+ && (theParentInstance.Valid()
+ && theBridge->GetObjectType(theParentInstance)
+ != OBJTYPE_SCENE)) // This checks if the object is
+ // AttachedToSceneDirectly
+ {
+ theCanMakeFlag = true;
+ }
+ }
+ }
+ return theCanMakeFlag;
+ }
+
+ case EUserTransaction_EditComponent:
+ return (GetObjectType() == OBJTYPE_COMPONENT);
+
+ default: // not handled
+ break;
+ }
+
+ return false;
+}
+
+using namespace Q3DStudio;
+
+inline void DoCut(CDoc &inDoc, const UICDM::TInstanceHandleList &inInstances)
+{
+ inDoc.DeselectAllKeyframes();
+ inDoc.CutObject(inInstances);
+}
+
+inline void DoDelete(CDoc &inDoc, const UICDM::TInstanceHandleList &inInstances)
+{
+ inDoc.DeselectAllKeyframes();
+ inDoc.DeleteObject(inInstances);
+}
+
+inline void DoMakeComponent(CDoc &inDoc, const UICDM::TInstanceHandleList &inInstances)
+{
+ SCOPED_DOCUMENT_EDITOR(inDoc, QObject::tr("Make Component"))->MakeComponent(inInstances);
+}
+
+void CUICDMTimelineItemBinding::PerformTransaction(EUserTransaction inTransaction)
+{
+ CDoc *theDoc = m_TransMgr->GetDoc();
+ UICDM::TInstanceHandleList theInstances = theDoc->GetSelectedValue().GetSelectedInstances();
+ if (theInstances.empty())
+ return;
+ CDispatch &theDispatch(*theDoc->GetCore()->GetDispatch());
+
+ // Transactions that could result in *this* object being deleted need to be executed
+ // via postmessage, not in this context because it could result in the currently
+ // active timeline row being deleted while in its own mouse handler.
+ switch (inTransaction) {
+ case EUserTransaction_Duplicate: {
+ theDoc->DeselectAllKeyframes();
+ SCOPED_DOCUMENT_EDITOR(*theDoc, QObject::tr("Duplicate Object"))->DuplicateInstances(theInstances);
+ } break;
+ case EUserTransaction_Cut: {
+ theDispatch.FireOnAsynchronousCommand(
+ std::bind(DoCut, std::ref(*theDoc), theInstances));
+ } break;
+ case EUserTransaction_Copy: {
+ theDoc->DeselectAllKeyframes();
+ theDoc->CopyObject(theInstances);
+ } break;
+ case EUserTransaction_Paste: {
+ theDoc->DeselectAllKeyframes();
+ theDoc->PasteObject(GetInstance());
+ } break;
+ case EUserTransaction_Delete: {
+ theDispatch.FireOnAsynchronousCommand(
+ std::bind(DoDelete, std::ref(*theDoc), theInstances));
+ } break;
+ case EUserTransaction_MakeComponent: {
+ theDispatch.FireOnAsynchronousCommand(
+ std::bind(DoMakeComponent, std::ref(*theDoc), theInstances));
+ }
+ default: // not handled
+ break;
+ }
+}
+
+Q3DStudio::CString CUICDMTimelineItemBinding::GetObjectPath()
+{
+ CDoc *theDoc = m_TransMgr->GetDoc();
+ // Because we are getting absolute path, the base id doesn't matter.
+ return CRelativePathTools::BuildAbsoluteReferenceString(m_DataHandle, theDoc);
+}
+
+ITimelineKeyframesManager *CUICDMTimelineItemBinding::GetKeyframesManager() const
+{
+ return m_TransMgr->GetKeyframesManager();
+}
+
+void CUICDMTimelineItemBinding::RemoveProperty(ITimelineItemProperty *inProperty)
+{
+ Q_UNUSED(inProperty);
+ // TODO: This function has no use in UICDM world. This is replaced by RemovePropertyRow(
+ // CUICDMPropertyHandle inPropertyHandle ).
+ // Decide if this function should be removed from ITimelineItemBinding.
+}
+
+void CUICDMTimelineItemBinding::LoadProperties()
+{
+ TPropertyHandleList theProperties;
+ m_StudioSystem->GetPropertySystem()->GetAggregateInstanceProperties(m_DataHandle,
+ theProperties);
+ for (size_t thePropertyIndex = 0; thePropertyIndex < theProperties.size(); ++thePropertyIndex) {
+ if (m_StudioSystem->GetAnimationSystem()->IsPropertyAnimated(
+ m_DataHandle, theProperties[thePropertyIndex]))
+ AddPropertyRow(theProperties[thePropertyIndex], true);
+ }
+}
+
+void CUICDMTimelineItemBinding::InsertKeyframe()
+{
+ if (m_PropertyBindingMap.empty())
+ return;
+
+ TPropertyBindingMap::const_iterator theIter = m_PropertyBindingMap.begin();
+ ScopedDocumentEditor editor(*g_StudioApp.GetCore()->GetDoc(), L"Insert Keyframe", __FILE__,
+ __LINE__);
+ for (; theIter != m_PropertyBindingMap.end(); ++theIter)
+ editor->KeyframeProperty(m_DataHandle, theIter->first, false);
+}
+
+void CUICDMTimelineItemBinding::DeleteAllChannelKeyframes()
+{
+ if (m_PropertyBindingMap.empty())
+ return;
+
+ CDoc *theDoc = m_TransMgr->GetDoc();
+ Q3DStudio::ScopedDocumentEditor editor(*theDoc, L"Delete Channel Keyframes", __FILE__,
+ __LINE__);
+ for (TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.begin(),
+ theEnd = m_PropertyBindingMap.end();
+ theIter != theEnd; ++theIter)
+ theIter->second->DeleteAllKeys();
+}
+
+long CUICDMTimelineItemBinding::GetKeyframeCount() const
+{
+ // This list is updated when properties are loaded and when keyframes are added & deleted.
+ return (long)m_Keyframes.size();
+}
+
+IKeyframe *CUICDMTimelineItemBinding::GetKeyframeByTime(long inTime) const
+{
+ TAssetKeyframeList::const_iterator theIter = m_Keyframes.begin();
+ for (; theIter != m_Keyframes.end(); ++theIter) {
+ if ((*theIter).GetTime() == inTime)
+ return const_cast<CUICDMAssetTimelineKeyframe *>(&(*theIter));
+ }
+ return nullptr;
+}
+
+IKeyframe *CUICDMTimelineItemBinding::GetKeyframeByIndex(long inIndex) const
+{
+ if (inIndex >= 0 && inIndex < (long)m_Keyframes.size())
+ return const_cast<CUICDMAssetTimelineKeyframe *>(&m_Keyframes[inIndex]);
+
+ ASSERT(0); // should not happen
+ return nullptr;
+}
+
+long CUICDMTimelineItemBinding::OffsetSelectedKeyframes(long inOffset)
+{
+ return m_TransMgr->GetKeyframesManager()->OffsetSelectedKeyframes(inOffset);
+}
+
+void CUICDMTimelineItemBinding::CommitChangedKeyframes()
+{
+ m_TransMgr->GetKeyframesManager()->CommitChangedKeyframes();
+}
+
+void CUICDMTimelineItemBinding::OnEditKeyframeTime(long inCurrentTime, long inObjectAssociation)
+{
+ CTimeEditDlg theTimeEditDlg;
+ theTimeEditDlg.SetKeyframesManager(m_TransMgr->GetKeyframesManager());
+ theTimeEditDlg.ShowDialog(inCurrentTime, 0, g_StudioApp.GetCore()->GetDoc(),
+ inObjectAssociation);
+}
+
+void CUICDMTimelineItemBinding::SelectKeyframes(bool inSelected, long inTime /*= -1 */)
+{
+ // Callback from UI, hence skip the UI update
+ DoSelectKeyframes(inSelected, inTime, false);
+}
+
+CUICDMInstanceHandle CUICDMTimelineItemBinding::GetInstanceHandle() const
+{
+ return m_DataHandle;
+}
+
+long CUICDMTimelineItemBinding::GetFlavor() const
+{
+ return EUIC_FLAVOR_ASSET_TL;
+}
+
+void CUICDMTimelineItemBinding::OnBeginDataModelNotifications()
+{
+}
+void CUICDMTimelineItemBinding::OnEndDataModelNotifications()
+{
+ RefreshStateRow();
+}
+void CUICDMTimelineItemBinding::OnImmediateRefreshInstanceSingle(
+ UICDM::CUICDMInstanceHandle inInstance)
+{
+ if (inInstance == m_DataHandle)
+ RefreshStateRow(true);
+}
+void CUICDMTimelineItemBinding::OnImmediateRefreshInstanceMultiple(
+ UICDM::CUICDMInstanceHandle *inInstance, long inInstanceCount)
+{
+ for (long idx = 0; idx < inInstanceCount; ++idx)
+ if (inInstance[idx] == m_DataHandle) {
+ RefreshStateRow();
+ break;
+ }
+}
+
+void CUICDMTimelineItemBinding::RefreshStateRow(bool inRefreshChildren)
+{
+ CStateRow *theRow = dynamic_cast<CStateRow *>(m_Row);
+ if (theRow) {
+ theRow->OnTimeChange();
+ theRow->ClearDirty();
+ if (inRefreshChildren) {
+ long theChildrenCount = GetChildrenCount();
+ for (long theIndex = 0; theIndex < theChildrenCount; ++theIndex) {
+ ITimelineItemBinding *theChild = GetChild(theIndex);
+ CUICDMTimelineItemBinding *theBinding =
+ dynamic_cast<CUICDMTimelineItemBinding *>(theChild);
+ if (theBinding)
+ theBinding->RefreshStateRow(inRefreshChildren);
+ }
+ }
+ }
+}
+
+ITimelineTimebar *CUICDMTimelineItemBinding::CreateTimelineTimebar()
+{
+ return new CUICDMTimelineTimebar(m_TransMgr, m_DataHandle);
+}
+
+ITimelineItemProperty *
+CUICDMTimelineItemBinding::GetPropertyBinding(CUICDMPropertyHandle inPropertyHandle)
+{
+ TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.find(inPropertyHandle);
+ // check if it already exists
+ if (theIter != m_PropertyBindingMap.end())
+ return theIter->second;
+ return nullptr;
+}
+
+ITimelineItemProperty *
+CUICDMTimelineItemBinding::GetOrCreatePropertyBinding(CUICDMPropertyHandle inPropertyHandle)
+{
+ ITimelineItemProperty *theProperty = GetPropertyBinding(inPropertyHandle);
+ // check if it already exists
+ if (theProperty)
+ return theProperty;
+
+ // Create
+ CUICDMTimelineItemProperty *theTimelineProperty =
+ new CUICDMTimelineItemProperty(m_TransMgr, inPropertyHandle, m_DataHandle);
+ m_PropertyBindingMap.insert(std::make_pair(inPropertyHandle, theTimelineProperty));
+
+ return theTimelineProperty;
+}
+
+//=============================================================================
+/**
+ * Add a new property row for this property.
+ * @param inAppend true to skip the check to find where to insert. ( true if this is a
+ * loading/initializing step, where the call is already done in order )
+ */
+void CUICDMTimelineItemBinding::AddPropertyRow(CUICDMPropertyHandle inPropertyHandle,
+ bool inAppend /*= false */)
+{
+ ITimelineItemProperty *theTimelineProperty = GetPropertyBinding(inPropertyHandle);
+ if (theTimelineProperty && theTimelineProperty->GetRow()) // if created, bail
+ return;
+
+ if (!theTimelineProperty)
+ theTimelineProperty = GetOrCreatePropertyBinding(inPropertyHandle);
+
+ // Find the row to insert this new property, if any, this preserves the order the property rows
+ // is displayed in the timeline.
+ ITimelineItemProperty *theNextProperty = nullptr;
+ if (!inAppend) {
+ TPropertyHandleList theProperties;
+ m_StudioSystem->GetPropertySystem()->GetAggregateInstanceProperties(m_DataHandle,
+ theProperties);
+ size_t thePropertyIndex = 0;
+ size_t thePropertyCount = theProperties.size();
+ for (; thePropertyIndex < thePropertyCount; ++thePropertyIndex) {
+ if (theProperties[thePropertyIndex] == inPropertyHandle) {
+ ++thePropertyIndex;
+ break;
+ }
+ }
+ // Not all properties are displayed, so another loop to search for the first one that maps
+ // to a existing propertyrow
+ for (; thePropertyIndex < thePropertyCount; ++thePropertyIndex) {
+ TPropertyBindingMap::iterator theNextPropIter =
+ m_PropertyBindingMap.find(theProperties[thePropertyIndex]);
+ if (theNextPropIter != m_PropertyBindingMap.end()) {
+ theNextProperty = theNextPropIter->second;
+ break;
+ }
+ }
+ }
+ // Create a new property row
+ m_TransMgr->CreateNewPropertyRow(theTimelineProperty, m_Row,
+ theNextProperty ? theNextProperty->GetRow() : nullptr);
+
+ // Update keyframes
+ AddKeyframes(theTimelineProperty);
+}
+
+void CUICDMTimelineItemBinding::RemovePropertyRow(CUICDMPropertyHandle inPropertyHandle)
+{
+ TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.find(inPropertyHandle);
+ if (theIter != m_PropertyBindingMap.end()) {
+ ITimelineItemProperty *thePropertyBinding = theIter->second;
+
+ bool theUpdateUI = DeleteAssetKeyframesWhereApplicable(thePropertyBinding);
+
+ m_TransMgr->RemovePropertyRow(thePropertyBinding);
+ m_PropertyBindingMap.erase(theIter);
+
+ // UI must update
+ if (m_Row && theUpdateUI) {
+ m_Row->OnChildVisibilityChanged();
+ m_Row->GetTimebar()->SetDirty(true);
+ }
+ }
+}
+
+// called when a keyframe is inserted, deleted or updated in the data model
+void CUICDMTimelineItemBinding::RefreshPropertyKeyframe(
+ UICDM::CUICDMPropertyHandle inPropertyHandle, UICDM::CUICDMKeyframeHandle inKeyframe,
+ ETimelineKeyframeTransaction inTransaction)
+{
+ TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.find(inPropertyHandle);
+ if (theIter != m_PropertyBindingMap.end()) {
+ CUICDMTimelineItemProperty *theProperty = theIter->second;
+ if (theProperty) {
+ if (theProperty->RefreshKeyframe(inKeyframe, inTransaction)) {
+ // Update asset keyframes
+ UpdateKeyframe(theProperty->GetKeyframeByHandle(inKeyframe), inTransaction);
+ if (m_Row) // UI update
+ m_Row->GetTimebar()->SetDirty(true);
+ }
+ }
+ }
+}
+
+// called when the keyframes are updated in the UI and data model hasn't committed the change, ie no
+// event callback from UICDM
+void CUICDMTimelineItemBinding::UIRefreshPropertyKeyframe(long inOffset)
+{
+ if (!m_Row)
+ return;
+
+ // TODO: figure out a better way to sync m_Keyframes
+ TAssetKeyframeList::iterator theKeyIter = m_Keyframes.begin();
+ for (; theKeyIter != m_Keyframes.end(); ++theKeyIter) {
+ if (theKeyIter->IsSelected())
+ theKeyIter->UpdateTime(theKeyIter->GetTime() + inOffset);
+ }
+ // If a asset keyframe was "shared" by several properties' keyframes
+ // we need to 'break' this sharing and create for the remaining unmoved keyframes.
+ TPropertyBindingMap::const_iterator theIter = m_PropertyBindingMap.begin();
+ for (; theIter != m_PropertyBindingMap.end(); ++theIter) {
+ (*theIter).second->RefreshKeyFrames();
+
+ for (long i = 0; i < theIter->second->GetKeyframeCount(); ++i) {
+ IKeyframe *theKeyframe = theIter->second->GetKeyframeByIndex(i);
+ UpdateKeyframe(theKeyframe, ETimelineKeyframeTransaction_Add);
+
+ // Unfortunately, this is the way we can propagate UI updates to ALL selected keyframes
+ if (theKeyframe->IsSelected()) {
+ CPropertyRow *thePropertyRow = theIter->second->GetRow();
+ if (thePropertyRow)
+ thePropertyRow->GetTimebar()->SetDirty(true);
+ }
+ }
+ }
+ m_Row->GetTimebar()->SetDirty(true);
+}
+
+void CUICDMTimelineItemBinding::OnPropertyChanged(CUICDMPropertyHandle inPropertyHandle)
+{ // Refresh UI
+ CClientDataModelBridge *theBridge = m_StudioSystem->GetClientDataModelBridge();
+ if (m_Row && (inPropertyHandle == theBridge->GetNameProperty()
+ || inPropertyHandle == theBridge->GetSceneAsset().m_Eyeball
+ || inPropertyHandle == theBridge->GetSceneAsset().m_Locked
+ || inPropertyHandle == theBridge->GetSceneAsset().m_Shy
+ || inPropertyHandle == theBridge->GetSceneAsset().m_StartTime
+ || inPropertyHandle == theBridge->GetSceneAsset().m_EndTime))
+ m_Row->OnDirty();
+}
+
+void CUICDMTimelineItemBinding::OnPropertyLinked(CUICDMPropertyHandle inPropertyHandle)
+{
+ if (m_StudioSystem->GetAnimationSystem()->IsPropertyAnimated(m_DataHandle, inPropertyHandle)) {
+ // Refresh property row by delete and recreate
+ RemovePropertyRow(inPropertyHandle);
+ AddPropertyRow(inPropertyHandle);
+ }
+}
+
+bool CUICDMTimelineItemBinding::HasDynamicKeyframes(long inTime)
+{
+ if (inTime == -1) {
+ if (GetPropertyCount() == 0)
+ return false;
+
+ for (long i = 0; i < GetPropertyCount(); ++i) {
+ ITimelineItemProperty *theTimelineItemProperty = GetProperty(i);
+ if (!theTimelineItemProperty->IsDynamicAnimation())
+ return false;
+ }
+ return true;
+ } else {
+ TPropertyBindingMap::const_iterator theIter = m_PropertyBindingMap.begin();
+ for (; theIter != m_PropertyBindingMap.end(); ++theIter) {
+ IKeyframe *theKeyframe = theIter->second->GetKeyframeByTime(inTime);
+ if (theKeyframe && theKeyframe->IsDynamic())
+ return true;
+ }
+ }
+ return false;
+}
+
+void CUICDMTimelineItemBinding::SetDynamicKeyframes(long inTime, bool inDynamic)
+{
+ TPropertyBindingMap::const_iterator theIter = m_PropertyBindingMap.begin();
+ for (; theIter != m_PropertyBindingMap.end(); ++theIter) {
+ IKeyframe *theKeyframe = theIter->second->GetKeyframeByTime(inTime);
+ if (theKeyframe)
+ theKeyframe->SetDynamic(inDynamic); // TODO: we want this in 1 batch command
+ }
+}
+
+// Update UI on the selection state of all keyframes on this row and all its properties' keyframes.
+void CUICDMTimelineItemBinding::DoSelectKeyframes(bool inSelected, long inTime, bool inUpdateUI)
+{
+ if (inTime == -1) // all keyframes
+ {
+ TAssetKeyframeList::iterator theKeyIter = m_Keyframes.begin();
+ for (; theKeyIter != m_Keyframes.end(); ++theKeyIter)
+ theKeyIter->SetSelected(inSelected);
+ } else {
+ CUICDMAssetTimelineKeyframe *theKeyframe =
+ dynamic_cast<CUICDMAssetTimelineKeyframe *>(GetKeyframeByTime(inTime));
+ if (theKeyframe)
+ theKeyframe->SetSelected(inSelected);
+ }
+ if (inUpdateUI && m_Row)
+ m_Row->GetTimebar()->SelectKeysByTime(-1, inSelected);
+
+ // legacy feature: all properties with keyframes at inTime or all if inTime is -1 are selected
+ // as well.
+ TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.begin();
+ for (; theIter != m_PropertyBindingMap.end(); ++theIter)
+ theIter->second->DoSelectKeyframes(inSelected, inTime, true, this);
+}
+
+// When selecting by mouse-drag, if all properties are selected, select the asset keyframe. And if
+// one gets de-selected, de-select. Legacy feature.
+// Note that if only 1 property has a keyframe at time t, the asset keyframe gets selected
+// automatically when that keyframe is selected. Its odd to me but
+// that's how it has always behaved.
+void CUICDMTimelineItemBinding::OnPropertySelection(long inTime)
+{
+ IKeyframe *theAssetKeyframe = GetKeyframeByTime(inTime);
+ if (theAssetKeyframe) {
+ bool theAllSelectedFlag = true;
+ TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.begin();
+ for (; theIter != m_PropertyBindingMap.end(); ++theIter) {
+ IKeyframe *theKeyframe = theIter->second->GetKeyframeByTime(inTime);
+ if (theKeyframe && !theKeyframe->IsSelected()) // done, i.e selection remain unchanged.
+ {
+ theAllSelectedFlag = false;
+ break;
+ }
+ }
+ if (theAssetKeyframe->IsSelected() != theAllSelectedFlag) {
+ dynamic_cast<CUICDMAssetTimelineKeyframe *>(theAssetKeyframe)
+ ->SetSelected(theAllSelectedFlag);
+ // Update UI
+ if (m_Row)
+ m_Row->GetTimebar()->SelectKeysByTime(inTime, theAllSelectedFlag);
+ }
+ }
+}
+
+Q3DStudio::CId CUICDMTimelineItemBinding::GetGuid() const
+{
+ CClientDataModelBridge *theClientBridge = m_StudioSystem->GetClientDataModelBridge();
+ UICDM::IPropertySystem *thePropertySystem = m_StudioSystem->GetPropertySystem();
+ SValue theValue;
+ if (thePropertySystem->GetInstancePropertyValue(m_DataHandle, theClientBridge->GetIdProperty(),
+ theValue)) {
+ SLong4 theLong4 = UICDM::get<SLong4>(theValue);
+ return Q3DStudio::CId(theLong4.m_Longs[0], theLong4.m_Longs[1], theLong4.m_Longs[2],
+ theLong4.m_Longs[3]);
+ }
+ return Q3DStudio::CId();
+}
+
+// Delete asset keyframes at time t if no property keyframes exist at time t
+//@param inSkipPropertyBinding property that to skip, e.g. in cases where property is deleted
+//@return true if there are asset keyframes deleted.
+bool CUICDMTimelineItemBinding::DeleteAssetKeyframesWhereApplicable(
+ ITimelineItemProperty *inSkipPropertyBinding /*= nullptr */)
+{
+ // iterate through m_Keyframes because we cannot obtain time information from the Animation
+ // keyframes anymore, since they are deleted.
+ std::vector<long> theDeleteIndicesList;
+ for (size_t theIndex = 0; theIndex < m_Keyframes.size(); ++theIndex) {
+ TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.begin();
+ for (; theIter != m_PropertyBindingMap.end(); ++theIter) {
+ if ((!inSkipPropertyBinding || theIter->second != inSkipPropertyBinding)
+ && theIter->second->GetKeyframeByTime(m_Keyframes[theIndex].GetTime())) // done!
+ break;
+ }
+ if (theIter == m_PropertyBindingMap.end())
+ theDeleteIndicesList.push_back((long)theIndex);
+ }
+ // start with the last item, so that the indices remain valid.
+ for (long i = (long)theDeleteIndicesList.size() - 1; i >= 0; --i) {
+ TAssetKeyframeList::iterator theKeyIter = m_Keyframes.begin();
+ std::advance(theKeyIter, theDeleteIndicesList[i]);
+ m_Keyframes.erase(theKeyIter);
+ }
+
+ return !theDeleteIndicesList.empty();
+}
+
+void CUICDMTimelineItemBinding::RemoveAllPropertyBindings()
+{
+ TPropertyBindingMap::iterator theIter = m_PropertyBindingMap.begin();
+ for (; theIter != m_PropertyBindingMap.end(); ++theIter)
+ delete theIter->second;
+ m_PropertyBindingMap.clear();
+}
+
+void CUICDMTimelineItemBinding::AddKeyframes(ITimelineItemProperty *inPropertyBinding)
+{
+ for (long i = 0; i < inPropertyBinding->GetKeyframeCount(); ++i)
+ UpdateKeyframe(inPropertyBinding->GetKeyframeByIndex(i), ETimelineKeyframeTransaction_Add);
+}
+
+// Update the asset keyframes based on the properties' keyframes.
+void CUICDMTimelineItemBinding::UpdateKeyframe(IKeyframe *inKeyframe,
+ ETimelineKeyframeTransaction inTransaction)
+{
+ bool theDoAddFlag = (inTransaction == ETimelineKeyframeTransaction_Add);
+ bool theDoDeleteFlag = (inTransaction == ETimelineKeyframeTransaction_Delete);
+
+ // For update, if there isn't already a asset keyframe at the associated time, create one
+ if (inTransaction == ETimelineKeyframeTransaction_Update) {
+ theDoAddFlag = inKeyframe && !GetKeyframeByTime(inKeyframe->GetTime());
+ theDoDeleteFlag = true; // plus, since we don't keep track of indiviual property keyframes
+ // here, iterate and make sure list is correct.
+ }
+
+ if (theDoDeleteFlag)
+ DeleteAssetKeyframesWhereApplicable();
+
+ // Add when a new keyframe is added or MAYBE when a keyframe is moved
+ if (theDoAddFlag && inKeyframe) {
+ long theKeyframeTime = inKeyframe->GetTime();
+ if (theKeyframeTime >= 0) {
+ bool theAppend = true;
+ // insert this in the order that it should be. and we trust the
+ TAssetKeyframeList::iterator theIter = m_Keyframes.begin();
+ for (; theIter != m_Keyframes.end(); ++theIter) {
+ long theTime = (*theIter).GetTime();
+ if (theTime == theKeyframeTime) {
+ theAppend = false;
+ break; // already exists, we are done. Because we only need 1 to represent ALL
+ // properties
+ }
+ }
+ if (theAppend)
+ m_Keyframes.push_back(CUICDMAssetTimelineKeyframe(this, theKeyframeTime));
+ }
+ }
+ if (m_Row && (theDoAddFlag
+ || inTransaction == ETimelineKeyframeTransaction_DynamicChanged)) // dynamic =>
+ // only UI needs
+ // to refresh
+ m_Row->GetTimebar()->SetDirty(true);
+}
+
+void CUICDMTimelineItemBinding::OnAddChild(CUICDMInstanceHandle inInstance)
+{
+ CDoc *theDoc = m_TransMgr->GetDoc();
+ CClientDataModelBridge *theBridge = m_StudioSystem->GetClientDataModelBridge();
+ ISlideSystem *theSlideSystem = m_StudioSystem->GetSlideSystem();
+
+ UICDM::CUICDMSlideHandle theSlide = theSlideSystem->GetAssociatedSlide(inInstance);
+ if (theBridge->IsInActiveComponent(inInstance)
+ && (theSlideSystem->IsMasterSlide(theSlide) || theSlide == theDoc->GetActiveSlide())) {
+ // Only add if the asset is in the current active component, and it's a master asset or in
+ // the current slide
+ ITimelineItemBinding *theNextItem = nullptr;
+ UICDM::CUICDMInstanceHandle theParentInstance = GetInstance();
+ // Figure out where to insert this row, if applicable.
+ // CAsset has a list of children, and not necessarily all are active in this slide (e.g.
+ // non-master children)
+ Q3DStudio::TIdentifier theNextChild = 0;
+ if (theParentInstance.Valid()) {
+ // Get the next prioritized child in the same slide
+ Q3DStudio::CGraphIterator theChildren;
+ GetAssetChildrenInSlide(theDoc, theParentInstance, theDoc->GetActiveSlide(),
+ theChildren);
+ theNextChild = GetSibling(inInstance, true, theChildren);
+ }
+
+ if (theNextChild != 0)
+ theNextItem = m_TransMgr->GetOrCreate(theNextChild);
+
+ m_Row->AddChildRow(m_TransMgr->GetOrCreate(inInstance), theNextItem);
+ }
+}
+
+void CUICDMTimelineItemBinding::OnDeleteChild(CUICDMInstanceHandle inInstance)
+{
+ ITimelineItemBinding *theChild = m_TransMgr->GetOrCreate(inInstance);
+ if (theChild) {
+ m_Row->RemoveChildRow(theChild);
+ }
+}
+
+void CUICDMTimelineItemBinding::UpdateActionStatus()
+{
+ if (m_Row)
+ m_Row->UpdateActionStatus();
+}
+
+//=============================================================================
+/**
+ * Open the associated item as though it was double-clicked in explorer
+ * Respective subclasses (for example Image and Behavior) can call this function
+ */
+bool CUICDMTimelineItemBinding::OpenSourcePathFile()
+{
+ // Get source path property value
+ CClientDataModelBridge *theClientBridge = m_StudioSystem->GetClientDataModelBridge();
+ UICDM::IPropertySystem *thePropertySystem = m_StudioSystem->GetPropertySystem();
+ SValue theValue;
+ if (thePropertySystem->GetInstancePropertyValue(
+ m_DataHandle, theClientBridge->GetSourcePathProperty(), theValue)) {
+ // Open the respective file
+ Q3DStudio::CFilePath theSourcePath(UICDM::get<UICDM::TDataStrPtr>(theValue)->GetData());
+ CUICFile theFile(m_TransMgr->GetDoc()->GetResolvedPathToDoc(theSourcePath));
+ theFile.Execute();
+ return true;
+ }
+ return false;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.h
new file mode 100644
index 00000000..2866d698
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.h
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_UICDM_TIMELINEITEM_BINDING_H
+#define INCLUDED_UICDM_TIMELINEITEM_BINDING_H 1
+
+#pragma once
+
+#include "ITimelineItemBinding.h"
+#include "ITimelineItem.h"
+
+// Data model
+#include "UICDMHandles.h"
+#include "IDragable.h"
+#include "UICDMAssetTimelineKeyframe.h"
+#include "OffsetKeyframesCommandHelper.h"
+#include "UICDMTimeline.h"
+#include "UICDMSignals.h"
+#include "DispatchListeners.h"
+
+//==============================================================================
+// Classes
+//==============================================================================
+class CTimelineTranslationManager;
+class CBaseStateRow;
+class CUICDMTimelineItemProperty;
+class CCmdDataModelSetKeyframeTime;
+
+namespace UICDM {
+class CStudioSystem;
+}
+
+//=============================================================================
+/**
+ * Binding to generic UICDM object
+ */
+class CUICDMTimelineItemBinding : public ITimelineItemBinding,
+ public ITimelineItem,
+ public IDragable,
+ public IDataModelListener
+
+{
+protected: // Typedef
+ typedef std::map<UICDM::CUICDMPropertyHandle, CUICDMTimelineItemProperty *> TPropertyBindingMap;
+ typedef std::vector<CUICDMAssetTimelineKeyframe> TAssetKeyframeList;
+
+protected:
+ CBaseStateRow *m_Row;
+ CTimelineTranslationManager *m_TransMgr;
+ UICDM::CUICDMInstanceHandle m_DataHandle;
+ ITimelineItemBinding *m_Parent;
+ ITimelineTimebar *m_TimelineTimebar;
+ TPropertyBindingMap m_PropertyBindingMap;
+ TAssetKeyframeList m_Keyframes; /// Sorted (by time) list of keyframes
+ UICDM::CStudioSystem *m_StudioSystem;
+
+ UICDM::TSignalConnectionPtr m_StartTimeConnection;
+ UICDM::TSignalConnectionPtr m_EndTimeConnection;
+
+public:
+ CUICDMTimelineItemBinding(CTimelineTranslationManager *inMgr,
+ UICDM::CUICDMInstanceHandle inDataHandle);
+ CUICDMTimelineItemBinding(CTimelineTranslationManager *inMgr);
+ virtual ~CUICDMTimelineItemBinding();
+
+protected:
+ bool UICDMGetBoolean(UICDM::CUICDMPropertyHandle inProperty) const;
+ void UICDMSetBoolean(UICDM::CUICDMPropertyHandle inProperty, bool inValue,
+ const QString &inNiceText) const;
+ void SetInstanceHandle(UICDM::CUICDMInstanceHandle inDataHandle);
+
+public:
+ // ITimelineItem
+ EStudioObjectType GetObjectType() const override;
+ bool IsMaster() const override;
+ bool IsShy() const override;
+ void SetShy(bool) override;
+ bool IsLocked() const override;
+ void SetLocked(bool) override;
+ bool IsVisible() const override;
+ void SetVisible(bool) override;
+ bool IsExpanded() const override;
+ void SetExpanded(bool inExpanded) override;
+ bool HasAction(bool inMaster) override;
+ bool ChildrenHasAction(bool inMaster) override;
+ bool ComponentHasAction(bool inMaster) override;
+ ITimelineTimebar *GetTimebar() override;
+
+ // INamable
+ Q3DStudio::CString GetName() const override;
+ void SetName(const Q3DStudio::CString &inName) override;
+
+ // ITimelineItemBinding
+ ITimelineItem *GetTimelineItem() override;
+ CBaseStateRow *GetRow() override;
+ void SetSelected(bool inMultiSelect) override;
+ void OnCollapsed() override;
+ void ClearKeySelection() override;
+ bool OpenAssociatedEditor() override;
+ void DoStartDrag(CControlWindowListener *inWndListener) override;
+ void SetDropTarget(CDropTarget *inTarget) override;
+ // Hierarchy
+ long GetChildrenCount() override;
+ ITimelineItemBinding *GetChild(long inIndex) override;
+ ITimelineItemBinding *GetParent() override;
+ void SetParent(ITimelineItemBinding *parent) override;
+ // Properties
+ long GetPropertyCount() override;
+ ITimelineItemProperty *GetProperty(long inIndex) override;
+ // Eye/Lock toggles
+ bool ShowToggleControls() const override;
+ bool IsLockedEnabled() const override;
+ bool IsVisibleEnabled() const override;
+ // Init/Cleanup
+ void Bind(CBaseStateRow *inRow) override;
+ void Release() override;
+ // ContextMenu
+ bool IsValidTransaction(EUserTransaction inTransaction) override;
+ void PerformTransaction(EUserTransaction inTransaction) override;
+ Q3DStudio::CString GetObjectPath() override;
+ // Selected keyframes
+ ITimelineKeyframesManager *GetKeyframesManager() const override;
+ // Properties
+ void RemoveProperty(ITimelineItemProperty *inProperty) override;
+ void LoadProperties() override;
+
+ // ITimelineItemKeyframesHolder
+ void InsertKeyframe() override;
+ void DeleteAllChannelKeyframes() override;
+ long GetKeyframeCount() const override;
+ IKeyframe *GetKeyframeByTime(long inTime) const override;
+ IKeyframe *GetKeyframeByIndex(long inIndex) const override;
+ long OffsetSelectedKeyframes(long inOffset) override;
+ void CommitChangedKeyframes() override;
+ void OnEditKeyframeTime(long inCurrentTime, long inObjectAssociation) override;
+
+ // IKeyframeSelector
+ void SelectKeyframes(bool inSelected, long inTime = -1) override;
+
+ // IUICDMSelectable
+ virtual UICDM::CUICDMInstanceHandle GetInstanceHandle() const;
+
+ // IDragable
+ long GetFlavor() const override;
+
+ void OnBeginDataModelNotifications() override;
+ void OnEndDataModelNotifications() override;
+ void OnImmediateRefreshInstanceSingle(UICDM::CUICDMInstanceHandle inInstance) override;
+ void OnImmediateRefreshInstanceMultiple(UICDM::CUICDMInstanceHandle *inInstance,
+ long inInstanceCount) override;
+ void RefreshStateRow(bool inRefreshChildren = false);
+
+ virtual void AddPropertyRow(UICDM::CUICDMPropertyHandle inPropertyHandle,
+ bool inAppend = false);
+ virtual void RemovePropertyRow(UICDM::CUICDMPropertyHandle inPropertyHandle);
+ virtual void RefreshPropertyKeyframe(UICDM::CUICDMPropertyHandle inPropertyHandle,
+ UICDM::CUICDMKeyframeHandle,
+ ETimelineKeyframeTransaction inTransaction);
+ virtual void OnPropertyChanged(UICDM::CUICDMPropertyHandle inPropertyHandle);
+ virtual void OnPropertyLinked(UICDM::CUICDMPropertyHandle inPropertyHandle);
+
+ virtual void UIRefreshPropertyKeyframe(long inOffset);
+ // Keyframe manipulation
+ virtual bool HasDynamicKeyframes(long inTime);
+ virtual void SetDynamicKeyframes(long inTime, bool inDynamic);
+ virtual void DoSelectKeyframes(bool inSelected, long inTime, bool inUpdateUI);
+ virtual void OnPropertySelection(long inTime);
+
+ virtual void OnAddChild(UICDM::CUICDMInstanceHandle inInstance);
+ virtual void OnDeleteChild(UICDM::CUICDMInstanceHandle inInstance);
+
+ void UpdateActionStatus();
+
+ Q3DStudio::CId GetGuid() const;
+
+ // Bridge between asset & UICDM. Ideally we should be fully UICDM
+ virtual UICDM::CUICDMInstanceHandle GetInstance() const;
+
+protected:
+ virtual ITimelineTimebar *CreateTimelineTimebar();
+ ITimelineItemProperty *GetPropertyBinding(UICDM::CUICDMPropertyHandle inPropertyHandle);
+ ITimelineItemProperty *GetOrCreatePropertyBinding(UICDM::CUICDMPropertyHandle inPropertyHandle);
+ void RemoveAllPropertyBindings();
+ void AddKeyframes(ITimelineItemProperty *inPropertyBinding);
+ bool
+ DeleteAssetKeyframesWhereApplicable(ITimelineItemProperty *inTriggerPropertyBinding = nullptr);
+ void UpdateKeyframe(IKeyframe *inKeyframe, ETimelineKeyframeTransaction inTransaction);
+
+ // For iterating through children
+ virtual bool AmITimeParent() const { return false; }
+
+ // subclasses can call this method to open referenced files
+ virtual bool OpenSourcePathFile();
+};
+
+#endif // INCLUDED_UICDM_TIMELINEITEM_BINDING_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.cpp
new file mode 100644
index 00000000..c09fca25
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.cpp
@@ -0,0 +1,579 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "UICDMTimelineItemProperty.h"
+#include "PropertyRow.h"
+#include "TimelineTranslationManager.h"
+#include "ITimelineItemBinding.h"
+#include "PropertyTimebarRow.h"
+#include "UICDMTimelineItemBinding.h"
+#include "UICDMTimelineKeyframe.h"
+#include "KeyframesManager.h"
+#include "CmdDataModelChangeKeyframe.h"
+#include "CmdDataModelRemoveKeyframe.h"
+#include "StudioApp.h"
+#include "Core.h"
+
+// Link to data model
+#include "TimeEditDlg.h"
+#include "ClientDataModelBridge.h"
+#include "UICDMSlides.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMAnimation.h"
+#include "UICDMMetaData.h"
+#include "UICDMPropertyDefinition.h"
+#include "UICDMDataCore.h"
+#include "StudioFullSystem.h"
+#include <boost/bind.hpp>
+using namespace UICDM;
+
+bool SortKeyframeByTime(const CUICDMTimelineKeyframe *inLHS, const CUICDMTimelineKeyframe *inRHS)
+{
+ return inLHS->GetTime() < inRHS->GetTime();
+}
+
+// UICDM stores it from 0..1, UI expects 0..255
+inline float UICDMToColor(float inValue)
+{
+ return inValue * 255;
+}
+
+CUICDMTimelineItemProperty::CUICDMTimelineItemProperty(CTimelineTranslationManager *inTransMgr,
+ CUICDMPropertyHandle inPropertyHandle,
+ CUICDMInstanceHandle inInstance)
+ : m_Row(nullptr)
+ , m_InstanceHandle(inInstance)
+ , m_PropertyHandle(inPropertyHandle)
+ , m_TransMgr(inTransMgr)
+ , m_SetKeyframeValueCommand(nullptr)
+{
+ // Cache all the animation handles because we need them for any keyframes manipulation.
+ // the assumption is that all associated handles are created all at once (i.e. we do not need to
+ // add or delete from this list )
+ CreateKeyframes();
+ InitializeCachedVariables(inInstance);
+ m_Signals.push_back(
+ m_TransMgr->GetStudioSystem()->GetFullSystem()->GetSignalProvider()->ConnectPropertyLinked(
+ boost::bind(&CUICDMTimelineItemProperty::OnPropertyLinkStatusChanged, this, _1, _2,
+ _3)));
+
+ m_Signals.push_back(
+ m_TransMgr->GetStudioSystem()
+ ->GetFullSystem()
+ ->GetSignalProvider()
+ ->ConnectPropertyUnlinked(boost::bind(
+ &CUICDMTimelineItemProperty::OnPropertyLinkStatusChanged, this, _1, _2, _3)));
+}
+
+CUICDMTimelineItemProperty::~CUICDMTimelineItemProperty()
+{
+ ReleaseKeyframes();
+ Release();
+}
+
+void CUICDMTimelineItemProperty::CreateKeyframes()
+{
+ // Cache all the animation handles because we need them for any keyframes manipulation.
+ // the assumption is that all associated handles are created all at once (i.e. we do not need to
+ // add or delete from this list )
+ UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem();
+ DataModelDataType::Value theDataType = thePropertySystem->GetDataType(m_PropertyHandle);
+ IStudioAnimationSystem *theAnimationSystem =
+ m_TransMgr->GetStudioSystem()->GetAnimationSystem();
+ std::tuple<bool, size_t> theArity = GetDatatypeAnimatableAndArity(theDataType);
+ for (size_t i = 0; i < std::get<1>(theArity); ++i) {
+ CUICDMAnimationHandle theAnimationHandle =
+ theAnimationSystem->GetControllingAnimation(m_InstanceHandle, m_PropertyHandle, i);
+ if (theAnimationHandle.Valid())
+ m_AnimationHandles.push_back(theAnimationHandle);
+ }
+ if (!m_AnimationHandles.empty()) { // update wrappers for keyframes
+ IAnimationCore *theAnimationCore = m_TransMgr->GetStudioSystem()->GetAnimationCore();
+ TKeyframeHandleList theKeyframes;
+ // all channels have keyframes at the same time
+ theAnimationCore->GetKeyframes(m_AnimationHandles[0], theKeyframes);
+ for (size_t i = 0; i < theKeyframes.size(); ++i)
+ CreateKeyframeIfNonExistent(theKeyframes[i], m_AnimationHandles[0]);
+ }
+}
+
+void CUICDMTimelineItemProperty::ReleaseKeyframes()
+{
+ // clear any selection from m_TransMgr
+ TKeyframeList::iterator theIter = m_Keyframes.begin();
+ for (; theIter != m_Keyframes.end(); ++theIter) {
+ m_TransMgr->GetKeyframesManager()->SetKeyframeSelected(*theIter, false);
+
+ SAFE_DELETE(*theIter);
+ }
+ m_Keyframes.clear();
+ m_AnimationHandles.clear();
+}
+
+// Type doesn't change and due to the logic required to figure this out, cache it.
+void CUICDMTimelineItemProperty::InitializeCachedVariables(UICDM::CUICDMInstanceHandle inInstance)
+{
+ using namespace Q3DStudio;
+ UICDM::IPropertySystem *thePropertySystem = m_TransMgr->GetStudioSystem()->GetPropertySystem();
+
+ m_Type.first = thePropertySystem->GetDataType(m_PropertyHandle);
+ m_Type.second = thePropertySystem->GetAdditionalMetaDataType(inInstance, m_PropertyHandle);
+
+ // Name doesn't change either.
+ TCharStr theFormalName = thePropertySystem->GetFormalName(inInstance, m_PropertyHandle);
+
+ if (theFormalName.empty()) // fallback on property name
+ theFormalName = thePropertySystem->GetName(m_PropertyHandle);
+ m_Name = theFormalName.c_str();
+}
+
+Q3DStudio::CString CUICDMTimelineItemProperty::GetName() const
+{
+ return m_Name;
+}
+
+// Helper function to retrieve the parent binding class.
+inline ITimelineItemBinding *GetParentBinding(CPropertyRow *inRow)
+{
+ ITimelineItemBinding *theParentBinding = nullptr;
+ if (inRow) {
+ CBaseStateRow *theParentRow = inRow->GetParentRow();
+ if (theParentRow) {
+ theParentBinding = theParentRow->GetTimelineItemBinding();
+ ASSERT(theParentBinding); // TimelineItemBinding should be set properly during
+ // CBaseStateRow::Initialize
+ }
+ }
+ return theParentBinding;
+}
+
+bool CUICDMTimelineItemProperty::IsMaster() const
+{
+ if (m_Row) {
+ if (CUICDMTimelineItemBinding *theParentBinding =
+ dynamic_cast<CUICDMTimelineItemBinding *>(GetParentBinding(m_Row)))
+ return m_TransMgr->GetDoc()->GetDocumentReader().IsPropertyLinked(
+ theParentBinding->GetInstanceHandle(), m_PropertyHandle);
+ }
+ return false;
+}
+
+UICDM::TDataTypePair CUICDMTimelineItemProperty::GetType() const
+{
+ return m_Type;
+}
+
+void CompareAndSet(const CUICDMTimelineKeyframe *inKeyframe, float &outRetValue, bool inGreaterThan)
+{
+ float theValue = (inGreaterThan) ? inKeyframe->GetMaxValue() : inKeyframe->GetMinValue();
+ if ((inGreaterThan && theValue > outRetValue) || (!inGreaterThan && theValue < outRetValue))
+ outRetValue = theValue;
+}
+
+// return the max value of the current set of keyframes
+float CUICDMTimelineItemProperty::GetMaximumValue() const
+{
+ float theRetVal = FLT_MIN;
+ do_all(m_Keyframes, boost::bind(CompareAndSet, _1, boost::ref(theRetVal), true));
+ if (m_Type.first == DataModelDataType::Float3 && m_Type.second == AdditionalMetaDataType::Color)
+ theRetVal = UICDMToColor(theRetVal);
+ return theRetVal;
+}
+
+// return the min value of the current set of keyframes
+float CUICDMTimelineItemProperty::GetMinimumValue() const
+{
+ float theRetVal = FLT_MAX;
+ do_all(m_Keyframes, boost::bind(CompareAndSet, _1, boost::ref(theRetVal), false));
+ if (m_Type.first == DataModelDataType::Float3 && m_Type.second == AdditionalMetaDataType::Color)
+ theRetVal = UICDMToColor(theRetVal);
+ return theRetVal;
+}
+
+void CUICDMTimelineItemProperty::Bind(CPropertyRow *inRow)
+{
+ ASSERT(!m_Row);
+
+ m_Row = inRow;
+}
+
+void CUICDMTimelineItemProperty::Release()
+{
+ m_Row = nullptr;
+}
+
+// Ensures the object that owns this property is selected.
+void CUICDMTimelineItemProperty::SetSelected()
+{
+ if (m_Row) {
+ ITimelineItemBinding *theParentBinding = GetParentBinding(m_Row);
+ if (theParentBinding)
+ theParentBinding->SetSelected(false);
+ }
+}
+
+void CUICDMTimelineItemProperty::ClearKeySelection()
+{
+ m_TransMgr->ClearKeyframeSelection();
+}
+
+void CUICDMTimelineItemProperty::DeleteAllKeys()
+{
+ if (m_Keyframes.empty())
+ return;
+
+ using namespace Q3DStudio;
+
+ ScopedDocumentEditor editor(*m_TransMgr->GetDoc(), L"Delete All Keyframes", __FILE__, __LINE__);
+ for (size_t idx = 0, end = m_AnimationHandles.size(); idx < end; ++idx)
+ editor->DeleteAllKeyframes(m_AnimationHandles[idx]);
+}
+
+ITimelineKeyframesManager *CUICDMTimelineItemProperty::GetKeyframesManager() const
+{
+ return m_TransMgr->GetKeyframesManager();
+}
+
+IKeyframe *CUICDMTimelineItemProperty::GetKeyframeByTime(long inTime) const
+{
+ std::vector<long> theTest;
+ TKeyframeList::const_iterator theIter = m_Keyframes.begin();
+ for (; theIter != m_Keyframes.end(); ++theIter) {
+ if ((*theIter)->GetTime() == inTime)
+ return (*theIter);
+
+ theTest.push_back((*theIter)->GetTime());
+ }
+ // if key had been deleted, this returns nullptr
+ return nullptr;
+}
+
+IKeyframe *CUICDMTimelineItemProperty::GetKeyframeByIndex(long inIndex) const
+{
+ if (inIndex >= 0 && inIndex < (long)m_Keyframes.size())
+ return m_Keyframes[inIndex];
+
+ ASSERT(0); // should not happen
+ return nullptr;
+}
+
+long CUICDMTimelineItemProperty::GetKeyframeCount() const
+{
+ // this list is updated in constructor and when keyframes are added or deleted.
+ return (long)m_Keyframes.size();
+}
+
+long CUICDMTimelineItemProperty::GetChannelCount() const
+{
+ return (long)m_AnimationHandles.size();
+}
+
+float CUICDMTimelineItemProperty::GetChannelValueAtTime(long inChannelIndex, long inTime)
+{
+ // if no keyframes, get current property value.
+ if (m_Keyframes.empty()) {
+ CUICDMTimelineItemBinding *theParentBinding =
+ dynamic_cast<CUICDMTimelineItemBinding *>(GetParentBinding(m_Row));
+ if (theParentBinding) {
+
+ SValue theValue;
+ UICDM::IPropertySystem *thePropertySystem =
+ m_TransMgr->GetStudioSystem()->GetPropertySystem();
+ thePropertySystem->GetInstancePropertyValue(theParentBinding->GetInstanceHandle(),
+ m_PropertyHandle, theValue);
+ switch (m_Type.first) {
+ case DataModelDataType::Float3: {
+ if (m_Type.second == AdditionalMetaDataType::Color) {
+ SFloat3 theFloat3 = UICDM::get<SFloat3>(theValue);
+ if (inChannelIndex >= 0 && inChannelIndex < 3)
+ return UICDMToColor(theFloat3[inChannelIndex]);
+ } else {
+ SFloat3 theFloat3 = UICDM::get<SFloat3>(theValue);
+ if (inChannelIndex >= 0 && inChannelIndex < 3)
+ return theFloat3[inChannelIndex];
+ }
+ break;
+ }
+ case DataModelDataType::Float2: {
+ SFloat2 theFloat2 = UICDM::get<SFloat2>(theValue);
+ if (inChannelIndex >= 0 && inChannelIndex < 2)
+ return theFloat2[inChannelIndex];
+ break;
+ }
+ case DataModelDataType::Float:
+ return UICDM::get<float>(theValue);
+ break;
+ default: // TODO: handle other types
+ break;
+ }
+ }
+ }
+ IAnimationCore *theAnimationCore = m_TransMgr->GetStudioSystem()->GetAnimationCore();
+ if (!m_AnimationHandles.empty() && inChannelIndex >= 0
+ && inChannelIndex < (long)m_AnimationHandles.size()) {
+ float theValue = theAnimationCore->EvaluateAnimation(
+ m_AnimationHandles[inChannelIndex], CUICDMTimelineKeyframe::GetTimeInSecs(inTime));
+ if (m_Type.first == DataModelDataType::Float3
+ && m_Type.second == AdditionalMetaDataType::Color)
+ theValue = UICDMToColor(theValue);
+
+ return theValue;
+ }
+ return 0.f;
+}
+
+void CUICDMTimelineItemProperty::SetChannelValueAtTime(long inChannelIndex, long inTime,
+ float inValue)
+{
+ using namespace boost;
+ CUICDMTimelineKeyframe *theKeyframeWrapper =
+ dynamic_cast<CUICDMTimelineKeyframe *>(GetKeyframeByTime(inTime));
+ if (theKeyframeWrapper) {
+ CUICDMTimelineKeyframe::TKeyframeHandleList theKeyframes;
+ theKeyframeWrapper->GetKeyframeHandles(theKeyframes);
+ if (!theKeyframes.empty() && inChannelIndex < (long)theKeyframes.size()) {
+ inValue /= 255;
+ if (!m_SetKeyframeValueCommand)
+ m_SetKeyframeValueCommand = new CCmdDataModelSetKeyframeValue(
+ g_StudioApp.GetCore()->GetDoc(), theKeyframes[inChannelIndex], inValue);
+ m_SetKeyframeValueCommand->Update(inValue);
+ }
+ }
+}
+
+long CUICDMTimelineItemProperty::OffsetSelectedKeyframes(long inOffset)
+{
+ long theRetVal = m_TransMgr->GetKeyframesManager()->OffsetSelectedKeyframes(inOffset);
+ if (m_Row) // UI update, since the data model sends no event while the change isn't commited.
+ {
+ m_Row->Refresh();
+ }
+ return theRetVal;
+}
+
+void CUICDMTimelineItemProperty::CommitChangedKeyframes()
+{
+ if (m_SetKeyframeValueCommand) { // if this is moving a keyframe value
+ g_StudioApp.GetCore()->ExecuteCommand(m_SetKeyframeValueCommand, false);
+ m_SetKeyframeValueCommand = nullptr;
+ } else // otherwise its changing keyframe times
+ m_TransMgr->GetKeyframesManager()->CommitChangedKeyframes();
+}
+
+void CUICDMTimelineItemProperty::OnEditKeyframeTime(long inCurrentTime, long inObjectAssociation)
+{
+ (void)inObjectAssociation;
+ CTimeEditDlg theTimeEditDlg;
+ theTimeEditDlg.SetKeyframesManager(m_TransMgr->GetKeyframesManager());
+ theTimeEditDlg.ShowDialog(inCurrentTime, 0, g_StudioApp.GetCore()->GetDoc(), ASSETKEYFRAME);
+}
+
+void CUICDMTimelineItemProperty::SelectKeyframes(bool inSelected, long inTime /*= -1 */)
+{
+ CUICDMTimelineItemBinding *theParent =
+ dynamic_cast<CUICDMTimelineItemBinding *>(GetParentBinding(m_Row));
+ DoSelectKeyframes(inSelected, inTime, false, theParent);
+}
+
+CPropertyRow *CUICDMTimelineItemProperty::GetRow()
+{
+ return m_Row;
+}
+
+bool CUICDMTimelineItemProperty::IsDynamicAnimation()
+{
+ return m_Keyframes.size() > 0 && m_Keyframes[0]->IsDynamic();
+}
+
+//=============================================================================
+/**
+ * For updating the UI when keyframes are added/updated/deleted.
+ */
+bool CUICDMTimelineItemProperty::RefreshKeyframe(UICDM::CUICDMKeyframeHandle inKeyframe,
+ ETimelineKeyframeTransaction inTransaction)
+{
+ bool theHandled = false;
+ switch (inTransaction) {
+ case ETimelineKeyframeTransaction_Delete: {
+ TKeyframeList::iterator theIter = m_Keyframes.begin();
+ for (; theIter != m_Keyframes.end(); ++theIter) {
+ CUICDMTimelineKeyframe *theKeyframe = *theIter;
+ if (theKeyframe->HasKeyframeHandle(inKeyframe)) { // clear selection
+ m_TransMgr->GetKeyframesManager()->SetKeyframeSelected(theKeyframe, false);
+ m_Keyframes.erase(theIter);
+
+ theHandled = true;
+ break;
+ }
+ }
+ } break;
+ case ETimelineKeyframeTransaction_Add: {
+ ASSERT(!m_AnimationHandles.empty());
+ IAnimationCore *theAnimationCore = m_TransMgr->GetStudioSystem()->GetAnimationCore();
+ CUICDMAnimationHandle theAnimationHandle =
+ theAnimationCore->GetAnimationForKeyframe(inKeyframe);
+ // only create for the first animation handle.
+ if (theAnimationHandle == m_AnimationHandles[0]) { // for undo/redo, the keyframes can be
+ // added in reverse, hence the need to
+ // sort
+ if (CreateKeyframeIfNonExistent(inKeyframe, theAnimationHandle))
+ std::stable_sort(m_Keyframes.begin(), m_Keyframes.end(), SortKeyframeByTime);
+ theHandled = true;
+ }
+ } break;
+ case ETimelineKeyframeTransaction_Update:
+ case ETimelineKeyframeTransaction_DynamicChanged:
+ theHandled = true;
+ break;
+ default:
+ return false;
+ }
+ if (theHandled && m_Row)
+ m_Row->Refresh();
+
+ return theHandled;
+}
+
+IKeyframe *CUICDMTimelineItemProperty::GetKeyframeByHandle(UICDM::CUICDMKeyframeHandle inKeyframe)
+{
+ TKeyframeList::iterator theIter = m_Keyframes.begin();
+ for (; theIter != m_Keyframes.end(); ++theIter) {
+ CUICDMTimelineKeyframe *theKeyframe = *theIter;
+ if (theKeyframe->HasKeyframeHandle(inKeyframe))
+ return *theIter;
+ }
+ return nullptr;
+}
+
+// This is either triggered from this property's keyframe selection OR from a parent's keyframe
+// selection.
+void CUICDMTimelineItemProperty::DoSelectKeyframes(bool inSelected, long inTime,
+ bool inParentTriggered,
+ CUICDMTimelineItemBinding *inParent)
+{
+ // this is what it used to do before the refactor. selecting a keyframe always selects the
+ // asset.
+ if (inSelected)
+ SetSelected();
+
+ if (!inParent)
+ return;
+
+ if (inTime == -1) // all keyframes
+ {
+ TKeyframeList::iterator theIter = m_Keyframes.begin();
+ for (; theIter != m_Keyframes.end(); ++theIter) {
+ (*theIter)->SetSelected(inSelected);
+ m_TransMgr->GetKeyframesManager()->SetKeyframeSelected(*theIter, inSelected, inParent);
+ }
+ } else {
+ CUICDMTimelineKeyframe *theKeyframe =
+ dynamic_cast<CUICDMTimelineKeyframe *>(GetKeyframeByTime(inTime));
+ if (theKeyframe) {
+ theKeyframe->SetSelected(inSelected);
+ m_TransMgr->GetKeyframesManager()->SetKeyframeSelected(theKeyframe, inSelected,
+ inParent);
+ }
+ }
+ // Requires UI to be updated explicitly
+ if (inParentTriggered && m_Row)
+ m_Row->GetTimebar()->SelectKeysByTime(inTime, inSelected);
+
+ // Support existing feature, selection by mouse-drag a rect, when all property keyframes are
+ // selected, the asset keyframe is automatically selected as well.
+ // and the mouse drags 'outside' a keyframe and de-selecting it, the asset keyframe has to be
+ // deselected as well.
+ if (!inParentTriggered && inTime != -1)
+ inParent->OnPropertySelection(inTime);
+}
+
+//=============================================================================
+/**
+ * Create a wrapper for this keyframe if doesn't exists.
+ * @return true if created, false if already exists.
+ */
+bool CUICDMTimelineItemProperty::CreateKeyframeIfNonExistent(
+ UICDM::CUICDMKeyframeHandle inKeyframeHandle, CUICDMAnimationHandle inOwningAnimation)
+{
+ TKeyframeList::iterator theIter = m_Keyframes.begin();
+ for (; theIter != m_Keyframes.end(); ++theIter) {
+ CUICDMTimelineKeyframe *theKeyframe = *theIter;
+ if (theKeyframe->HasKeyframeHandle(inKeyframeHandle))
+ return false;
+ }
+ // check for multiple channels => only create 1 CUICDMTimelineKeyframe
+ CUICDMTimelineKeyframe *theNewKeyframe =
+ new CUICDMTimelineKeyframe(g_StudioApp.GetCore()->GetDoc());
+ theNewKeyframe->AddKeyframeHandle(inKeyframeHandle);
+ if (m_AnimationHandles.size()
+ > 1) { // assert assumption that is only called for the first handle
+ ASSERT(m_AnimationHandles[0] == inOwningAnimation);
+ IAnimationCore *theAnimationCore = m_TransMgr->GetStudioSystem()->GetAnimationCore();
+ float theKeyframeTime = KeyframeTime(theAnimationCore->GetKeyframeData(inKeyframeHandle));
+ for (size_t i = 1; i < m_AnimationHandles.size(); ++i) {
+ TKeyframeHandleList theKeyframes;
+ theAnimationCore->GetKeyframes(m_AnimationHandles[i], theKeyframes);
+ // the data model ensures that there is only 1 keyframe created for a given time
+ for (size_t theKeyIndex = 0; theKeyIndex < theKeyframes.size(); ++theKeyIndex) {
+ float theValue =
+ KeyframeTime(theAnimationCore->GetKeyframeData(theKeyframes[theKeyIndex]));
+ if (theValue == theKeyframeTime) {
+ theNewKeyframe->AddKeyframeHandle(theKeyframes[theKeyIndex]);
+ break;
+ }
+ }
+ }
+ }
+ m_Keyframes.push_back(theNewKeyframe);
+ return true;
+}
+
+void CUICDMTimelineItemProperty::OnPropertyLinkStatusChanged(UICDM::CUICDMSlideHandle inSlide,
+ UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMPropertyHandle inProperty)
+{
+ if (inInstance == m_InstanceHandle && inProperty == m_PropertyHandle) {
+ // Re-bind to keyframes because the ones we should be pointing to will have changed.
+ ReleaseKeyframes();
+ CreateKeyframes();
+ }
+}
+
+void CUICDMTimelineItemProperty::RefreshKeyFrames(void)
+{
+ std::stable_sort(m_Keyframes.begin(), m_Keyframes.end(), SortKeyframeByTime);
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.h
new file mode 100644
index 00000000..ddd4b647
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_UICDMTIMELINE_ITEM_PROPERTY_H
+#define INCLUDED_UICDMTIMELINE_ITEM_PROPERTY_H 1
+
+#pragma once
+
+#include "ITimelineItemProperty.h"
+#include "UICDMTimelineKeyframe.h"
+#include "UICDMTimeline.h"
+#include "UICDMPropertyDefinition.h"
+
+class CTimelineTranslationManager;
+class CCmdDataModelSetKeyframeValue;
+class CUICDMTimelineItemBinding;
+
+//=============================================================================
+/**
+ * A data model item's property.
+ * Typically only animated properties show up in the Timeline.
+ */
+//=============================================================================
+class CUICDMTimelineItemProperty : public ITimelineItemProperty
+{
+public:
+ CUICDMTimelineItemProperty(CTimelineTranslationManager *inTransMgr,
+ UICDM::CUICDMPropertyHandle inPropertyHandle,
+ UICDM::CUICDMInstanceHandle inInstance);
+ virtual ~CUICDMTimelineItemProperty();
+
+ // ITimelineProperty
+ Q3DStudio::CString GetName() const override;
+ bool IsMaster() const override;
+ UICDM::TDataTypePair GetType() const override;
+ float GetMaximumValue() const override;
+ float GetMinimumValue() const override;
+ void SetSelected() override;
+ void ClearKeySelection() override;
+ void DeleteAllKeys() override;
+ ITimelineKeyframesManager *GetKeyframesManager() const override;
+ IKeyframe *GetKeyframeByTime(long inTime) const override;
+ IKeyframe *GetKeyframeByIndex(long inIndex) const override;
+ long GetKeyframeCount() const override;
+ long GetChannelCount() const override;
+ float GetChannelValueAtTime(long inChannelIndex, long inTime) override;
+ void SetChannelValueAtTime(long inChannelIndex, long inTime, float inValue) override;
+ long OffsetSelectedKeyframes(long inOffset) override;
+ void CommitChangedKeyframes() override;
+ void OnEditKeyframeTime(long inCurrentTime, long inObjectAssociation) override;
+ bool IsDynamicAnimation() override;
+ // IKeyframeSelector
+ void SelectKeyframes(bool inSelected, long inTime = -1) override;
+
+ void Bind(CPropertyRow *inRow) override;
+ void Release() override;
+ CPropertyRow *GetRow() override;
+
+ bool RefreshKeyframe(UICDM::CUICDMKeyframeHandle inKeyframe,
+ ETimelineKeyframeTransaction inTransaction);
+ IKeyframe *GetKeyframeByHandle(UICDM::CUICDMKeyframeHandle inKeyframe);
+ void DoSelectKeyframes(bool inSelected, long inTime, bool inParentTriggered,
+ CUICDMTimelineItemBinding *inParent);
+
+ void RefreshKeyFrames(void);
+
+protected:
+ void InitializeCachedVariables(UICDM::CUICDMInstanceHandle inInstance);
+ bool CreateKeyframeIfNonExistent(UICDM::CUICDMKeyframeHandle inKeyframe,
+ UICDM::CUICDMAnimationHandle inOwningAnimation);
+ void OnPropertyLinkStatusChanged(UICDM::CUICDMSlideHandle inSlide,
+ UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMPropertyHandle inProperty);
+ void CreateKeyframes();
+ void ReleaseKeyframes();
+
+protected:
+ typedef std::vector<CUICDMTimelineKeyframe *> TKeyframeList;
+
+ CPropertyRow *m_Row;
+ UICDM::CUICDMInstanceHandle m_InstanceHandle;
+ UICDM::CUICDMPropertyHandle m_PropertyHandle;
+ CTimelineTranslationManager *m_TransMgr;
+ std::vector<UICDM::CUICDMAnimationHandle> m_AnimationHandles;
+ TKeyframeList m_Keyframes;
+ CCmdDataModelSetKeyframeValue
+ *m_SetKeyframeValueCommand; // for merging modifying keyframe values via graph
+ UICDM::TDataTypePair m_Type;
+ Q3DStudio::CString m_Name;
+ std::vector<std::shared_ptr<UICDM::ISignalConnection>> m_Signals;
+};
+
+#endif // INCLUDED_UICDMTIMELINE_ITEM_PROPERTY_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.cpp
new file mode 100644
index 00000000..c29062a2
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.cpp
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+#include "UICDMTimelineKeyframe.h"
+#include "UICDMAnimation.h"
+#include "CmdDataModelChangeKeyframe.h"
+#include "CmdBatch.h"
+#include "UICDMStudioSystem.h"
+#include "OffsetKeyframesCommandHelper.h"
+
+#include "Doc.h"
+#include "StudioApp.h"
+#include "Core.h"
+
+using namespace UICDM;
+
+// TODO: figure out if we can just use IDoc instead of CDoc
+CUICDMTimelineKeyframe::CUICDMTimelineKeyframe(IDoc *inDoc)
+ : m_Doc(dynamic_cast<CDoc *>(inDoc))
+ , m_Selected(false)
+{
+}
+
+CUICDMTimelineKeyframe::~CUICDMTimelineKeyframe()
+{
+}
+
+bool CUICDMTimelineKeyframe::IsSelected() const
+{
+ return m_Selected;
+}
+
+float my_roundf(float r)
+{
+ return (r > 0.0f) ? floorf(r + 0.5f) : ceilf(r - 0.5f);
+}
+
+long CUICDMTimelineKeyframe::GetTime() const
+{
+ if (!m_KeyframeHandles.empty()) {
+ IAnimationCore *theAnimationCore = m_Doc->GetStudioSystem()->GetAnimationCore();
+ CUICDMKeyframeHandle theKeyframeHandle = *m_KeyframeHandles.begin();
+ if (theAnimationCore->KeyframeValid(theKeyframeHandle)) {
+ float theTimeinSecs =
+ KeyframeTime(theAnimationCore->GetKeyframeData(theKeyframeHandle));
+ // We always convert back and forth between between long and float.
+ // This causes especially issues when we do comparisons
+ return (long)my_roundf(theTimeinSecs * 1000);
+ }
+ }
+ return -1; // keyframe was deleted, and data cannot be retrieved.
+}
+
+float CUICDMTimelineKeyframe::GetTimeInSecs(long inTime)
+{
+ float theTimeinSecs = static_cast<float>(inTime) / 1000.f;
+ // round off to 4 decimal place to workaround precision issues
+ // TODO: fix this, either all talk float OR long. choose one.
+ theTimeinSecs = (float)(((theTimeinSecs + 0.00005) * 10000.0) / 10000.0f);
+ return theTimeinSecs;
+}
+
+void CUICDMTimelineKeyframe::SetTime(const long inNewTime)
+{
+ float theTimeinSecs = GetTimeInSecs(inNewTime);
+ CCmd *theCmd = nullptr;
+ if (m_KeyframeHandles.size() == 1) {
+ theCmd = new CCmdDataModelSetKeyframeTime(m_Doc, m_KeyframeHandles.front(), theTimeinSecs);
+ } else { // more than 1 channel
+ CCmdBatch *theBatch = new CCmdBatch(m_Doc);
+ TKeyframeHandleList::iterator theIter = m_KeyframeHandles.begin();
+ for (; theIter != m_KeyframeHandles.end(); ++theIter)
+ theBatch->AddCommand(new CCmdDataModelSetKeyframeTime(m_Doc, *theIter, theTimeinSecs));
+ theCmd = theBatch;
+ }
+ if (theCmd)
+ m_Doc->GetCore()->ExecuteCommand(theCmd);
+
+#ifdef _DEBUG
+ // we have a precision issue from converting from long to float..
+ IAnimationCore *theAnimationCore = m_Doc->GetStudioSystem()->GetAnimationCore();
+ long theTest = static_cast<long>(
+ KeyframeTime(theAnimationCore->GetKeyframeData(*m_KeyframeHandles.begin())) * 1000);
+ ASSERT(inNewTime == theTest);
+#endif
+}
+
+inline CUICDMAnimationHandle GetAnimationHandle(UICDM::IAnimationCore *inAnimationCore,
+ const TKeyframeHandleList &inKeyframes)
+{
+ if (!inKeyframes.empty())
+ return inAnimationCore->GetAnimationForKeyframe(inKeyframes[0]);
+ return 0;
+}
+
+void CUICDMTimelineKeyframe::SetDynamic(bool inIsDynamic)
+{
+ if (!m_KeyframeHandles.empty()) {
+ CUICDMAnimationHandle theAnimation =
+ GetAnimationHandle(m_Doc->GetStudioSystem()->GetAnimationCore(), m_KeyframeHandles);
+ if (theAnimation.Valid())
+ m_Doc->GetCore()->ExecuteCommand(
+ new CCmdDataModelChangeDynamicKeyframe(m_Doc, theAnimation, inIsDynamic));
+ }
+}
+
+// Only the first key of a track can be dynamic.
+bool CUICDMTimelineKeyframe::IsDynamic() const
+{
+ UICDM::IAnimationCore *theAnimationCore = m_Doc->GetStudioSystem()->GetAnimationCore();
+ CUICDMAnimationHandle theAnimation = GetAnimationHandle(theAnimationCore, m_KeyframeHandles);
+ if (theAnimation.Valid()) {
+ SAnimationInfo theInfo = theAnimationCore->GetAnimationInfo(theAnimation);
+ if (theInfo.m_DynamicFirstKeyframe) {
+ TKeyframeHandleList theKeyframes;
+ theAnimationCore->GetKeyframes(theAnimation, theKeyframes);
+ if (!theKeyframes.empty()) // only true if track is dynamic and this is the first
+ // keyframe. Might have to optimize because this is so
+ // clunky.
+ return (theKeyframes[0] == m_KeyframeHandles[0]);
+ }
+ }
+ return false;
+}
+
+void CUICDMTimelineKeyframe::AddKeyframeHandle(UICDM::CUICDMKeyframeHandle inHandle)
+{
+ m_KeyframeHandles.push_back(inHandle);
+}
+
+bool CUICDMTimelineKeyframe::HasKeyframeHandle(UICDM::CUICDMKeyframeHandle inHandle) const
+{
+ TKeyframeHandleList::const_iterator theIter = m_KeyframeHandles.begin();
+ for (; theIter != m_KeyframeHandles.end(); ++theIter) {
+ if (*theIter == inHandle)
+ return true;
+ }
+ return false;
+}
+
+void CUICDMTimelineKeyframe::SetSelected(bool inSelected)
+{
+ m_Selected = inSelected;
+}
+
+// For colors, there would be 3 keyframe handles
+void CUICDMTimelineKeyframe::UpdateKeyframesTime(COffsetKeyframesCommandHelper *inCommandHelper,
+ long inTime)
+{
+ for (size_t i = 0; i < m_KeyframeHandles.size(); ++i)
+ inCommandHelper->SetCommandTime(m_KeyframeHandles[i], inTime);
+}
+
+void CUICDMTimelineKeyframe::GetKeyframeHandles(TKeyframeHandleList &outList) const
+{
+ outList = m_KeyframeHandles;
+}
+
+void CompareAndSet(CUICDMKeyframeHandle inKeyframe, IAnimationCore *inAnimationCore,
+ float &outRetValue, bool inGreaterThan)
+{
+ TKeyframe theKeyframeData = inAnimationCore->GetKeyframeData(inKeyframe);
+ float theValue = KeyframeValueValue(theKeyframeData);
+ if ((inGreaterThan && theValue > outRetValue) || (!inGreaterThan && theValue < outRetValue))
+ outRetValue = theValue;
+}
+
+float CUICDMTimelineKeyframe::GetMaxValue() const
+{
+ IAnimationCore *theAnimationCore = m_Doc->GetStudioSystem()->GetAnimationCore();
+ float theRetVal = FLT_MIN;
+ do_all(m_KeyframeHandles,
+ std::bind(CompareAndSet, std::placeholders::_1, theAnimationCore,
+ std::ref(theRetVal), true));
+ return theRetVal;
+}
+
+float CUICDMTimelineKeyframe::GetMinValue() const
+{
+ IAnimationCore *theAnimationCore = m_Doc->GetStudioSystem()->GetAnimationCore();
+ float theRetVal = FLT_MAX;
+ do_all(m_KeyframeHandles,
+ std::bind(CompareAndSet, std::placeholders::_1, theAnimationCore,
+ std::ref(theRetVal), false));
+ return theRetVal;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.h
new file mode 100644
index 00000000..bb615202
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef INCLUDED_UICDMKEYFRAME_H
+#define INCLUDED_UICDMKEYFRAME_H 1
+
+#pragma once
+
+#include "IKeyframe.h"
+
+// Data model specific
+#include "UICDMHandles.h"
+
+class IDoc;
+class CDoc;
+class CCmdBatch;
+class COffsetKeyframesCommandHelper;
+
+//==============================================================================
+/**
+ * Wrapper for a keyframe in UICDM.
+ */
+//==============================================================================
+class CUICDMTimelineKeyframe : public IKeyframe
+{
+public:
+ typedef std::vector<UICDM::CUICDMKeyframeHandle> TKeyframeHandleList;
+
+protected:
+ TKeyframeHandleList
+ m_KeyframeHandles; ///< no. corresponds to the channels the animated property has.
+ CDoc *m_Doc;
+ bool m_Selected;
+
+public:
+ CUICDMTimelineKeyframe(IDoc *inDoc);
+ virtual ~CUICDMTimelineKeyframe();
+
+ // IKeyframe
+ bool IsSelected() const override;
+ long GetTime() const override;
+ void SetTime(const long inNewTime) override;
+ void SetDynamic(bool inIsDynamic) override;
+ bool IsDynamic() const override;
+
+ void AddKeyframeHandle(UICDM::CUICDMKeyframeHandle inHandle);
+ bool HasKeyframeHandle(UICDM::CUICDMKeyframeHandle inHandle) const;
+ void SetSelected(bool inSelected);
+ void UpdateKeyframesTime(COffsetKeyframesCommandHelper *inCommandHelper, long inTime);
+ void GetKeyframeHandles(TKeyframeHandleList &outList) const;
+
+ // support drawing graphs
+ float GetMaxValue() const;
+ float GetMinValue() const;
+
+ static float GetTimeInSecs(long inTime);
+};
+
+#endif // INCLUDED_UICDMKEYFRAME_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.cpp
new file mode 100644
index 00000000..2c44e438
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.cpp
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "UICDMTimelineTimebar.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMDataCore.h"
+#include "UICDMDataTypes.h"
+#include "ClientDataModelBridge.h"
+#include "TimelineTranslationManager.h"
+#include "Doc.h"
+#include "Dispatch.h"
+#include "Core.h"
+#include "TimeEditDlg.h"
+#include "IDocumentEditor.h"
+#include "BaseStateRow.h"
+#include "BaseTimebarlessRow.h"
+#include "StudioFullSystem.h"
+#include "StudioPreferences.h"
+#include "ITimelineItemBinding.h"
+
+CUICDMTimelineTimebar::CUICDMTimelineTimebar(
+ CTimelineTranslationManager *inTimelineTranslationManager,
+ UICDM::CUICDMInstanceHandle inDataHandle)
+ : Q3DStudio::CUpdateableDocumentEditor(*inTimelineTranslationManager->GetDoc())
+ , m_TimelineTranslationManager(inTimelineTranslationManager)
+ , m_PropertySystem(inTimelineTranslationManager->GetStudioSystem()->GetPropertySystem())
+ , m_DataHandle(inDataHandle)
+{
+ CClientDataModelBridge *theClientDataModelBridge =
+ inTimelineTranslationManager->GetStudioSystem()->GetClientDataModelBridge();
+ m_StartTime = theClientDataModelBridge->GetSceneAsset().m_StartTime;
+ m_EndTime = theClientDataModelBridge->GetSceneAsset().m_EndTime;
+ UICDM::SValue theValue;
+ if (m_PropertySystem->GetInstancePropertyValue(
+ m_DataHandle, theClientDataModelBridge->GetSceneAsset().m_TimebarColor, theValue)) {
+ UICDM::SFloat3 theTimebarColor = UICDM::get<UICDM::SFloat3>(theValue);
+
+ m_Color.SetRGB(static_cast<int>(theTimebarColor.m_Floats[0] * 255.0f),
+ static_cast<int>(theTimebarColor.m_Floats[1] * 255.0f),
+ static_cast<int>(theTimebarColor.m_Floats[2] * 255.0f));
+ }
+ UICDM::IStudioFullSystemSignalProvider *theProvider =
+ inTimelineTranslationManager->GetStudioSystem()->GetFullSystem()->GetSignalProvider();
+ m_PropertyChangedSignal = theProvider->ConnectInstancePropertyValue(
+ std::bind(&CUICDMTimelineTimebar::OnPropertyChanged, this,
+ std::placeholders::_1, std::placeholders::_2));
+
+ OnPropertyChanged(m_DataHandle, theClientDataModelBridge->GetSceneAsset().m_TimebarColor);
+ OnPropertyChanged(m_DataHandle, theClientDataModelBridge->GetSceneAsset().m_TimebarText);
+}
+
+void CUICDMTimelineTimebar::OnPropertyChanged(UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMPropertyHandle inProperty)
+{
+ if (m_DataHandle == inInstance) {
+ bool needsInvalidate = false;
+ UICDM::SValue theValue;
+ CClientDataModelBridge *theClientDataModelBridge =
+ m_TimelineTranslationManager->GetStudioSystem()->GetClientDataModelBridge();
+ if (inProperty == theClientDataModelBridge->GetSceneAsset().m_TimebarColor) {
+
+ if (m_PropertySystem->GetInstancePropertyValue(
+ m_DataHandle, theClientDataModelBridge->GetSceneAsset().m_TimebarColor,
+ theValue)) {
+ UICDM::SFloat3 theTimebarColor = UICDM::get<UICDM::SFloat3>(theValue);
+
+ m_Color.SetRGB(static_cast<int>(theTimebarColor.m_Floats[0] * 255.0f),
+ static_cast<int>(theTimebarColor.m_Floats[1] * 255.0f),
+ static_cast<int>(theTimebarColor.m_Floats[2] * 255.0f));
+ } else {
+ switch (theClientDataModelBridge->GetObjectType(inInstance)) {
+ case OBJTYPE_LAYER:
+ m_Color = CStudioPreferences::GetLayerTimebarColor();
+ break;
+ case OBJTYPE_BEHAVIOR:
+ m_Color = CStudioPreferences::GetBehaviorTimebarColor();
+ break;
+ case OBJTYPE_CAMERA:
+ m_Color = CStudioPreferences::GetCameraTimebarColor();
+ break;
+ case OBJTYPE_LIGHT:
+ m_Color = CStudioPreferences::GetLightTimebarColor();
+ break;
+ case OBJTYPE_MODEL:
+ m_Color = CStudioPreferences::GetModelTimebarColor();
+ break;
+ case OBJTYPE_GROUP:
+ m_Color = CStudioPreferences::GetGroupTimebarColor();
+ break;
+ case OBJTYPE_COMPONENT:
+ m_Color = CStudioPreferences::GetComponentTimebarColor();
+ break;
+ case OBJTYPE_EFFECT:
+ m_Color = CStudioPreferences::GetEffectTimebarColor();
+ break;
+ default:
+ m_Color = CStudioPreferences::GetObjectTimebarColor();
+ break;
+ }
+ }
+ needsInvalidate = true;
+ } else if (inProperty == theClientDataModelBridge->GetSceneAsset().m_TimebarText) {
+ if (m_PropertySystem->GetInstancePropertyValue(
+ m_DataHandle, theClientDataModelBridge->GetSceneAsset().m_TimebarText,
+ theValue)) {
+ UICDM::SStringRef theTimebarComment = UICDM::get<UICDM::SStringRef>(theValue);
+ m_Comment.Assign(static_cast<const wchar_t *>(theTimebarComment));
+ } else {
+ m_Comment.Assign(L"");
+ }
+ needsInvalidate = true;
+ }
+ if (needsInvalidate) {
+ ITimelineItemBinding *theBinding =
+ m_TimelineTranslationManager->GetOrCreate(inInstance);
+ if (theBinding) {
+ CBaseStateRow *theRow = theBinding->GetRow();
+ if (theRow) {
+ CBaseTimebarlessRow *theTimebar = theRow->GetTimebar();
+ theTimebar->RefreshRowMetaData();
+ }
+ }
+ }
+ }
+}
+
+CUICDMTimelineTimebar::~CUICDMTimelineTimebar()
+{
+}
+
+// TODO: Can we put this on IInstancePropertyCore?
+template <typename T>
+T GetInstancePropertyValue(UICDM::IPropertySystem *inPropertySystem,
+ UICDM::CUICDMInstanceHandle inInstanceHandle,
+ UICDM::CUICDMPropertyHandle inProperty)
+{
+ UICDM::SValue theValue;
+ inPropertySystem->GetInstancePropertyValue(inInstanceHandle, inProperty, theValue);
+ return UICDM::get<T>(theValue);
+}
+
+long CUICDMTimelineTimebar::GetStartTime() const
+{
+ return GetInstancePropertyValue<qt3ds::QT3DSI32>(m_PropertySystem, m_DataHandle, m_StartTime);
+}
+
+long CUICDMTimelineTimebar::GetEndTime() const
+{
+ return GetInstancePropertyValue<qt3ds::QT3DSI32>(m_PropertySystem, m_DataHandle, m_EndTime);
+}
+
+long CUICDMTimelineTimebar::GetDuration() const
+{
+ auto theStartTime = GetInstancePropertyValue<qt3ds::QT3DSI32>(m_PropertySystem, m_DataHandle, m_StartTime);
+ auto theEndTime = GetInstancePropertyValue<qt3ds::QT3DSI32>(m_PropertySystem, m_DataHandle, m_EndTime);
+
+ return theEndTime - theStartTime;
+}
+
+bool CUICDMTimelineTimebar::ShowHandleBars() const
+{
+ return true;
+}
+
+void CUICDMTimelineTimebar::OnBeginDrag()
+{ // Really? TODO: Figure out why this is here.
+ // ASSERT(0);
+}
+
+void CUICDMTimelineTimebar::OffsetTime(long inDiff)
+{
+ if (m_DataHandle.Valid()) {
+ ENSURE_EDITOR(L"Time Bar Move").OffsetTimeRange(m_DataHandle, inDiff);
+ m_TimelineTranslationManager->GetDoc()
+ ->GetCore()
+ ->GetDispatch()
+ ->FireImmediateRefreshInstance(m_DataHandle);
+ }
+}
+
+void CUICDMTimelineTimebar::ChangeTime(long inTime, bool inSetStart)
+{
+ if (m_DataHandle.Valid()) {
+ ENSURE_EDITOR(L"Time Bar Resize").ResizeTimeRange(m_DataHandle, inTime, inSetStart);
+ m_TimelineTranslationManager->GetDoc()
+ ->GetCore()
+ ->GetDispatch()
+ ->FireImmediateRefreshInstance(m_DataHandle);
+ }
+}
+
+void CUICDMTimelineTimebar::CommitTimeChange()
+{
+ CommitEditor();
+}
+
+void CUICDMTimelineTimebar::RollbackTimeChange()
+{
+ RollbackEditor();
+}
+
+void CUICDMTimelineTimebar::SetTimebarColor(const ::CColor &inColor)
+{
+ using namespace Q3DStudio;
+ if (inColor != m_Color) {
+ UICDM::CUICDMInstanceHandle theHandle = m_DataHandle;
+ SCOPED_DOCUMENT_EDITOR(*m_TimelineTranslationManager->GetDoc(), QObject::tr("Set Timebar Color"))
+ ->SetTimebarColor(theHandle, inColor);
+ }
+}
+
+void CUICDMTimelineTimebar::SetTimebarComment(const Q3DStudio::CString &inComment)
+{
+ using namespace Q3DStudio;
+ if (inComment != m_Comment) {
+ UICDM::CUICDMInstanceHandle theHandle = m_DataHandle;
+ SCOPED_DOCUMENT_EDITOR(*m_TimelineTranslationManager->GetDoc(), QObject::tr("Set Timebar Text"))
+ ->SetTimebarText(theHandle, inComment);
+ }
+}
+
+void CUICDMTimelineTimebar::SetTimebarTime(ITimeChangeCallback *inCallback /*= nullptr*/)
+{
+ long theStartTime = GetStartTime();
+ long theEndTime = GetEndTime();
+ CTimeEditDlg theTimeEditDlg;
+ theTimeEditDlg.ShowDialog(theStartTime, theEndTime, m_TimelineTranslationManager->GetDoc(),
+ TIMEBAR, inCallback);
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.h
new file mode 100644
index 00000000..d1441039
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#pragma once
+
+///////////////////////////////////////////////////////////////////////////////
+// Includes
+#include "ITimelineTimebar.h"
+#include "UICDMHandles.h"
+#include "IDocumentEditor.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Forwards
+class CTimelineTranslationManager;
+
+namespace Q3DStudio {
+class IDocumentEditor;
+}
+
+namespace UICDM {
+class IPropertySystem;
+class ISignalConnection;
+}
+
+//=============================================================================
+/**
+ * General timebar implementation for UICDM objects
+ */
+class CUICDMTimelineTimebar : public ITimelineTimebar, public Q3DStudio::CUpdateableDocumentEditor
+{
+public:
+ CUICDMTimelineTimebar(CTimelineTranslationManager *inTimelineTranslationManager,
+ UICDM::CUICDMInstanceHandle inDataHandle);
+ virtual ~CUICDMTimelineTimebar();
+
+protected:
+ CTimelineTranslationManager *m_TimelineTranslationManager;
+ UICDM::IPropertySystem *m_PropertySystem;
+ UICDM::CUICDMInstanceHandle m_DataHandle; // The Instance Handle for this Timeline Timeber.
+ UICDM::CUICDMPropertyHandle m_StartTime;
+ UICDM::CUICDMPropertyHandle m_EndTime;
+ ::CColor m_Color; // Timebar color
+ Q3DStudio::CString m_Comment; // Timebar comment text
+ std::shared_ptr<UICDM::ISignalConnection> m_PropertyChangedSignal;
+ void OnPropertyChanged(UICDM::CUICDMInstanceHandle inInstance,
+ UICDM::CUICDMPropertyHandle inProperty);
+
+public:
+ // ITimelineTimebar
+ long GetStartTime() const override;
+ long GetEndTime() const override;
+ long GetDuration() const override;
+ bool ShowHandleBars() const override;
+ void OnBeginDrag() override;
+ void OffsetTime(long inDiff) override;
+ void ChangeTime(long inTime, bool inSetStart) override;
+ void CommitTimeChange() override;
+ void RollbackTimeChange() override;
+ ::CColor GetTimebarColor() override { return m_Color; }
+ void SetTimebarColor(const ::CColor &inColor) override;
+ Q3DStudio::CString GetTimebarComment() override { return m_Comment; }
+ void SetTimebarComment(const Q3DStudio::CString &inComment) override;
+ void SetTimebarTime(ITimeChangeCallback *inCallback = nullptr) override;
+};
diff --git a/src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.cpp b/src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.cpp
new file mode 100644
index 00000000..fb25559a
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.cpp
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "BlankToggleControl.h"
+#include "Renderer.h"
+#include "BaseStateRow.h"
+#include "StudioPreferences.h"
+#include "HotKeys.h"
+
+CBlankToggleControl::CBlankToggleControl(CBaseStateRow *inBaseStateRow)
+ : m_StateRow(inBaseStateRow)
+ , m_Selected(false)
+{
+ m_BackgroundColor = m_StateRow->GetTimebarBackgroundColor(inBaseStateRow->GetObjectType());
+}
+
+CBlankToggleControl::~CBlankToggleControl()
+{
+}
+
+//==============================================================================
+/**
+ * Handles the drawing fo rthe toggle control
+ */
+void CBlankToggleControl::Draw(CRenderer *inRenderer)
+{
+ CRct theRect(GetSize());
+
+ // Fill in the background
+ if (!m_Selected)
+ inRenderer->FillSolidRect(theRect, m_BackgroundColor);
+ else
+ inRenderer->FillSolidRect(theRect, CStudioPreferences::GetTimelineSelectColor());
+
+ // Draw the line at the bottom of this control
+ inRenderer->PushPen(CStudioPreferences::GetTreeFloorColor());
+ inRenderer->MoveTo(CPt(0, theRect.size.y - 1));
+ inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1));
+ inRenderer->PopPen();
+
+ // Draw the line on the left side of this control
+ inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor());
+ inRenderer->MoveTo(CPt(0, 0));
+ inRenderer->LineTo(CPt(0, theRect.size.y - 1));
+ inRenderer->PopPen();
+
+ // Draw the highlight
+ inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor());
+ inRenderer->MoveTo(CPt(1, 0));
+ inRenderer->LineTo(CPt(1, theRect.size.y - 1));
+ inRenderer->PopPen();
+
+ // Draw the line on the right side of this control
+ inRenderer->PushPen(CStudioPreferences::GetButtonShadowColor());
+ inRenderer->MoveTo(CPt(theRect.size.x - 1, 0));
+ inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y - 1));
+ inRenderer->PopPen();
+}
+
+//=============================================================================
+/**
+ * Notification that the object that this row is representing has been selected.
+ */
+void CBlankToggleControl::OnSelect()
+{
+ m_Selected = true;
+
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Notification that the object that this row is representing has been deselected.
+ */
+void CBlankToggleControl::OnDeselect()
+{
+ m_Selected = false;
+
+ Invalidate();
+}
+
+//==============================================================================
+/**
+ * Handler for the OnMouseDown event
+ *
+ * @param inPoint the point where this event takes place
+ * @param inFlags the state when this event takes place.
+ */
+bool CBlankToggleControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseDown(inPoint, inFlags)) {
+ m_StateRow->Select(SBaseStateRowSelectionKeyState());
+ }
+ return true;
+}
+
+//==============================================================================
+/**
+ * Sets the background color of this toggle control
+ */
+void CBlankToggleControl::SetBackgroundColor(::CColor inBackgroundColor)
+{
+ if (m_BackgroundColor == inBackgroundColor)
+ return;
+
+ m_BackgroundColor = inBackgroundColor;
+
+ Invalidate();
+}
+
+//==============================================================================
+/**
+ * Handler for the OnMouseOver event
+ *
+ * @param inPoint the point where this event takes place
+ * @param inFlags the state when this event takes place.
+ */
+void CBlankToggleControl::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOver(inPoint, inFlags);
+
+ m_StateRow->OnMouseOver();
+}
+
+//==============================================================================
+/**
+ * Handler for the OnMouseOut event
+ *
+ * @param inPoint the point where this event takes place
+ * @param inFlags the state when this event takes place.
+ */
+void CBlankToggleControl::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOut(inPoint, inFlags);
+
+ m_StateRow->OnMouseOut();
+}
+
+void CBlankToggleControl::Refresh()
+{
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.h b/src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.h
new file mode 100644
index 00000000..2fe4ce28
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_BLANK_TOGGLE_CONTROL_H
+#define INCLUDED_BLANK_TOGGLE_CONTROL_H 1
+
+#pragma once
+
+#include "Control.h"
+#include "CColor.h"
+
+class CBaseStateRow;
+
+class CBlankToggleControl : public CControl
+{
+public:
+ CBlankToggleControl(CBaseStateRow *inStateRow);
+ virtual ~CBlankToggleControl();
+
+ void Draw(CRenderer *inRenderer) override;
+
+ void OnSelect();
+ void OnDeselect();
+
+ void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+ void SetBackgroundColor(::CColor inBackgroundColor);
+
+ virtual void Refresh();
+
+protected:
+ CBaseStateRow *m_StateRow;
+ bool m_Selected;
+
+ ::CColor m_BackgroundColor;
+};
+#endif // INCLUDED_BLANK_TOGGLE_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.cpp b/src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.cpp
new file mode 100644
index 00000000..2564d087
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "ColorBlankControl.h"
+#include "Renderer.h"
+#include "StudioPreferences.h"
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CColorBlankControl::CColorBlankControl(CColor inColor)
+ : CBlankControl(inColor)
+{
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CColorBlankControl::~CColorBlankControl()
+{
+}
+
+//=============================================================================
+/**
+ * Handles custom drawing of the blank control underneath the tree control
+ * on the timeline palette.
+ */
+void CColorBlankControl::Draw(CRenderer *inRenderer)
+{
+ CBlankControl::Draw(inRenderer);
+
+ // Draw the line on the right side of this control
+ CPt theSize = GetSize();
+ inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor());
+ inRenderer->MoveTo(theSize.x - 1, 0);
+ inRenderer->LineTo(theSize.x - 1, theSize.y - 1);
+ inRenderer->PopPen();
+
+ // Draw the line on the left side of this control
+ inRenderer->PushPen(CStudioPreferences::GetRowTopColor());
+ inRenderer->MoveTo(0, 0);
+ inRenderer->LineTo(0, theSize.y - 1);
+ inRenderer->PopPen();
+
+ // Draw the highlight on the left side of this control
+ inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor());
+ inRenderer->MoveTo(CPt(1, 0));
+ inRenderer->LineTo(CPt(1, theSize.y - 1));
+ inRenderer->PopPen();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.h b/src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.h
new file mode 100644
index 00000000..bb85b2aa
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_COLOR_BLANK_CONTROL_H
+#define INCLUDED_COLOR_BLANK_CONTROL_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "BlankControl.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CRenderer;
+
+//=============================================================================
+/**
+ * Extends the blank control to draw items specific to the tree view side of the
+ * timeline palette.
+ */
+class CColorBlankControl : public CBlankControl
+{
+public:
+ CColorBlankControl(CColor inColor = CStudioPreferences::GetBaseColor());
+ virtual ~CColorBlankControl();
+ void Draw(CRenderer *inRenderer) override;
+
+protected:
+};
+
+#endif // INCLUDED_COLOR_BLANK_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/ColorControl.cpp b/src/Authoring/Studio/Palettes/Timeline/ColorControl.cpp
new file mode 100644
index 00000000..71d1c392
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ColorControl.cpp
@@ -0,0 +1,307 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "CColor.h"
+#include "ColorControl.h"
+#include "CoreUtils.h"
+#include "BaseStateRow.h"
+#include "Renderer.h"
+#include "StudioPreferences.h"
+#include "HotKeys.h"
+#include "Dispatch.h"
+#include "ResourceCache.h"
+#include "Bindings/ITimelineItem.h"
+
+//==============================================================================
+/**
+ * The control (of each row) to the left of the tree view, where it indicates if there are
+ *actions associated with this row.
+ */
+CColorControl::CColorControl(CBaseStateRow *inRow)
+ : m_Shaded(true)
+ , m_Selected(false)
+ , m_HasAction(false)
+ , m_HasMasterAction(false)
+ , m_ChildHasAction(false)
+ , m_ChildHasMasterAction(false)
+ , m_ComponentHasAction(false)
+ , m_ComponentHasMasterAction(false)
+{
+ m_ParentRow = inRow;
+ m_BackgroundColor = m_ParentRow->GetTimebarBackgroundColor(m_ParentRow->GetObjectType());
+
+ UpdateIconStatus();
+}
+
+CColorControl::~CColorControl()
+{
+}
+
+void CColorControl::SetShaded(bool inIsShaded)
+{
+ m_Shaded = inIsShaded;
+}
+
+//==============================================================================
+/**
+ * Draw
+ *
+ * draws this object
+ *
+ * @param inRenderer a renderer object
+ */
+void CColorControl::Draw(CRenderer *inRenderer)
+{
+ CRct theRect(GetSize());
+
+ inRenderer->FillSolidRect(theRect, m_BackgroundColor);
+ //
+ inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor());
+ // bottom
+ inRenderer->MoveTo(CPt(1, theRect.size.y - 1));
+ inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y - 1));
+ // left
+ inRenderer->MoveTo(CPt(0, 1));
+ inRenderer->LineTo(CPt(0, theRect.size.y - 1));
+ // right
+ inRenderer->MoveTo(CPt(theRect.size.x - 1, 1));
+ inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y - 1));
+ //
+ inRenderer->PopPen();
+
+ CPt thePos(0, 0);
+ if (m_HasMasterAction) {
+ if (m_ActionImages[IMAGETYPE_MASTERACTION].isNull())
+ m_ActionImages[IMAGETYPE_MASTERACTION] =
+ CResourceCache::GetInstance()->GetBitmap("Action-MasterAction.png");
+
+ inRenderer->DrawBitmap(thePos, m_ActionImages[IMAGETYPE_MASTERACTION]);
+ } else if (m_HasAction) {
+ if (m_ActionImages[IMAGETYPE_ACTION].isNull())
+ m_ActionImages[IMAGETYPE_ACTION] =
+ CResourceCache::GetInstance()->GetBitmap("Action-Action.png");
+
+ inRenderer->DrawBitmap(thePos, m_ActionImages[IMAGETYPE_ACTION]);
+ }
+ if (m_ChildHasMasterAction) {
+ if (m_ActionImages[IMAGETYPE_CHILDMASTERACTION].isNull())
+ m_ActionImages[IMAGETYPE_CHILDMASTERACTION] =
+ CResourceCache::GetInstance()->GetBitmap("Action-ChildMasterAction.png");
+
+ inRenderer->DrawBitmap(thePos, m_ActionImages[IMAGETYPE_CHILDMASTERACTION]);
+ } else if (m_ChildHasAction) {
+ if (m_ActionImages[IMAGETYPE_CHILDACTION].isNull())
+ m_ActionImages[IMAGETYPE_CHILDACTION] =
+ CResourceCache::GetInstance()->GetBitmap("Action-ChildAction.png");
+
+ inRenderer->DrawBitmap(thePos, m_ActionImages[IMAGETYPE_CHILDACTION]);
+ }
+ if (m_ComponentHasMasterAction) {
+ if (m_ActionImages[IMAGETYPE_COMPONENTMASTERACTION].isNull())
+ m_ActionImages[IMAGETYPE_COMPONENTMASTERACTION] =
+ CResourceCache::GetInstance()->GetBitmap("Action-ComponentMasterAction.png");
+
+ inRenderer->DrawBitmap(thePos, m_ActionImages[IMAGETYPE_COMPONENTMASTERACTION]);
+ } else if (m_ComponentHasAction) {
+ if (m_ActionImages[IMAGETYPE_COMPONENTACTION].isNull())
+ m_ActionImages[IMAGETYPE_COMPONENTACTION] =
+ CResourceCache::GetInstance()->GetBitmap("Action-ComponentAction.png");
+
+ inRenderer->DrawBitmap(thePos, m_ActionImages[IMAGETYPE_COMPONENTACTION]);
+ }
+
+ // the old code with selection
+
+ // inRenderer->DrawGradientBitmap( theRect, m_ParentRow->GetAsset( )->GetTimebarColor( ), false
+ // );
+ // if ( m_Selected )
+ //{
+ // long theXSize = theRect.size.x / 2;
+ // long theYSize = theRect.size.y / 2;
+ // inRenderer->FillSolidRect( CRct( CPt( theXSize / 2, theYSize / 2 ), CPt( theXSize, theYSize)
+ //), CalculateSelectedColor( m_ParentRow->GetAsset( )->GetTimebarColor( ) ) );
+ //}
+
+ // if this is selected then do something special
+ // if ( m_Shaded )
+ //{
+ // // This is used for the left line of the color control
+ // CColor theNonGradiantHighlight = m_ParentRow->GetAsset( )->GetTimebarColor( );
+ // float theLuminance = theNonGradiantHighlight.GetLuminance( );
+ // theLuminance = theLuminance * (float)1.15;
+ // if ( theLuminance > 1.0 )
+ // {
+ // theLuminance = (float)1.0;
+ // }
+ //
+ // // Highlight on left edge
+ // theNonGradiantHighlight.SetLuminance( theLuminance );
+ // inRenderer->PushPen( theNonGradiantHighlight );
+ // inRenderer->MoveTo( CPt( 1, 0 ) );
+ // inRenderer->LineTo( CPt( 1, theRect.size.y - 1 ) );
+ // inRenderer->PopPen( );
+
+ // // Dark line on far left edge
+ // inRenderer->PushPen( CStudioPreferences::GetRowTopColor( ) );
+ // inRenderer->MoveTo( CPt( 0, 0 ) );
+ // inRenderer->LineTo( CPt( 0, theRect.size.y - 1 ) );
+ // inRenderer->PopPen( );
+ //
+ // inRenderer->PushPen( CStudioPreferences::GetRowTopColor( ) );
+ // inRenderer->MoveTo( CPt( 0,theRect.size.y - 1 ) );
+ // inRenderer->LineTo( CPt( theRect.size.x, theRect.size.y - 1 ) );
+ // inRenderer->MoveTo( CPt( theRect.size.x - 1, 0 ) );
+ // inRenderer->LineTo( CPt( theRect.size.x - 1, theRect.size.y - 1 ) );
+ // inRenderer->PopPen( );
+ //}
+
+ // inRenderer->Draw3dRect( CRct( theRect.position, CPt( theRect.size.x, theRect.size.y + 1 ) ),
+ // CColor( 0, 255, 0 ), CColor( 0, 255, 0 ) );
+}
+
+//==============================================================================
+/**
+ * CalculateNonGradiantHighlight
+ *
+ * calculates the highlight for this color
+ *
+ * @param inColor color to multiply
+ */
+CColor CColorControl::CalculateNonGradiantHighlight(CColor inColor)
+{
+ double theNonGradiantHighlightR = inColor.GetRed() * 1.15;
+ double theNonGradiantHighlightG = inColor.GetGreen() * 1.15;
+ double theNonGradiantHighlightB = inColor.GetBlue() * 1.15;
+ if (theNonGradiantHighlightR > 255) {
+ theNonGradiantHighlightR = 255;
+ }
+ if (theNonGradiantHighlightG > 255) {
+ theNonGradiantHighlightG = 255;
+ }
+ if (theNonGradiantHighlightB > 255) {
+ theNonGradiantHighlightB = 255;
+ }
+ return CColor(::dtol(theNonGradiantHighlightR), ::dtol(theNonGradiantHighlightG),
+ ::dtol(theNonGradiantHighlightB));
+}
+
+//==============================================================================
+/**
+ * CalculateNonGradiantHighlight
+ *
+ * calculates the highlight for this color
+ *
+ * @param inColor color to multiply
+ */
+CColor CColorControl::CalculateSelectedColor(CColor inColor)
+{
+ double theNonGradiantHighlightR = inColor.GetRed() * 0.65;
+ double theNonGradiantHighlightG = inColor.GetGreen() * 0.65;
+ double theNonGradiantHighlightB = inColor.GetBlue() * 0.65;
+ if (theNonGradiantHighlightR > 255) {
+ theNonGradiantHighlightR = 255;
+ }
+ if (theNonGradiantHighlightG > 255) {
+ theNonGradiantHighlightG = 255;
+ }
+ if (theNonGradiantHighlightB > 255) {
+ theNonGradiantHighlightB = 255;
+ }
+ return CColor(::dtol(theNonGradiantHighlightR), ::dtol(theNonGradiantHighlightG),
+ ::dtol(theNonGradiantHighlightB));
+}
+
+//==============================================================================
+/**
+ * Handles the OnMouseDownEvent
+ */
+bool CColorControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ Q_UNUSED(inPoint);
+ Q_UNUSED(inFlags);
+ return true;
+}
+
+//==============================================================================
+/**
+ * Called when this row becomes selected
+ */
+void CColorControl::OnSelect()
+{
+ m_Selected = true;
+ this->Invalidate();
+}
+
+//==============================================================================
+/**
+ * Called when this row becomes deselected
+ */
+void CColorControl::OnDeselect()
+{
+ m_Selected = false;
+ this->Invalidate();
+}
+
+//==============================================================================
+/**
+ * Updates the icon used for display based on the following logic:
+ * 1. Self has actions
+ * 2. Descendents have actions
+ * Results in 4 states.
+ */
+void CColorControl::UpdateIconStatus()
+{
+ ITimelineItem *theTimelineItem = m_ParentRow->GetTimelineItem();
+
+ if (!theTimelineItem)
+ return;
+
+ // Master 'supersede' non-master
+ m_HasMasterAction = theTimelineItem->HasAction(true);
+ if (!m_HasMasterAction)
+ m_HasAction = theTimelineItem->HasAction(false);
+
+ // no descendent info if current row is expanded
+ if (!m_ParentRow->IsExpanded()) {
+ m_ChildHasMasterAction = theTimelineItem->ChildrenHasAction(true);
+ if (!m_ChildHasMasterAction)
+ m_ChildHasAction = theTimelineItem->ChildrenHasAction(false);
+ } else {
+ m_ChildHasMasterAction = false;
+ m_ChildHasAction = false;
+ }
+
+ m_ComponentHasMasterAction = theTimelineItem->ComponentHasAction(true);
+ if (!m_ComponentHasMasterAction)
+ m_ComponentHasAction = theTimelineItem->ComponentHasAction(false);
+
+ this->Invalidate();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/ColorControl.h b/src/Authoring/Studio/Palettes/Timeline/ColorControl.h
new file mode 100644
index 00000000..ec5b156d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ColorControl.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_COLOR_CONTROL_H
+#define INCLUDED_COLOR_CONTROL_H 1
+
+#pragma once
+
+#include "Control.h"
+#include "CColor.h"
+#include "CmdStack.h"
+
+#include <QPixmap>
+
+class CBaseStateRow;
+
+//==============================================================================
+/**
+ * The control at the left side of the TimeContextRow.
+ * It is currently being used to indicate if the Asset or its descendents have any Action.
+ */
+class CColorControl : public CControl
+{
+protected:
+ enum EImageType {
+ IMAGETYPE_ACTION = 0, ///< Types of action image
+ IMAGETYPE_MASTERACTION,
+ IMAGETYPE_CHILDACTION,
+ IMAGETYPE_CHILDMASTERACTION,
+ IMAGETYPE_COMPONENTACTION,
+ IMAGETYPE_COMPONENTMASTERACTION,
+ IMAGETYPE_MAXCOUNT
+ };
+
+public:
+ CColorControl(CBaseStateRow *inRow);
+ virtual ~CColorControl();
+
+ void SetColor(::CColor inColor);
+
+ void SetShaded(bool inIsShaded);
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+ void Draw(CRenderer *inRenderer) override;
+ ::CColor CalculateNonGradiantHighlight(::CColor inColor);
+
+ void OnSelect();
+ void OnDeselect();
+
+ static ::CColor CalculateSelectedColor(::CColor inCOLOR);
+
+ void UpdateIconStatus();
+
+protected:
+ ::CColor m_BackgroundColor;
+ bool m_Shaded;
+ bool m_Selected;
+ CBaseStateRow *m_ParentRow;
+
+ ///////////////////////////////////////////////////
+ // Action icons
+ // Action status
+ bool m_HasAction;
+ bool m_HasMasterAction;
+ bool m_ChildHasAction;
+ bool m_ChildHasMasterAction;
+ bool m_ComponentHasAction;
+ bool m_ComponentHasMasterAction;
+ // Action images
+ QPixmap m_ActionImages[IMAGETYPE_MAXCOUNT];
+};
+#endif // INCLUDED_COLOR_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/CommentEdit.cpp b/src/Authoring/Studio/Palettes/Timeline/CommentEdit.cpp
new file mode 100644
index 00000000..d0d5325f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/CommentEdit.cpp
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "CommentEdit.h"
+#include "Renderer.h"
+#include "ColorControl.h"
+#include "Bindings/ITimelineTimebar.h"
+#include "CoreUtils.h"
+//=============================================================================
+/**
+ * Constructor
+ */
+CCommentEdit::CCommentEdit(ITimelineTimebar *inTimelineItemTimebar)
+ : m_TimelineItemTimebar(inTimelineItemTimebar)
+ , m_IsSelected(false)
+{
+ AddCommitListener(this);
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CCommentEdit::~CCommentEdit()
+{
+ RemoveCommitListener(this);
+}
+
+//=============================================================================
+/**
+ * Called when a property changes.
+ * @param inProperty the property that was changed
+ * @param inIsVisibleChange true if this is a change that effects the property's visibility in the
+ * Timeline
+ */
+void CCommentEdit::OnSetData(CControl *inControl)
+{
+ if (inControl == this && m_TimelineItemTimebar) {
+ m_TimelineItemTimebar->SetTimebarComment(GetString());
+ }
+}
+
+//=============================================================================
+/**
+ * Called when this control receives a double click, edit the comment.
+ *
+ * @param inPoint the point where the double click occured
+ * @param inFlags the flags at the time of the click
+ */
+bool CCommentEdit::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ Q_UNUSED(inPoint);
+ Q_UNUSED(inFlags);
+
+ if (GetDisplayString().Length() > 0) {
+ DoChangeComment();
+ return true;
+ }
+ return false;
+}
+
+//=============================================================================
+/**
+ * Edit the Comment
+ *
+ */
+void CCommentEdit::DoChangeComment()
+{
+ SetEditMode(true);
+ SelectAllText();
+}
+
+//=============================================================================
+/**
+ * Called when this control receives a mouse down, don't do anything unless we're in edit mode
+ *
+ * @param inPoint the point where the click occured
+ * @param inFlags the flags at the time of the click
+ */
+bool CCommentEdit::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ bool theRetVal = false;
+ if (GetEditMode()) {
+ theRetVal = CTextEditInPlace::OnMouseDown(inPoint, inFlags);
+ }
+ return theRetVal;
+}
+
+//=============================================================================
+/**
+ * Called when this control loses focus
+ */
+void CCommentEdit::OnLoseFocus()
+{
+ CStringEdit::OnLoseFocus();
+ SetEditMode(false);
+}
+
+//=============================================================================
+/**
+ * Called when this control gains focus, don't do anytihng
+ */
+void CCommentEdit::OnGainFocus()
+{
+}
+
+//=============================================================================
+/**
+ * Override for the draw, don't set the size of this control here since we are in
+ * a comment and wouldn't want the size changing
+ */
+void CCommentEdit::Draw(CRenderer *inRenderer)
+{
+ CPt theRectPoint = CPt(::dtol(CalculateCharWidths(inRenderer) + GetRightBuffer()), GetSize().y);
+ CPt theSize = GetSize();
+ if (theSize.x < theRectPoint.x)
+ theRectPoint.x = theSize.x;
+ CRct theRect = CRct(theRectPoint);
+ ::CColor theOutlineColor = ::CColor(0, 0, 0);
+ bool theFillFlag = m_FillBackground;
+
+ if (theFillFlag && !GetEditMode())
+ SetFillBackground(false);
+
+ if (GetEditMode())
+ SetTextColor(::CColor(0, 0, 0));
+
+ inRenderer->PushClippingRect(theRect);
+ CStringEdit::Draw(inRenderer);
+ inRenderer->PopClippingRect();
+
+ if (!GetEditMode())
+ SetFillBackground(theFillFlag);
+
+ if (GetEditMode())
+ inRenderer->DrawRectOutline(theRect, theOutlineColor, theOutlineColor, theOutlineColor,
+ theOutlineColor);
+}
+
+//=============================================================================
+/**
+ * Called when the timebar comment or the time bar color changes on an asset
+ */
+void CCommentEdit::RefreshMetaData()
+{
+ m_Color = ::CColor(m_TimelineItemTimebar->GetTimebarColor());
+ CalculateTextColor();
+ SetData(m_TimelineItemTimebar->GetTimebarComment());
+
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Calculates the text color based on whether the object is selected or not
+ */
+void CCommentEdit::CalculateTextColor()
+{
+ ::CColor theColor = m_Color;
+ float theLuminance = theColor.GetLuminance();
+ if (m_IsSelected) {
+ theLuminance = theLuminance * 0.8f;
+ }
+ // Duplicated Code to check luminance when the timebar changes color
+
+ if (theLuminance < 0.5) {
+ SetTextColor(::CColor(255, 255, 255));
+ } else {
+ SetTextColor(::CColor(0, 0, 0));
+ }
+}
+
+//=============================================================================
+/**
+ * Sets this object as selected
+ * @param inPoint the point to check
+ */
+void CCommentEdit::SetSelected(bool inState)
+{
+ m_IsSelected = inState;
+ CalculateTextColor();
+}
+
+//=============================================================================
+/**
+ * Overrides the hit test for the case when the click occurs in the object, but outside the text
+ * @param inPoint the point to check
+ */
+bool CCommentEdit::HitTest(const CPt &inPoint) const
+{
+ // rp this seems wrong but apparently it magically works
+ bool theRetVal = false;
+ if (inPoint.x
+ < m_TotalCharWidth + GetRightBuffer() + 2 * CStudioPreferences::GetTimebarTipSize())
+ theRetVal = CTextEditInPlace::HitTest(inPoint);
+ return theRetVal;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/CommentEdit.h b/src/Authoring/Studio/Palettes/Timeline/CommentEdit.h
new file mode 100644
index 00000000..8ae37ad9
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/CommentEdit.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_COMMENT_EDIT
+#define INCLUDED_COMMENT_EDIT 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "TextEditInPlace.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CRenderer;
+class ITimelineTimebar;
+
+//=============================================================================
+/**
+ * @class CCommentEdit this class handles changing the comments for a timebar in
+ * the timeline. This class seems necessary only to change the color of the text
+ * depending on the timebar color
+ */
+class CCommentEdit : public CTextEditInPlace, public CCommitDataListener
+{
+public:
+ CCommentEdit(ITimelineTimebar *inTimelineItemTimebar);
+ virtual ~CCommentEdit();
+ void OnSetData(CControl *inControl) override;
+ bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void Draw(CRenderer *inRenderer) override;
+ void RefreshMetaData();
+ void CalculateTextColor();
+ bool HitTest(const CPt &inPoint) const override;
+ void SetSelected(bool inState);
+
+ void OnLoseFocus() override;
+ void OnGainFocus() override;
+
+ void DoChangeComment();
+
+protected:
+ ITimelineTimebar *m_TimelineItemTimebar;
+ ::CColor m_Color;
+ bool m_IsSelected;
+};
+
+#endif // INCLUDED_COMMENT_EDIT
diff --git a/src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.cpp b/src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.cpp
new file mode 100644
index 00000000..8909ab7e
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.cpp
@@ -0,0 +1,309 @@
+/****************************************************************************
+**
+** Copyright (C) 1999-2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+#include "Strings.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "ComponentContextMenu.h"
+#include "TimelineControl.h"
+#include "StudioUtils.h"
+#include "StudioClipboard.h"
+#include "Dialogs.h"
+#include "BaseTimelineTreeControl.h"
+#include "Bindings/ITimelineItemBinding.h"
+#include "RelativePathTools.h"
+
+CComponentContextMenu::CComponentContextMenu(CBaseTimelineTreeControl *inTreeControl,
+ ITimelineItemBinding *inTimelineItemBinding,
+ QWidget *parent)
+ : QMenu(parent)
+ , m_TreeControl(inTreeControl)
+ , m_TimelineItemBinding(inTimelineItemBinding)
+{
+ Initialize();
+}
+
+void CComponentContextMenu::Initialize()
+{
+ m_renameAction = new QAction(tr("Rename Object"), this);
+ connect(m_renameAction, &QAction::triggered, this, &CComponentContextMenu::RenameObject);
+ addAction(m_renameAction);
+
+ m_duplicateAction = new QAction(tr("Duplicate Object"), this);
+ connect(m_duplicateAction, &QAction::triggered, this, &CComponentContextMenu::DuplicateObject);
+ addAction(m_duplicateAction);
+
+ m_deleteAction = new QAction(tr("Delete Object"), this);
+ connect(m_deleteAction, &QAction::triggered, this, &CComponentContextMenu::DeleteObject);
+ addAction(m_deleteAction);
+
+ addSeparator();
+
+ m_copyAction = new QAction(tr("Copy"), this);
+ connect(m_copyAction, &QAction::triggered, this, &CComponentContextMenu::CopyObject);
+ addAction(m_copyAction);
+
+ m_pasteAction = new QAction(tr("Paste"), this);
+ connect(m_pasteAction, &QAction::triggered, this, &CComponentContextMenu::PasteObject);
+ addAction(m_pasteAction);
+
+ m_cutAction = new QAction(tr("Cut"), this);
+ connect(m_cutAction, &QAction::triggered, this, &CComponentContextMenu::CutObject);
+ addAction(m_cutAction);
+ addSeparator();
+
+ m_makeAction = new QAction(tr("Make Component"), this);
+ connect(m_makeAction, &QAction::triggered, this, &CComponentContextMenu::MakeComponent);
+ addAction(m_makeAction);
+
+ if (CanInspectComponent()) {
+ m_inspectAction = new QAction(tr("Edit Component"), this);
+ connect(m_inspectAction, &QAction::triggered, this, &CComponentContextMenu::InspectComponent);
+ addAction(m_inspectAction);
+ }
+
+ if (m_TimelineItemBinding->IsExternalizeable()) {
+ addSeparator();
+ m_externalizeAction = new QAction(tr("Externalize Buffer"), this);
+ connect(m_externalizeAction, &QAction::triggered, this, &CComponentContextMenu::Externalize);
+ addAction(m_externalizeAction);
+ } else if (m_TimelineItemBinding->IsInternalizeable()) {
+ addSeparator();
+ m_internalizeAction = new QAction(tr("Internalize Buffer"), this);
+ connect(m_internalizeAction, &QAction::triggered, this, &CComponentContextMenu::Internalize);
+ addAction(m_internalizeAction);
+ }
+
+ addSeparator();
+
+ m_copyPathAction = new QAction(tr("Copy Object Path"), this);
+ connect(m_copyPathAction, &QAction::triggered, this, &CComponentContextMenu::CopyObjectPath);
+ addAction(m_copyPathAction);
+}
+
+void CComponentContextMenu::showEvent(QShowEvent *event)
+{
+ m_renameAction->setEnabled(CanRenameObject());
+ m_duplicateAction->setEnabled(CanDuplicateObject());
+ m_deleteAction->setEnabled(CanDeleteObject());
+
+ m_cutAction->setEnabled(CanCutObject());
+ m_copyAction->setEnabled(CanCopyObject());
+ m_pasteAction->setEnabled(CanPasteObject());
+
+ m_makeAction->setEnabled(CanMakeComponent());
+
+ QMenu::showEvent(event);
+}
+
+
+CComponentContextMenu::~CComponentContextMenu()
+{
+ // This will result in a double deletion.
+ // DeletePerformers( );
+}
+
+//=============================================================================
+/**
+ * Checks to see if the object can be renamed.
+ * @return true if the object can be renamed.
+ */
+bool CComponentContextMenu::CanRenameObject()
+{
+ return m_TimelineItemBinding->IsValidTransaction(ITimelineItemBinding::EUserTransaction_Rename);
+}
+
+//=============================================================================
+/**
+ * Rename the object.
+ */
+void CComponentContextMenu::RenameObject()
+{
+ m_TreeControl->DoRename();
+}
+
+//=============================================================================
+/**
+ * Checks to see if the object can be duplicated.
+ * @return true if the object can be duplicated.
+ */
+bool CComponentContextMenu::CanDuplicateObject()
+{
+ return m_TimelineItemBinding->IsValidTransaction(
+ ITimelineItemBinding::EUserTransaction_Duplicate);
+}
+
+//=============================================================================
+/**
+ * Duplicate the object.
+ */
+void CComponentContextMenu::DuplicateObject()
+{
+ m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_Duplicate);
+}
+
+//=============================================================================
+/**
+ * Checks to see if the object can be deleted.
+ * @return true if the object can be deleted.
+ */
+bool CComponentContextMenu::CanDeleteObject()
+{
+ return m_TimelineItemBinding->IsValidTransaction(ITimelineItemBinding::EUserTransaction_Delete);
+}
+
+//=============================================================================
+/**
+ * Deletes the object from the scene graph.
+ */
+void CComponentContextMenu::DeleteObject()
+{
+ m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_Delete);
+}
+
+//=============================================================================
+/**
+ * Checks to see if the State is a component and can be inspected.
+ * @return true is the state is a component and can be inspected.
+ */
+bool CComponentContextMenu::CanInspectComponent()
+{
+ return m_TimelineItemBinding->IsValidTransaction(
+ ITimelineItemBinding::EUserTransaction_EditComponent);
+}
+
+//=============================================================================
+/**
+ * Inspect the State (Component).
+ * This will make the component the top level item of the timelineview.
+ */
+void CComponentContextMenu::InspectComponent()
+{
+ m_TimelineItemBinding->OpenAssociatedEditor();
+}
+
+//=============================================================================
+/**
+ * Checks to see if the object can be wrapped in a component.
+ * @return true if the object is allowed to be wrapped in a component.
+ */
+bool CComponentContextMenu::CanMakeComponent()
+{
+ return m_TimelineItemBinding->IsValidTransaction(
+ ITimelineItemBinding::EUserTransaction_MakeComponent);
+}
+
+//=============================================================================
+/**
+ * Wraps the specified asset hierarchy under a component.
+ */
+void CComponentContextMenu::MakeComponent()
+{
+ m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_MakeComponent);
+}
+
+//=============================================================================
+/**
+ * Get the full Scripting path of the object and copy it to the clipboard.
+ * This will figure out the proper way to address the object via scripting
+ * and put that path into the clipboard.
+ */
+void CComponentContextMenu::CopyObjectPath()
+{
+ CStudioClipboard::CopyTextToClipboard(m_TimelineItemBinding->GetObjectPath().toQString());
+}
+
+//=============================================================================
+/**
+ * Checks to see if the object can be copied
+ * @return true if the object can be copied
+ */
+bool CComponentContextMenu::CanCopyObject()
+{
+ return m_TimelineItemBinding->IsValidTransaction(ITimelineItemBinding::EUserTransaction_Copy);
+}
+
+//=============================================================================
+/**
+ * Copy the object.
+ */
+void CComponentContextMenu::CopyObject()
+{
+ m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_Copy);
+}
+
+bool CComponentContextMenu::CanCutObject()
+{
+ return m_TimelineItemBinding->IsValidTransaction(ITimelineItemBinding::EUserTransaction_Cut);
+}
+
+void CComponentContextMenu::CutObject()
+{
+ m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_Cut);
+}
+
+//=============================================================================
+/**
+ * Checks to see if the object can be pasted
+ * @return true if the object can be pasted
+ */
+bool CComponentContextMenu::CanPasteObject()
+{
+ return m_TimelineItemBinding->IsValidTransaction(ITimelineItemBinding::EUserTransaction_Paste);
+}
+
+//=============================================================================
+/**
+ * Paste the object.
+ */
+void CComponentContextMenu::PasteObject()
+{
+ m_TimelineItemBinding->PerformTransaction(ITimelineItemBinding::EUserTransaction_Paste);
+}
+
+ITimelineItem *CComponentContextMenu::GetTimelineItem() const
+{
+ return m_TimelineItemBinding->GetTimelineItem();
+}
+
+void CComponentContextMenu::Externalize()
+{
+ m_TimelineItemBinding->Externalize();
+}
+
+void CComponentContextMenu::Internalize()
+{
+ m_TimelineItemBinding->Internalize();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.h b/src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.h
new file mode 100644
index 00000000..cf1573e6
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 1999-2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_COMPONENT_CONTEXT_MENU_H
+#define INCLUDED_COMPONENT_CONTEXT_MENU_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include <QMenu>
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CBaseTimelineTreeControl;
+class ITimelineItem;
+class ITimelineItemBinding;
+
+class CComponentContextMenu : public QMenu
+{
+ Q_OBJECT
+public:
+ CComponentContextMenu(CBaseTimelineTreeControl *inTreeControl,
+ ITimelineItemBinding *inTimelineItemBinding,
+ QWidget *parent = nullptr);
+ virtual ~CComponentContextMenu();
+
+protected Q_SLOTS:
+ void RenameObject();
+ void DuplicateObject();
+ void DeleteObject();
+ void InspectComponent();
+ void MakeComponent();
+ void CopyObjectPath();
+ void CopyObject();
+ void PasteObject();
+ void CutObject();
+ void Externalize();
+ void Internalize();
+
+protected:
+ void showEvent(QShowEvent *event) override;
+
+ bool CanRenameObject();
+ bool CanDuplicateObject();
+ bool CanDeleteObject();
+ bool CanInspectComponent();
+ bool CanMakeComponent();
+ bool CanCopyObject();
+ bool CanPasteObject();
+ bool CanCutObject();
+ void Import();
+ void RefreshImport();
+ bool CanImport();
+ bool CanRefreshImport();
+ bool CanExportComponent();
+
+ void Initialize();
+
+ ITimelineItem *GetTimelineItem() const;
+
+ CBaseTimelineTreeControl *m_TreeControl;
+ ITimelineItemBinding *m_TimelineItemBinding;
+ QAction *m_renameAction;
+ QAction *m_duplicateAction;
+ QAction *m_deleteAction;
+ QAction *m_inspectAction;
+ QAction *m_makeAction;
+ QAction *m_copyPathAction;
+ QAction *m_cutAction;
+ QAction *m_copyAction;
+ QAction *m_pasteAction;
+ QAction *m_externalizeAction;
+ QAction *m_internalizeAction;
+};
+#endif // INCLDUED_STATE_CONTEXT_MENU_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/FilterToolbar.cpp b/src/Authoring/Studio/Palettes/Timeline/FilterToolbar.cpp
new file mode 100644
index 00000000..ce2b296c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/FilterToolbar.cpp
@@ -0,0 +1,271 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+#include "Strings.h"
+#include "StringLoader.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "FilterToolbar.h"
+#include "ButtonControl.h"
+#include "SystemPreferences.h"
+#include "Renderer.h"
+#include "TimelineTreeLayout.h"
+#include "StudioPreferences.h"
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CFilterToolbar::CFilterToolbar(CTimelineTreeLayout *inTreeLayout)
+ : CFlowLayout(nullptr, false)
+{
+ m_TreeLayout = inTreeLayout;
+
+ SetFlowDirection(FLOW_HORIZONTAL);
+ SetAlignment(ALIGN_TOP, ALIGN_LEFT);
+ SetLeftMargin(1);
+
+ // Create the buttons
+ m_FltrBehaviorsBtn = new CProceduralButton<CToggleButton>();
+ m_FltrPropertiesBtn = new CProceduralButton<CToggleButton>();
+ m_FltrMaterialsBtn = new CProceduralButton<CToggleButton>();
+ m_FltrShyBtn = new CProceduralButton<CToggleButton>();
+ m_FltrVisibleBtn = new CProceduralButton<CToggleButton>();
+
+ // Load the bitmaps
+ m_FltrBehaviorsBtn->SetUpImage("obsolete_placeholder.png");
+ m_FltrBehaviorsBtn->SetDownImage("obsolete_placeholder.png");
+
+ m_FltrPropertiesBtn->SetUpImage("obsolete_placeholder.png");
+ m_FltrPropertiesBtn->SetDownImage("obsolete_placeholder.png");
+
+ m_FltrMaterialsBtn->SetUpImage("obsolete_placeholder.png");
+ m_FltrMaterialsBtn->SetDownImage("obsolete_placeholder.png");
+
+ m_FltrShyBtn->SetUpImage("Toggle-Shy.png");
+ m_FltrShyBtn->SetDownImage("Toggle-Shy.png");
+
+ m_FltrVisibleBtn->SetUpImage("Toggle-HideShow.png");
+ m_FltrVisibleBtn->SetDownImage("Toggle-HideShow.png");
+
+ // Turn off the left border of each button since they are all next to each other, otherwise,
+ // you'll get a double line effect
+ CProceduralButton<CToggleButton>::SBorderOptions theBorderOptions(false, true, true, true);
+ m_FltrBehaviorsBtn->SetBorderVisibilityAll(theBorderOptions);
+ m_FltrPropertiesBtn->SetBorderVisibilityAll(theBorderOptions);
+ m_FltrMaterialsBtn->SetBorderVisibilityAll(theBorderOptions);
+ m_FltrShyBtn->SetBorderVisibilityAll(theBorderOptions);
+ m_FltrVisibleBtn->SetBorderVisibilityAll(theBorderOptions);
+ CProceduralButton<CButtonControl>::SBorderOptions theBorderOptions2(false, true, true, true);
+
+ // Set the max sizes for the buttons
+ m_FltrBehaviorsBtn->SetAbsoluteSize(m_FltrBehaviorsBtn->GetSize());
+ m_FltrPropertiesBtn->SetAbsoluteSize(m_FltrPropertiesBtn->GetSize());
+ m_FltrMaterialsBtn->SetAbsoluteSize(m_FltrMaterialsBtn->GetSize());
+ m_FltrShyBtn->SetAbsoluteSize(m_FltrShyBtn->GetSize());
+ m_FltrVisibleBtn->SetAbsoluteSize(m_FltrShyBtn->GetSize());
+
+ // Tooltips
+ m_FltrBehaviorsBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_BEHAVIOR2));
+ m_FltrPropertiesBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_PROPERTIES2));
+ m_FltrMaterialsBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_MATERIALS2));
+ m_FltrShyBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_SHY2));
+ m_FltrVisibleBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_VISIBLE2));
+
+ // Callback for one of the Filter buttons being clicked on
+ m_FltrBehaviorsBtn->SigToggle.connect(std::bind(&CFilterToolbar::OnButtonToggled, this,
+ std::placeholders::_1, std::placeholders::_2));
+ m_FltrPropertiesBtn->SigToggle.connect(std::bind(&CFilterToolbar::OnButtonToggled, this,
+ std::placeholders::_1, std::placeholders::_2));
+ m_FltrMaterialsBtn->SigToggle.connect(std::bind(&CFilterToolbar::OnButtonToggled, this,
+ std::placeholders::_1, std::placeholders::_2));
+ m_FltrShyBtn->SigToggle.connect(std::bind(&CFilterToolbar::OnButtonToggled, this,
+ std::placeholders::_1, std::placeholders::_2));
+ m_FltrVisibleBtn->SigToggle.connect(std::bind(&CFilterToolbar::OnButtonToggled, this,
+ std::placeholders::_1, std::placeholders::_2));
+
+ // Add the buttons to this layout
+ AddChild(m_FltrMaterialsBtn);
+ AddChild(m_FltrPropertiesBtn);
+ AddChild(m_FltrBehaviorsBtn);
+ AddChild(m_FltrShyBtn);
+ AddChild(m_FltrVisibleBtn);
+
+ m_FltrBehaviorsBtn->SetToggleState(false);
+ m_FltrPropertiesBtn->SetToggleState(false);
+ m_FltrMaterialsBtn->SetToggleState(false);
+ m_FltrShyBtn->SetToggleState(false);
+ m_FltrVisibleBtn->SetToggleState(false);
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CFilterToolbar::~CFilterToolbar()
+{
+ delete m_FltrBehaviorsBtn;
+ delete m_FltrPropertiesBtn;
+ delete m_FltrMaterialsBtn;
+ delete m_FltrShyBtn;
+ delete m_FltrVisibleBtn;
+}
+
+//=============================================================================
+/**
+ * Overriden to draw some highlighting.
+ */
+void CFilterToolbar::Draw(CRenderer *inRenderer)
+{
+ CRct theRect(GetSize());
+ // Draw the highlight at the bottom
+ inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor());
+ inRenderer->MoveTo(CPt(0, theRect.size.y - 1));
+ inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1));
+ inRenderer->PopPen();
+
+ // Draw the line on the left side
+ inRenderer->PushPen(CStudioPreferences::GetButtonShadowColor());
+ inRenderer->MoveTo(0, 0);
+ inRenderer->LineTo(0, theRect.size.y - 1);
+ inRenderer->PopPen();
+}
+
+//=============================================================================
+/**
+ * Turns filtering on and off for behavior objects in the timeline.
+ * @param inFilter true to filter behaviors out of the timeline, false to show
+ * behaviors in the timeline.
+ */
+void CFilterToolbar::FilterBehaviors(bool inFilter)
+{
+ if (inFilter)
+ m_FltrBehaviorsBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_BEHAVIOR1));
+ else
+ m_FltrBehaviorsBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_BEHAVIOR2));
+
+ m_TreeLayout->GetFilter()->SetBehaviors(inFilter);
+ m_TreeLayout->Filter();
+}
+
+//=============================================================================
+/**
+ * Turns filtering on and off for properties on objects in the timeline.
+ * @param inFilter true to filter properties out of the timeline, false to show
+ * properties in the timeline.
+ */
+void CFilterToolbar::FilterProperties(bool inFilter)
+{
+ if (inFilter)
+ m_FltrPropertiesBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_PROPERTIES1));
+ else
+ m_FltrPropertiesBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_PROPERTIES2));
+
+ m_TreeLayout->GetFilter()->SetProperties(inFilter);
+ m_TreeLayout->Filter();
+}
+
+//=============================================================================
+/**
+ * Turns filtering on and off for material objects.
+ * @param inFilter true to filter material objects out of the timeline, false to show
+ * material objects in the timeline.
+ */
+void CFilterToolbar::FilterMaterials(bool inFilter)
+{
+ if (inFilter)
+ m_FltrMaterialsBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_MATERIALS1));
+ else
+ m_FltrMaterialsBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_MATERIALS2));
+
+ m_TreeLayout->GetFilter()->SetMaterials(inFilter);
+ m_TreeLayout->Filter();
+}
+
+//=============================================================================
+/**
+ * Turns filtering on and off for shy objects.
+ * @param inFilter true to filter shy objects out of the timeline, false to show
+ * shy objects in the timeline.
+ */
+void CFilterToolbar::FilterShy(bool inFilter)
+{
+ if (inFilter)
+ m_FltrShyBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_SHY1));
+ else
+ m_FltrShyBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_SHY2));
+
+ m_TreeLayout->GetFilter()->SetShy(inFilter);
+ m_TreeLayout->Filter();
+}
+
+//=============================================================================
+/**
+ * Turns filtering on and off for visible objects.
+ * @param inFilter true to filter visible objects out of the timeline, false to show
+ * shy objects in the timeline.
+ */
+void CFilterToolbar::FilterVisible(bool inFilter)
+{
+ if (inFilter)
+ m_FltrVisibleBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_VISIBLE1));
+ else
+ m_FltrVisibleBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_VISIBLE2));
+
+ m_TreeLayout->GetFilter()->SetVisible(inFilter);
+ m_TreeLayout->Filter();
+}
+
+//=============================================================================
+/**
+ * Handles turning a filter on or off in response to a button being pressed.
+ * @param inButton button that generated the event
+ * @param inState new state of the button after being toggled
+ */
+void CFilterToolbar::OnButtonToggled(CToggleButton *inButton, CButtonControl::EButtonState inState)
+{
+ bool theFilterNeedsApplied = (inState == CButtonControl::EBUTTONSTATE_UP);
+
+ if (inButton == m_FltrBehaviorsBtn)
+ FilterBehaviors(theFilterNeedsApplied);
+ else if (inButton == m_FltrPropertiesBtn)
+ FilterProperties(theFilterNeedsApplied);
+ else if (inButton == m_FltrMaterialsBtn)
+ FilterMaterials(theFilterNeedsApplied);
+ else if (inButton == m_FltrShyBtn)
+ FilterShy(theFilterNeedsApplied);
+ else if (inButton == m_FltrVisibleBtn)
+ FilterVisible(theFilterNeedsApplied);
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/FilterToolbar.h b/src/Authoring/Studio/Palettes/Timeline/FilterToolbar.h
new file mode 100644
index 00000000..8148fff3
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/FilterToolbar.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_FILTER_TOOLBAR_H
+#define INCLUDED_FILTER_TOOLBAR_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "FlowLayout.h"
+#include "ProceduralButton.h"
+#include "ToggleButton.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CButtonControl;
+class CRenderer;
+class CTimelineTreeLayout;
+
+//=============================================================================
+/**
+ * Control at the top of the timeline containing filter buttons.
+ */
+class CFilterToolbar : public CFlowLayout
+{
+public:
+ CFilterToolbar(CTimelineTreeLayout *inTreeLayout);
+ virtual ~CFilterToolbar();
+ void Draw(CRenderer *inRenderer) override;
+
+ void FilterBehaviors(bool inFilter);
+ void FilterProperties(bool inFilter);
+ void FilterMaterials(bool inFilter);
+ void FilterShy(bool inFilter);
+ void FilterVisible(bool inFilter);
+
+ void OnButtonToggled(CToggleButton *inButton, CToggleButton::EButtonState inState);
+
+protected:
+ CProceduralButton<CToggleButton> *m_FltrBehaviorsBtn;
+ CProceduralButton<CToggleButton> *m_FltrPropertiesBtn;
+ CProceduralButton<CToggleButton> *m_FltrMaterialsBtn;
+ CProceduralButton<CToggleButton> *m_FltrShyBtn;
+ CProceduralButton<CToggleButton> *m_FltrVisibleBtn;
+ CTimelineTreeLayout *m_TreeLayout;
+};
+
+#endif // INCLUDED_FILTER_TOOLBAR_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/IBreadCrumbProvider.h b/src/Authoring/Studio/Palettes/Timeline/IBreadCrumbProvider.h
new file mode 100644
index 00000000..18aa31ac
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/IBreadCrumbProvider.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_IBREADCRUMBPROVIDER_H
+#define INCLUDED_IBREADCRUMBPROVIDER_H 1
+
+#pragma once
+
+#include <QColor>
+#include <QString>
+
+#include <boost/signals.hpp>
+
+class QPixmap;
+
+struct SBreadCrumb
+{
+ QColor m_Color; /// Color for text of the bread crumb
+ QString m_String; /// Text to be displayed for the bread crumb
+};
+
+//=============================================================================
+/**
+ * A interface class for the breadcrumb control, to walk down the breadcrumb trail, without having
+ * to know any underlying implementations.
+ */
+class IBreadCrumbProvider
+{
+public:
+ typedef std::vector<SBreadCrumb> TTrailList;
+
+public:
+ virtual ~IBreadCrumbProvider() {}
+
+ virtual TTrailList GetTrail(bool inRefresh = true) = 0;
+ virtual void OnBreadCrumbClicked(long inTrailIndex) = 0;
+
+ virtual QPixmap GetRootImage() const = 0;
+ virtual QPixmap GetBreadCrumbImage() const = 0;
+ virtual QPixmap GetSeparatorImage() const = 0;
+ virtual QPixmap GetActiveBreadCrumbImage() const = 0;
+
+ boost::signal0<void> SigBreadCrumbUpdate;
+};
+
+#endif // INCLUDED_IBREADCRUMBPROVIDER_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/ITimelineControl.h b/src/Authoring/Studio/Palettes/Timeline/ITimelineControl.h
new file mode 100644
index 00000000..05af776e
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ITimelineControl.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_ITIMELINE_CONTROL_H
+#define INCLUDED_ITIMELINE_CONTROL_H 1
+
+#pragma once
+
+#include "Rct.h"
+
+class ISnappingListProvider;
+
+class ITimelineControl
+{
+public:
+ virtual ~ITimelineControl() {}
+
+ virtual void OnLayoutChanged() = 0;
+ virtual CRct GetBounds() const = 0;
+ virtual void HideTimelineMoveableTooltip() = 0;
+ virtual ISnappingListProvider *GetSnappingListProvider() const = 0;
+};
+
+#endif // INCLUDED_TIMELINE_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.cpp b/src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.cpp
new file mode 100644
index 00000000..78a2e4cb
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.cpp
@@ -0,0 +1,405 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+#include "Strings.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "KeyframeContextMenu.h"
+#include "IDoc.h"
+#include "CColor.h"
+#include "Preferences.h"
+#include "Dialogs.h"
+#include "TimebarControl.h"
+#include "Bindings/ITimelineTimebar.h"
+#include "Bindings/ITimelineKeyframesManager.h"
+#include "Bindings/ITimelineItemBinding.h"
+#include "Bindings/ITimelineItemProperty.h"
+#include "IKeyframe.h"
+
+#include <QColorDialog>
+
+#define IDC_KEYFRAME_COLOR_BOX 1002
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CBaseKeyframeContextMenu::CBaseKeyframeContextMenu(QWidget *parent)
+ : QMenu(parent)
+ , m_HasDynamicSelectedKeyframes(false)
+ , m_KeyframesManager(nullptr)
+{
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CBaseKeyframeContextMenu::~CBaseKeyframeContextMenu()
+{
+}
+
+void CBaseKeyframeContextMenu::Initialize(ITimelineKeyframesManager *inKeyframesManager)
+{
+ m_KeyframesManager = inKeyframesManager;
+ ASSERT(m_KeyframesManager);
+
+ //"Insert Keyframe"
+ ITimelineItemKeyframesHolder *theKeyframesHolder = GetKeyframesHolder();
+ if (theKeyframesHolder) {
+ m_insertAction = new QAction(tr("Insert Keyframe"));
+ connect(m_insertAction, &QAction::triggered, this, &CBaseKeyframeContextMenu::InsertKeyframe);
+ addAction(m_insertAction);
+ }
+
+ bool theHasKeysSelected = m_KeyframesManager->HasSelectedKeyframes();
+ bool theCanCopyKeys = m_KeyframesManager->CanPerformKeyframeCopy();
+ bool theCanPasteKeys = m_KeyframesManager->CanPerformKeyframePaste();
+
+ m_cutAction = new QAction(tr("Cut Selected Keyframes"));
+ connect(m_cutAction, &QAction::triggered, this, &CBaseKeyframeContextMenu::CutSelectedKeys);
+ m_cutAction->setEnabled(theCanCopyKeys);
+ addAction(m_cutAction);
+
+ m_copyAction = new QAction(tr("Copy Selected Keyframes"));
+ connect(m_copyAction, &QAction::triggered, this, &CBaseKeyframeContextMenu::CopySelectedKeys);
+ m_copyAction->setEnabled(theCanCopyKeys);
+ addAction(m_copyAction);
+
+ m_pasteAction = new QAction(tr("Paste Keyframes"));
+ connect(m_pasteAction, &QAction::triggered, this, &CBaseKeyframeContextMenu::PasteSelectedKeys);
+ m_pasteAction->setEnabled(theCanPasteKeys);
+ addAction(m_pasteAction);
+
+ m_deleteSelectedAction = new QAction(tr("Delete Selected Keyframes"));
+ connect(m_deleteSelectedAction, &QAction::triggered, this, &CBaseKeyframeContextMenu::DeleteSelectedKeys);
+ m_deleteSelectedAction->setEnabled(theHasKeysSelected);
+ addAction(m_deleteSelectedAction);
+
+ //"Delete All Channel Keyframes"
+ if (theKeyframesHolder) {
+ m_deleteChannelKeysAction = new QAction(tr("Delete All Channel Keyframes"));
+ connect(m_deleteChannelKeysAction, &QAction::triggered, this, &CBaseKeyframeContextMenu::DeleteChannelKeys);
+ addAction(m_deleteChannelKeysAction);
+ }
+}
+
+//=============================================================================
+/**
+ * Called when the cut selected keys option is chosen by the user. Makes a call
+ * to the doc to handle the request
+ */
+void CBaseKeyframeContextMenu::InsertKeyframe()
+{
+ GetKeyframesHolder()->InsertKeyframe();
+}
+
+//=============================================================================
+/**
+ * Called when the cut selected keys option is chosen by the user. Makes a call
+ * to the doc to handle the request
+ */
+void CBaseKeyframeContextMenu::DeleteChannelKeys()
+{
+ GetKeyframesHolder()->DeleteAllChannelKeyframes();
+}
+
+//=============================================================================
+/**
+ * Called when the cut selected keys option is chosen by the user. Makes a call
+ * to the doc to handle the request
+ */
+void CBaseKeyframeContextMenu::CutSelectedKeys()
+{
+ m_KeyframesManager->RemoveKeyframes(true);
+}
+
+//=============================================================================
+/**
+ * Called when the copy selected keys option is chosen by the user. Makes a call
+ * to the doc to handle the request
+ */
+void CBaseKeyframeContextMenu::CopySelectedKeys()
+{
+ m_KeyframesManager->CopyKeyframes();
+}
+
+//=============================================================================
+/**
+ * Called when the paste selected keys option is chosen by the user. Makes a call
+ * to the doc to handle the request
+ */
+void CBaseKeyframeContextMenu::PasteSelectedKeys()
+{
+ m_KeyframesManager->PasteKeyframes();
+}
+
+//=============================================================================
+/**
+ * Called when the delete selected keys option is chosen by the user. Makes a call
+ * to the doc to handle the request
+ */
+void CBaseKeyframeContextMenu::DeleteSelectedKeys()
+{
+ m_KeyframesManager->RemoveKeyframes(false);
+}
+
+//=============================================================================
+/**
+ * Toggle if the selected keyframe(s) is dynamic
+ */
+void CBaseKeyframeContextMenu::MakeDynamic()
+{
+ m_KeyframesManager->SetKeyframesDynamic(!m_HasDynamicSelectedKeyframes); // toggle
+}
+
+//==============================================================================
+// CTimebarKeyframeContextMenu
+//==============================================================================
+CTimebarKeyframeContextMenu::CTimebarKeyframeContextMenu(ITimebarControl *inTimebarControl, ITimelineKeyframesManager *inKeyframesManager,
+ bool inShowTimebarPropertiesOptions /*= true */, QWidget *parent)
+ : CBaseKeyframeContextMenu(parent)
+ , m_TimebarControl(inTimebarControl)
+ , m_ShowTimebarPropertiesOptions(inShowTimebarPropertiesOptions)
+{
+ Initialize(inKeyframesManager);
+}
+
+CTimebarKeyframeContextMenu::~CTimebarKeyframeContextMenu()
+{
+}
+
+void CTimebarKeyframeContextMenu::Initialize(ITimelineKeyframesManager *inKeyframesManager)
+{
+ CBaseKeyframeContextMenu::Initialize(inKeyframesManager);
+
+ // Dynamic keyframes ( the way it was set up before was, this option is still shown, but grayed
+ // out even if this context menu isn't triggered from right-clicking on a timebar )
+ QString theMakeDynamicOption = tr("Make Animations Static");
+
+ if (m_TimebarControl->GetKeyframesHolder()->GetKeyframeCount() > 0) {
+ m_HasDynamicSelectedKeyframes = m_KeyframesManager->HasDynamicKeyframes();
+
+ if (!m_HasDynamicSelectedKeyframes) {
+ theMakeDynamicOption = tr("Make Animations Dynamic");
+ }
+
+ m_makeDynamicAction = new QAction(theMakeDynamicOption);
+ connect(m_makeDynamicAction, &QAction::triggered, this, &CTimebarKeyframeContextMenu::MakeDynamic);
+ addAction(m_makeDynamicAction);
+ }
+
+ if (m_ShowTimebarPropertiesOptions) {
+ // Timebar specific actions
+ addSeparator();
+ m_timeBarColorAction = new QAction(tr("Change Time Bar Color"));
+ connect(m_timeBarColorAction, &QAction::triggered, this, &CTimebarKeyframeContextMenu::ChangeTimebarColor);
+
+ m_timeBarTextAction = new QAction(tr("Change Time Bar Text"));
+ connect(m_timeBarTextAction, &QAction::triggered, this, &CTimebarKeyframeContextMenu::ChangeTimebarText);
+
+ // Change the text for the timebar option depending on whether they are currently being
+ // shown or not
+ QString theTimebarHandleTextID = tr("Show Time Bar Handles");
+ if (CPreferences::GetUserPreferences("Timeline").GetValue("ShowTimebarHandles", false))
+ theTimebarHandleTextID = tr("Hide Time Bar Handles");
+
+ m_timeBarHandlesAction = new QAction(theTimebarHandleTextID);
+ connect(m_timeBarHandlesAction, &QAction::triggered, this, &CTimebarKeyframeContextMenu::ToggleTimebarHandles);
+
+ m_timeBarTimeAction = new QAction(tr("Set Timebar Time"));
+ connect(m_timeBarTimeAction, &QAction::triggered, this, &CTimebarKeyframeContextMenu::SetTimebarTime);
+ }
+}
+
+void CTimebarKeyframeContextMenu::MakeDynamic()
+{
+ m_KeyframesManager->SelectAllKeyframes();
+ CBaseKeyframeContextMenu::MakeDynamic();
+}
+
+//=============================================================================
+/**
+ * To show "Insert Keyframe" and "Delete All Channel Keyframes"
+ */
+ITimelineItemKeyframesHolder *CTimebarKeyframeContextMenu::GetKeyframesHolder()
+{
+ return m_TimebarControl->GetKeyframesHolder();
+}
+
+//=============================================================================
+/**
+ * Called when the copy selected keys option is chosen by the user.
+ */
+void CTimebarKeyframeContextMenu::ChangeTimebarColor()
+{
+ const auto color = QColorDialog::getColor(m_TimebarControl->GetTimebarColor());
+ if (color.isValid())
+ m_TimebarControl->SetTimebarColor(color);
+}
+
+//=============================================================================
+/**
+ * Called when the copy selected keys option is chosen by the user.
+ */
+void CTimebarKeyframeContextMenu::ChangeTimebarText()
+{
+ m_TimebarControl->OnEditTimeComment();
+}
+
+//=============================================================================
+/**
+ * Shows or hides timebar handles in the timeline. If timebar handles are
+ * currently being shown, they are hidden, and the preference is stored. If
+ * timebar handles are being hidden, they are shown.
+ */
+void CTimebarKeyframeContextMenu::ToggleTimebarHandles()
+{
+ // Get the current timebar handle preference
+ bool theHandlesAreShowing =
+ CPreferences::GetUserPreferences("Timeline").GetValue("ShowTimebarHandles", false);
+ // Switch the preference.
+ CPreferences::GetUserPreferences("Timeline")
+ .SetValue("ShowTimebarHandles", !theHandlesAreShowing);
+ if (m_TimebarControl)
+ m_TimebarControl->OnToggleTimebarHandles();
+}
+
+//=============================================================================
+/**
+ * SetTimebarTime: This is the event handler that will be called when the user
+ * chooses set timebar time from a pop up menu. This pop up
+ *menu
+ * is triggered when the user right click on the selected
+ *timebar.
+ * It displays a time edit dialog to allow the user to set the
+ * start and end time of the timebar time.
+ * @param NONE
+ * @return NONE
+ */
+void CTimebarKeyframeContextMenu::SetTimebarTime()
+{
+ m_TimebarControl->SetTimebarTime();
+}
+
+//==============================================================================
+// CKeyframeContextMenu
+//==============================================================================
+CKeyframeContextMenu::CKeyframeContextMenu(ITimelineKeyframesManager *inKeyframesManager,
+ ITimelineItemProperty *inTimelineItemProperty, QWidget *parent)
+ : CBaseKeyframeContextMenu(parent)
+ , m_TimelineItemProperty(inTimelineItemProperty)
+{
+ Initialize(inKeyframesManager);
+}
+
+CKeyframeContextMenu::~CKeyframeContextMenu()
+{
+}
+
+void CKeyframeContextMenu::Initialize(ITimelineKeyframesManager *inKeyframesManager)
+{
+ CBaseKeyframeContextMenu::Initialize(inKeyframesManager);
+
+ // Dynamic keyframes ( the way it was set up before was, this option is still shown, but grayed
+ // out even if this context menu isn't triggered from right-clicking on a timebar )
+ QString theMakeDynamicOption = tr("Make Animations Static");
+ m_HasDynamicSelectedKeyframes =
+ m_TimelineItemProperty && m_TimelineItemProperty->IsDynamicAnimation();
+
+ if (!m_HasDynamicSelectedKeyframes) {
+ theMakeDynamicOption = tr("Make Animations Dynamic");
+ }
+
+ m_makeDynamicAction = new QAction(theMakeDynamicOption);
+ connect(m_makeDynamicAction, &QAction::triggered, this, &CKeyframeContextMenu::MakeDynamic);
+ addAction(m_makeDynamicAction);
+
+ addSeparator();
+ bool theHasKeysSelected = m_KeyframesManager->HasSelectedKeyframes();
+ m_setInterpolationAction = new QAction(tr("Set Interpolation"));
+ connect(m_setInterpolationAction, &QAction::triggered, this, &CKeyframeContextMenu::SetInterpolation);
+ addAction(m_setInterpolationAction);
+
+ m_setKeyframeTimeAction = new QAction(tr("Set Keyframe Time"));
+ connect(m_setKeyframeTimeAction, &QAction::triggered, this, &CKeyframeContextMenu::SetKeyframeTime);
+ m_setKeyframeTimeAction->setEnabled(theHasKeysSelected);
+ addAction(m_setKeyframeTimeAction);
+}
+
+void CKeyframeContextMenu::MakeDynamic()
+{
+ if (m_TimelineItemProperty != nullptr && m_TimelineItemProperty->GetKeyframeCount() > 0) {
+ m_TimelineItemProperty->SelectKeyframes(
+ true, m_TimelineItemProperty->GetKeyframeByIndex(0)->GetTime());
+ }
+
+ CBaseKeyframeContextMenu::MakeDynamic();
+}
+
+//=============================================================================
+/**
+ * SetTime: Saves the keyframe time
+ * @param inTime is the keyframe time
+ */
+void CKeyframeContextMenu::SetTime(long inTime)
+{
+ m_Time = inTime;
+}
+
+//=============================================================================
+/**
+ * Called when the set interpolation option is taken by the user. Uses the left most
+ * selected key for the base interpolation in the dialog box. User can then set the interpolation
+ * and it is propagated to all teh keys
+ */
+void CKeyframeContextMenu::SetInterpolation()
+{
+ m_KeyframesManager->SetKeyframeInterpolation();
+}
+
+//=============================================================================
+/**
+ * SetKeyframeTime: This is the event handler that will be called when the user
+ * chooses set keyframe time from a pop up menu. This pop up
+ *menu
+ * is triggered when the user right click on the selected
+ *keyframe.
+ * It displays a time edit dialog to allow the user to set the
+ * keyframe time.
+ * @param NONE
+ * @return NONE
+ */
+void CKeyframeContextMenu::SetKeyframeTime()
+{
+ m_KeyframesManager->SetKeyframeTime(m_Time);
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.h b/src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.h
new file mode 100644
index 00000000..b11ccb2f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_KEYFRAME_CONTEXT_MENU
+#define INCLUDED_KEYFRAME_CONTEXT_MENU 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include <QMenu>
+
+class ITimelineKeyframesManager;
+class ITimelineItemProperty;
+class ITimelineTimebar;
+class ITimeChangeCallback;
+class ITimelineItemKeyframesHolder;
+class ITimebarControl;
+
+class QAction;
+
+//=============================================================================
+/**
+ * Abstract class that contain the common items for the keyframes-related context menu.
+ */
+class CBaseKeyframeContextMenu : public QMenu
+{
+ Q_OBJECT
+public:
+ CBaseKeyframeContextMenu(QWidget *parent = nullptr);
+ virtual ~CBaseKeyframeContextMenu();
+
+protected:
+ virtual void Initialize(ITimelineKeyframesManager *inKeyframesManager);
+ virtual void MakeDynamic();
+ virtual ITimelineItemKeyframesHolder *GetKeyframesHolder() { return nullptr; }
+
+protected Q_SLOTS:
+ void CutSelectedKeys();
+ void CopySelectedKeys();
+ void PasteSelectedKeys();
+ void DeleteSelectedKeys();
+ void InsertKeyframe();
+ void DeleteChannelKeys();
+
+protected:
+ bool m_HasDynamicSelectedKeyframes;
+ ITimelineKeyframesManager *m_KeyframesManager;
+ QAction *m_insertAction;
+ QAction *m_cutAction;
+ QAction *m_copyAction;
+ QAction *m_pasteAction;
+ QAction *m_deleteSelectedAction;
+ QAction *m_deleteChannelKeysAction;
+};
+
+//=============================================================================
+/**
+ * Context menu right-clicking on a timebar,
+ */
+class CTimebarKeyframeContextMenu : public CBaseKeyframeContextMenu
+{
+ Q_OBJECT
+public:
+ CTimebarKeyframeContextMenu(ITimebarControl *inTimebarControl,
+ ITimelineKeyframesManager *inKeyframesManager,
+ bool inShowTimebarPropertiesOptions = true,
+ QWidget *parent = nullptr);
+ ~CTimebarKeyframeContextMenu();
+
+protected:
+ void Initialize(ITimelineKeyframesManager *inKeyframesManager) override;
+ ITimelineItemKeyframesHolder *GetKeyframesHolder() override;
+ void MakeDynamic() override;
+
+ void ChangeTimebarColor();
+ void ChangeTimebarText();
+ void ToggleTimebarHandles();
+ void SetTimebarTime();
+
+protected:
+ ITimebarControl *m_TimebarControl;
+ bool m_ShowTimebarPropertiesOptions;
+
+ QAction *m_makeDynamicAction;
+ QAction *m_timeBarColorAction;
+ QAction *m_timeBarTextAction;
+ QAction *m_timeBarHandlesAction;
+ QAction *m_timeBarTimeAction;
+};
+
+//=============================================================================
+/**
+ * Context menu for right-clicking on selected keyframe(s)
+ * so even though the assoicated action isn't limited to the keyframe that was right-clicked on,
+ * this is still a different one from right-clicking on outside the keyframe.
+ * This is how the old system used to be.
+ */
+class CKeyframeContextMenu : public CBaseKeyframeContextMenu
+{
+ Q_OBJECT
+public:
+ CKeyframeContextMenu(ITimelineKeyframesManager *inKeyframesManager,
+ ITimelineItemProperty *inTimelineItemProperty = nullptr,
+ QWidget *parent = nullptr);
+ ~CKeyframeContextMenu();
+
+ void SetTime(long inTime);
+
+protected:
+ void Initialize(ITimelineKeyframesManager *inKeyframesManager) override;
+ void MakeDynamic() override;
+
+protected Q_SLOTS:
+ void SetInterpolation();
+ void SetKeyframeTime();
+
+protected:
+ long m_Time;
+
+private:
+ ITimelineItemProperty *m_TimelineItemProperty;
+ QAction *m_makeDynamicAction;
+ QAction *m_setKeyframeTimeAction;
+ QAction *m_setInterpolationAction;
+};
+#endif // INCLUDED_KEYFRAME_CONTEXT_MENU
diff --git a/src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.cpp b/src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.cpp
new file mode 100644
index 00000000..676a5d2d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.cpp
@@ -0,0 +1,30 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+#include "MultiSelectAspect.h"
diff --git a/src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.h b/src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.h
new file mode 100644
index 00000000..0c19b2b2
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_MULTISELECT_ASPECT_H
+#define INCLUDED_MULTISELECT_ASPECT_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "StateRow.h"
+#include "TimelineTimelineLayout.h"
+#include "Bindings/IKeyframeSelector.h"
+
+//==============================================================================
+/**
+ * This class handles the multi selection aspect for keyframes in the timeline.
+ * It toggles each keyframe's select state on or off, depending on whether the
+ * mouse rectangle is over them and if the modifier key is down.
+ */
+template <typename TSTLKeyFrameList>
+class CMultiSelectAspect
+{
+
+public:
+ typedef typename TSTLKeyFrameList::iterator TSTLKeyframesItr;
+
+protected:
+ TSTLKeyFrameList &m_STLKeyframes; ///< stores list of keyframes in a vector (STL)
+ IKeyframeSelector *m_KeyframeSelector; ///< the interface that performs the keyframes selection
+
+public:
+ //=============================================================================
+ /**
+ * Constructor
+ * @param inSTLKeyframes stores a list of keyframes in a vector
+ * @param inDoc stores the studio document
+ */
+ CMultiSelectAspect(TSTLKeyFrameList &inSTLKeyframes, IKeyframeSelector *inKeyframeSelector)
+ : m_STLKeyframes(inSTLKeyframes)
+ , m_KeyframeSelector(inKeyframeSelector)
+ {
+ }
+
+ //=============================================================================
+ /**
+ * Destructor
+ */
+ ~CMultiSelectAspect() {}
+
+ //=============================================================================
+ /**
+ * CommitSelections: Overwrites all previous keyframe states with the current keyframe states.
+ * This will prevent the keyframes in the current selection
+*from
+* switching states as we select other keyframes.
+ */
+ void CommitSelections()
+ {
+ // Iterates each keyframe and set the previous state to the current one.
+ TSTLKeyframesItr thePos = m_STLKeyframes.begin();
+ for (; thePos != m_STLKeyframes.end(); ++thePos) {
+ (*thePos)->SetPreviousSelectState((*thePos)->IsSelected());
+ }
+ }
+
+ //=============================================================================
+ /**
+ * MultiSelect: Handles the selection of keyframes in a given rect.
+ * @param inRect stores the rectangle that will be used to select the keyframes within it.
+ * @param inModifierKeyDown indicates if thte modifier key is pressed.
+ */
+ void MultiSelect(CRct inRect, bool inModifierKeyDown)
+ {
+ // Iterates through the keyframes and checks if the keys are in the rect and
+ // perform the necessary selection operations on each keyframe.
+ TSTLKeyframesItr thePos = m_STLKeyframes.begin();
+ for (; thePos != m_STLKeyframes.end(); ++thePos) {
+ bool isInRect = (*thePos)->IsInRect(inRect);
+ if ((*thePos)->IsEnabled()) {
+ if (inModifierKeyDown) {
+ if (isInRect) {
+ if (!(*thePos)->GetRectOverHandled()) {
+ bool theSelectState = (*thePos)->IsSelected();
+
+ // Update the previous select state
+ (*thePos)->SetPreviousSelectState(theSelectState);
+ // Negate the keyframe state when it is in the rectangle
+ theSelectState = !theSelectState;
+ (*thePos)->Select(theSelectState);
+ m_KeyframeSelector->SelectKeyframes(theSelectState,
+ (*thePos)->GetTime());
+
+ // Set the RectOverFlag to true, so that we will not repeat the negation
+ // in indefinitely.
+ (*thePos)->SetRectOverHandled(true);
+ }
+ } else {
+ // When the rectangle is not over the current keyframe, revert its state to
+ // the previous one
+ if ((*thePos)->IsSelected() != (*thePos)->GetPreviousSelectState()) {
+ (*thePos)->Select((*thePos)->GetPreviousSelectState());
+ m_KeyframeSelector->SelectKeyframes((*thePos)->GetPreviousSelectState(),
+ (*thePos)->GetTime());
+ }
+ (*thePos)->SetRectOverHandled(false);
+ }
+ } else {
+ // When modifier is not pressed we will just select the keyframes if it is over
+ // in the rectangle and deselect it when it isn't.
+ if ((*thePos)->IsSelected() != isInRect) {
+ (*thePos)->SetPreviousSelectState((*thePos)->IsSelected());
+ m_KeyframeSelector->SelectKeyframes(isInRect, (*thePos)->GetTime());
+ (*thePos)->Select(isInRect);
+ }
+ (*thePos)->SetRectOverHandled(false);
+ }
+ }
+ }
+ }
+};
+#endif // INCLUDED_MULTISELECT_ASPECT_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Playhead.cpp b/src/Authoring/Studio/Palettes/Timeline/Playhead.cpp
new file mode 100644
index 00000000..c010a854
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Playhead.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "Playhead.h"
+#include "Renderer.h"
+#include "TimelineTimelineLayout.h"
+#include "IDoc.h"
+#include "HotKeys.h"
+#include "ResourceCache.h"
+#include "TimeEditDlg.h"
+#include "TimeMeasure.h"
+
+//=============================================================================
+/**
+ * Create a new Playhead.
+ * The timeline is used for notifying of time changes and for scrolling.
+ * @param inTimeline the timeline that this is a part of.
+ */
+CPlayhead::CPlayhead(CTimelineTimelineLayout *inTimeline, IDoc *inDoc)
+ : m_IsMouseDown(false)
+ , m_MinimumPosition(0)
+ , m_MaximumPosition(LONG_MAX)
+ , m_InitialOffset(0)
+ , m_Doc(inDoc)
+{
+ m_Timeline = inTimeline;
+
+ m_PlayheadImage = CResourceCache::GetInstance()->GetBitmap("PlaybackHead.png");
+ SetName("Playhead");
+
+ // Set the line to the middle of this.
+ m_LinePos = GetSize().x / 2;
+ SetAlpha(128);
+}
+
+CPlayhead::~CPlayhead()
+{
+}
+
+//=============================================================================
+/**
+ * Call from the OverlayControl to perform the draw.
+ * Wish this didn't have to be a special function but...
+ * @param inRenderer the renderer to draw to.
+ */
+void CPlayhead::Draw(CRenderer *inRenderer)
+{
+ // If this goes before position then clip it at 0.
+ if (GetPosition().x < 0) {
+ CRct theClipRect(GetSize());
+ theClipRect.Offset(CPt(-GetPosition().x, 0));
+ inRenderer->PushClippingRect(theClipRect);
+ }
+
+ // Draw the playhead
+ inRenderer->DrawBitmap(CPt(0, 2), m_PlayheadImage);
+
+ // Draw the line
+ inRenderer->PushPen(CColor(255, 0, 0));
+ inRenderer->MoveTo(m_LinePos, 20);
+ inRenderer->LineTo(m_LinePos, GetSize().y - 1);
+ inRenderer->PopPen();
+
+ // If we added an extra clipping rect then remove it.
+ if (GetPosition().x < 0) {
+ inRenderer->PopClippingRect();
+ }
+}
+
+//=============================================================================
+/**
+ * Handles mouse down messages.
+ * @param inPoint where the mouse was clicked.
+ * @param inFlags the state of the mouse.
+ */
+bool CPlayhead::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ // If no one else processed it then process the command.
+ if (!COverlayControl::OnMouseDown(inPoint, inFlags)) {
+ m_Snapper.Clear();
+ m_Snapper.SetSource(this);
+ m_Timeline->PopulateSnappingList(&m_Snapper);
+
+ // m_Snapper.SetTimeOffset( m_Timeline->GetViewTimeOffset( ) );
+ m_Snapper.SetSnappingKeyframes(true);
+ m_Snapper.BeginDrag(inPoint.x, GetSize().x / 2);
+
+ m_InitialOffset = inPoint.x;
+ m_IsMouseDown = true;
+
+ m_Timeline->RecalcTime((inFlags & CHotKeys::MODIFIER_CONTROL) == 0, 0);
+ }
+
+ return true;
+}
+
+//=============================================================================
+/**
+ * Handles mouse double click messages. Pops up a time edit dialog box for
+ * modifying playhead time.
+ * @param inPoint the location of the mouse in local coordinates.
+ * @param inFlags the state of the mouse.
+ */
+bool CPlayhead::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ Q_UNUSED(inPoint);
+ Q_UNUSED(inFlags);
+
+ CTimeEditDlg theTimeEditDlg;
+ theTimeEditDlg.ShowDialog(GetCurrentTime(), 0, m_Doc, PLAYHEAD);
+ return true;
+}
+
+//=============================================================================
+/**
+ * Handles mouse move messages.
+ * @param inPoint the location of the mouse in local coordinates.
+ * @param inFlags the state of the mouse.
+ */
+void CPlayhead::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ COverlayControl::OnMouseMove(inPoint, inFlags);
+
+ // If we are down then move the playhead
+ if (m_IsMouseDown) {
+ long theTime = m_Snapper.ProcessDrag(GetCurrentTime(), inPoint.x, inFlags);
+ bool theUpdateClientTimeFlag = (inFlags & CHotKeys::MODIFIER_CONTROL) == 0;
+
+ UpdateTime(theTime, theUpdateClientTimeFlag);
+ }
+}
+
+//=============================================================================
+/**
+ * Updates the time of the active context
+ * @param inTime the new time
+ * @param inUpdateClient true if scene is to be redrawn
+ */
+void CPlayhead::UpdateTime(long inTime, bool /*inUpdateClient*/)
+{
+ // true to "check bounds" to ensure playhead is within valid range.
+ m_Doc->NotifyTimeChanged(inTime);
+}
+
+//=============================================================================
+/**
+ * Notification that the mouse was let go.
+ * @param inPoint the location of the mouse in local coordinates.
+ * @param inFlags the state of the mouse.
+ */
+void CPlayhead::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ COverlayControl::OnMouseUp(inPoint, inFlags);
+
+ m_IsMouseDown = false;
+}
+
+//=============================================================================
+/**
+ * Set the size of this control.
+ * @param inSize the size to be set.
+ */
+void CPlayhead::SetSize(CPt inSize)
+{
+ COverlayControl::SetSize(inSize);
+ // Update the line position.
+ m_LinePos = inSize.x / 2;
+}
+
+//=============================================================================
+/**
+ * Set the minimum and maximum allowed positions of the line.
+ * @param inMinimumPosition the minimum allowed position.
+ * @param inMaximumPosition the maximum allowed position.
+ */
+void CPlayhead::SetMinMaxPosition(long inMinimumPosition, long inMaximumPosition)
+{
+ m_MinimumPosition = inMinimumPosition;
+ m_MaximumPosition = inMaximumPosition;
+}
+
+long CPlayhead::GetCurrentTime()
+{
+ return m_Doc->GetCurrentViewTime();
+}
+
+//=============================================================================
+/**
+ * Check to see if inPoint is over this control or not.
+ * This overrides COverlayControl::HitTest so that the playhead line can be
+ * exempt from mouse hits.
+ * @param inPoint the location of the mouse in local coordinates.
+ */
+bool CPlayhead::HitTest(const CPt &inPoint) const
+{
+ if (inPoint.y < m_PlayheadImage.height()) {
+ return COverlayControl::HitTest(inPoint);
+ }
+ return false;
+}
+
+void CPlayhead::StepRightSmall()
+{
+ long theInterval = m_Timeline->GetTimeMeasure()->GetSmallHashInterval();
+
+ long theCurrentTime = GetCurrentTime();
+ long theTime = theCurrentTime / theInterval * theInterval + theInterval;
+ UpdateTime(theTime, true);
+}
+
+void CPlayhead::StepRightLarge()
+{
+ long theInterval = m_Timeline->GetTimeMeasure()->GetLargeHashInterval();
+
+ long theCurrentTime = GetCurrentTime();
+ long theTime = theCurrentTime / theInterval * theInterval + theInterval;
+ UpdateTime(theTime, true);
+}
+
+void CPlayhead::StepLeftSmall()
+{
+ long theInterval = m_Timeline->GetTimeMeasure()->GetSmallHashInterval();
+
+ long theCurrentTime = GetCurrentTime();
+ long theTime = theCurrentTime / theInterval * theInterval - theInterval;
+
+ UpdateTime(theTime, true);
+}
+
+void CPlayhead::StepLeftLarge()
+{
+ long theInterval = m_Timeline->GetTimeMeasure()->GetLargeHashInterval();
+
+ long theCurrentTime = GetCurrentTime();
+ long theTime = theCurrentTime / theInterval * theInterval - theInterval;
+
+ UpdateTime(theTime, true);
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Playhead.h b/src/Authoring/Studio/Palettes/Timeline/Playhead.h
new file mode 100644
index 00000000..21d21041
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Playhead.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_PLAYHEAD_H
+#define INCLUDED_PLAYHEAD_H 1
+
+#pragma once
+
+#include "OverlayControl.h"
+#include "Snapper.h"
+
+#include <QPixmap>
+
+class CTimelineTimelineLayout;
+class IDoc;
+
+class CPlayhead : public COverlayControl
+{
+public:
+ CPlayhead(CTimelineTimelineLayout *inTimeline, IDoc *inDoc);
+ virtual ~CPlayhead();
+
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void SetSize(CPt inSize) override;
+ void Draw(CRenderer *inRenderer) override;
+ void SetMinMaxPosition(long inMinimumPosition, long inMaximumPosition);
+ long GetCurrentTime();
+ bool HitTest(const CPt &inPoint) const override;
+ void StepRightSmall();
+ void StepRightLarge();
+ void StepLeftSmall();
+ void StepLeftLarge();
+
+ long GetCenterOffset() const { return m_LinePos; }
+ bool IsMouseDown() const { return m_IsMouseDown; }
+
+ void UpdateTime(long inTime, bool inUpdateClient);
+
+protected:
+ QPixmap m_PlayheadImage;
+ bool m_IsMouseDown;
+ long m_InitialOffset;
+
+ long m_MinimumPosition;
+ long m_MaximumPosition;
+ long m_LinePos;
+
+ CTimelineTimelineLayout *m_Timeline;
+
+ CSnapper m_Snapper;
+ IDoc *m_Doc;
+};
+#endif // INCLUDED_PLAYHEAD_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.cpp
new file mode 100644
index 00000000..3cffd417
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "PropertyColorControl.h"
+#include "Renderer.h"
+#include "PropertyRow.h"
+#include "StudioPreferences.h"
+#include "HotKeys.h"
+
+CPropertyColorControl::CPropertyColorControl(CPropertyRow *inPropertyRow)
+{
+ m_ParentRow = inPropertyRow;
+}
+
+CPropertyColorControl::~CPropertyColorControl()
+{
+}
+
+//==============================================================================
+/**
+ * Draw
+ *
+ * draws this object
+ *
+ * @param inRenderer a renderer object
+ */
+void CPropertyColorControl::Draw(CRenderer *inRenderer)
+{
+ // Fill the control with the solid color
+ CRct theRect(GetSize());
+ CColor theBgColor(CStudioPreferences::GetPropertyBackgroundColor());
+ inRenderer->FillSolidRect(theRect, theBgColor);
+
+ // Define the colors for the side and bottom outline
+ CColor theBorderColor(CStudioPreferences::GetPropertyFloorColor());
+
+ // Right
+ inRenderer->PushPen(theBorderColor);
+ inRenderer->MoveTo(CPt(theRect.size.x - 1, 0));
+ inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y - 1));
+
+ // Left
+ inRenderer->MoveTo(CPt(0, 0));
+ inRenderer->LineTo(CPt(0, theRect.size.y - 1));
+
+ // Bottom
+ inRenderer->MoveTo(CPt(1, theRect.size.y - 1));
+ inRenderer->LineTo(CPt(theRect.size.x - 2, theRect.size.y - 1));
+ inRenderer->PopPen();
+}
+
+//==============================================================================
+/**
+ * Handles the OnMouseDownEvent
+ */
+bool CPropertyColorControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ Q_UNUSED(inPoint);
+ m_ParentRow->Select((CHotKeys::MODIFIER_SHIFT & inFlags) == CHotKeys::MODIFIER_SHIFT);
+ return true;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.h b/src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.h
new file mode 100644
index 00000000..cc3263b8
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_PROPERTYCOLOR_CONTROL_H
+#define INCLUDED_PROPERTYCOLOR_CONTROL_H 1
+
+#pragma once
+
+#include "Control.h"
+#include "CColor.h"
+
+class CRenderer;
+class CPropertyRow;
+
+class CPropertyColorControl : public CControl
+{
+public:
+ CPropertyColorControl(CPropertyRow *inPropertyRow);
+ virtual ~CPropertyColorControl();
+
+ void SetColor(::CColor inColor);
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+ void Draw(CRenderer *inRenderer) override;
+
+protected:
+ CPropertyRow *m_ParentRow;
+};
+#endif // INCLUDED_
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.cpp
new file mode 100644
index 00000000..fd7585ac
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.cpp
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "PropertyGraphKeyframe.h"
+#include "Renderer.h"
+#include "Bindings/ITimelineItemProperty.h"
+#include "StudioUtils.h"
+#include "CColor.h"
+
+CPropertyGraphKeyframe::CPropertyGraphKeyframe(ITimelineItemProperty *inProperty,
+ long inChannelIndex, long inKeyframeTime,
+ double inTimeRatio, long inMinY, long inMaxY,
+ float inMinVal, float inMaxVal)
+ : m_Property(inProperty)
+ , m_ChannelIndex(inChannelIndex)
+ , m_KeyframeTime(inKeyframeTime)
+ , m_TimeRatio(inTimeRatio)
+ , m_MinVal(inMinVal)
+ , m_MaxVal(inMaxVal)
+ , m_MinY(inMinY)
+ , m_MaxY(inMaxY)
+ , m_IsMouseDown(false)
+{
+ SetSize(CPt(4, 4));
+ PositionKeyframe();
+}
+
+CPropertyGraphKeyframe::~CPropertyGraphKeyframe()
+{
+}
+
+long CPropertyGraphKeyframe::GetTime()
+{
+ return m_KeyframeTime;
+}
+
+long CPropertyGraphKeyframe::GetChannelIndex() const
+{
+ return m_ChannelIndex;
+}
+
+void CPropertyGraphKeyframe::PositionKeyframe()
+{
+ long theXPos = ::TimeToPos(m_KeyframeTime, m_TimeRatio);
+ float theValue = GetKeyframeValue();
+ long theYPos = (long)((1.0 - (theValue - m_MinVal) / (m_MaxVal - m_MinVal)) * (m_MaxY - m_MinY)
+ + m_MinY - GetSize().y / 2 + .5);
+
+ if (theYPos < m_MinY)
+ theYPos = m_MinY;
+ else if (theYPos > m_MaxY)
+ theYPos = m_MaxY;
+
+ SetPosition(CPt(theXPos, theYPos));
+}
+
+void CPropertyGraphKeyframe::SetTimeRatio(double inTimeRatio)
+{
+ m_TimeRatio = inTimeRatio;
+ PositionKeyframe();
+}
+
+float CPropertyGraphKeyframe::GetKeyframeValue()
+{
+ return m_Property->GetChannelValueAtTime(m_ChannelIndex, m_KeyframeTime);
+}
+
+void CPropertyGraphKeyframe::SetKeyframeValue(float inValue)
+{
+ m_Property->SetChannelValueAtTime(m_ChannelIndex, m_KeyframeTime, inValue);
+}
+
+void CPropertyGraphKeyframe::Draw(CRenderer *inRenderer)
+{
+ CPt mySize = GetSize();
+ inRenderer->MoveTo(0, 0);
+ inRenderer->LineTo(mySize.x, 0);
+ inRenderer->LineTo(mySize.x, mySize.y);
+ inRenderer->LineTo(0, mySize.y);
+ inRenderer->LineTo(0, 0);
+
+ if (m_IsMouseDown) {
+ inRenderer->FillSolidRect(CRct(GetSize()), CColor::black);
+ }
+}
+
+bool CPropertyGraphKeyframe::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseDown(inPoint, inFlags)) {
+ m_IsMouseDown = true;
+ m_MouseDownLoc = inPoint;
+ }
+ return true;
+}
+
+void CPropertyGraphKeyframe::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseUp(inPoint, inFlags);
+ m_IsMouseDown = false;
+ m_Property->CommitChangedKeyframes();
+ GetParent()->Invalidate();
+}
+
+void CPropertyGraphKeyframe::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseMove(inPoint, inFlags);
+
+ if (m_IsMouseDown) {
+ long theDiff = inPoint.y - m_MouseDownLoc.y;
+ long theYPos = GetPosition().y + theDiff;
+ if (theYPos < m_MinY)
+ theYPos = m_MinY;
+ if (theYPos > m_MaxY)
+ theYPos = m_MaxY;
+ SetPosition(GetPosition().x, theYPos);
+
+ float theValue = (m_MaxVal - m_MinVal)
+ * (((m_MaxY + m_MinY) - theYPos - GetSize().y / 2) - m_MinY) / (m_MaxY - m_MinY)
+ + m_MinVal;
+ SetKeyframeValue(theValue);
+
+ GetParent()->Invalidate();
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.h
new file mode 100644
index 00000000..daffc8ab
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_PROPERTY_GRAPH_KEYFRAME_H
+#define INCLUDED_PROPERTY_GRAPH_KEYFRAME_H 1
+
+#pragma once
+
+#include "Control.h"
+
+class ITimelineItemProperty;
+
+class CPropertyGraphKeyframe : public CControl
+{
+public:
+ CPropertyGraphKeyframe(ITimelineItemProperty *inProperty, long inChannelIndex,
+ long inKeyframeTime, double inTimeRatio, long inHeight, long inOffset,
+ float inMinVal, float inMaxVal);
+ virtual ~CPropertyGraphKeyframe();
+
+ void Draw(CRenderer *inRenderer) override;
+
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+ long GetTime();
+ long GetChannelIndex() const;
+ void SetTimeRatio(double inTimeRatio);
+ void PositionKeyframe();
+
+protected:
+ float GetKeyframeValue();
+ void SetKeyframeValue(float inValue);
+
+ ITimelineItemProperty *m_Property;
+ long m_ChannelIndex; // index that identifies the channel for a animated property
+ long m_KeyframeTime;
+ double m_TimeRatio;
+ float m_MinVal;
+ float m_MaxVal;
+ long m_MinY;
+ long m_MaxY;
+ CPt m_MouseDownLoc;
+ bool m_IsMouseDown;
+};
+#endif // INCLUDED_PROPERTY_GRAPH_KEYFRAME_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyRow.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyRow.cpp
new file mode 100644
index 00000000..986d8326
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyRow.cpp
@@ -0,0 +1,377 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "PropertyRow.h"
+#include "TimelineControl.h"
+#include "PropertyColorControl.h"
+#include "PropertyToggleControl.h"
+#include "PropertyTreeControl.h"
+#include "PropertyTimebarRow.h"
+#include "BlankControl.h"
+#include "StudioPreferences.h"
+#include "StateRow.h"
+#include "Bindings/ITimelineItemProperty.h"
+
+//=============================================================================
+/**
+ * Create a property row for inProperty.
+ * @param inProperty the property that this is displaying.
+ */
+CPropertyRow::CPropertyRow(ITimelineItemProperty *inProperty)
+ : m_Highlighted(false)
+ , m_DetailedView(false)
+ , m_TimeRatio(0.0f)
+ , m_Property(inProperty)
+{
+ m_IsViewable = true;
+
+ m_TreeControl = new CPropertyTreeControl(this);
+ m_ToggleControl = new CPropertyToggleControl(this);
+ m_TimebarRow = new CPropertyTimebarRow(this);
+
+ m_PropertyColorControl = new CPropertyColorControl(this);
+ long theTimebarHeight = CStudioPreferences::GetRowSize();
+
+ // do not set absolute size because it messes up the timeline
+ m_TreeControl->SetSize(CPt(500, theTimebarHeight));
+ m_PropertyColorControl->SetAbsoluteSize(CPt(theTimebarHeight, theTimebarHeight));
+ m_ToggleControl->SetAbsoluteSize(CPt(57, theTimebarHeight));
+ m_TimebarRow->SetSize(CPt(0, theTimebarHeight));
+
+ // sk: setting controls names' seem to be only useful for debugging.
+ // Q3DStudio::CString thePropName( inProperty->GetName( ) );
+ // m_TreeControl->SetName( thePropName );
+ // m_TimebarRow->SetName( thePropName + "TimebarRow" );
+}
+
+CPropertyRow::~CPropertyRow()
+{
+ delete m_TreeControl;
+ delete m_ToggleControl;
+ delete m_PropertyColorControl;
+ delete m_TimebarRow;
+}
+
+//=============================================================================
+/**
+ * Get the left hand color control for this row.
+ * @return the color control for this row.
+ */
+CControl *CPropertyRow::GetColorControl()
+{
+ return m_PropertyColorControl;
+}
+
+//=============================================================================
+/**
+ * Get the tree control object for this row.
+ * @return the tree control object for this row.
+ */
+CControl *CPropertyRow::GetTreeControl()
+{
+ return m_TreeControl;
+}
+
+//=============================================================================
+/**
+ * Get the toggle control object for this row.
+ * @return the toggle control object for this row.
+ */
+CControl *CPropertyRow::GetToggleControl()
+{
+ return m_ToggleControl;
+}
+
+//=============================================================================
+/**
+ * Get the timebar control for this row.
+ * @return the timebar control for this row.
+ */
+CControl *CPropertyRow::GetTimebarControl()
+{
+ return m_TimebarRow;
+}
+
+//=============================================================================
+/**
+ * Set the amount that this row is indented.
+ * This handles the tree indenting.
+ * @param inIndent the amount of indent for this row.
+ */
+void CPropertyRow::SetIndent(long inIndent)
+{
+ m_TreeControl->SetIndent(inIndent);
+}
+
+//=============================================================================
+/**
+ * Notification from one of the child controls that the mouse just entered.
+ * This is used to handle the highlighting of the entire row.
+ */
+void CPropertyRow::OnMouseOver()
+{
+ // Only change if change is needed
+ if (!m_Highlighted) {
+ m_TreeControl->SetHighlighted(true);
+ m_ToggleControl->SetHighlighted(true);
+ m_TimebarRow->SetHighlighted(true);
+
+ m_Highlighted = true;
+ }
+}
+
+//=============================================================================
+/**
+ * Notification from one of the child controls that the mouse just left.
+ * This is used to handle the highlighting of the entire row.
+ */
+void CPropertyRow::OnMouseOut()
+{
+ // Only change is change is needed.
+ if (m_Highlighted) {
+ m_TreeControl->SetHighlighted(false);
+ m_ToggleControl->SetHighlighted(false);
+ m_TimebarRow->SetHighlighted(false);
+
+ m_Highlighted = false;
+ }
+}
+
+//=============================================================================
+/**
+ * Double click handler for the property row
+ */
+void CPropertyRow::OnMouseDoubleClick()
+{
+ SetDetailedView(!m_DetailedView);
+}
+
+//=============================================================================
+/**
+ * Expands the row out so a more detailed view of the animation tracks can be seen
+ *
+ * @param inIsInDetailedView true if we are switching to a detailed view
+ */
+void CPropertyRow::SetDetailedView(bool inIsDetailedView)
+{
+ m_DetailedView = inIsDetailedView;
+
+ if (m_DetailedView) {
+ long theHeight = 100;
+ m_PropertyColorControl->SetAbsoluteSize(
+ CPt(m_PropertyColorControl->GetSize().x, theHeight));
+ m_TreeControl->SetSize(CPt(m_TreeControl->GetSize().x, theHeight));
+ m_ToggleControl->SetAbsoluteSize(CPt(m_ToggleControl->GetSize().x, theHeight));
+ m_TimebarRow->SetAbsoluteSize(CPt(m_TimebarRow->GetSize().x, theHeight));
+
+ m_TimebarRow->SetDetailedView(true);
+ } else {
+ long theDefaultHeight = CStudioPreferences::GetRowSize();
+
+ m_PropertyColorControl->SetAbsoluteSize(
+ CPt(m_PropertyColorControl->GetSize().x, theDefaultHeight));
+ m_TreeControl->SetSize(CPt(m_TreeControl->GetSize().x, theDefaultHeight));
+ m_ToggleControl->SetAbsoluteSize(CPt(m_ToggleControl->GetSize().x, theDefaultHeight));
+ m_TimebarRow->SetAbsoluteSize(CPt(m_TimebarRow->GetSize().x, theDefaultHeight));
+
+ m_TimebarRow->SetDetailedView(false);
+ }
+
+ GetTopControl()->OnLayoutChanged();
+}
+
+//=============================================================================
+/**
+ * Filter this property.
+ * This controls whether or not this row should be displayed. The filter will
+ * be stored and used for future operations that may change whether or not
+ * this should be visible.
+ * @param inFilter the filter to filter on.
+ * @param inFilterChildren true if the call is recursive.
+ */
+void CPropertyRow::Filter(const CFilter &inFilter, bool inFilterChildren /*= true*/)
+{
+ Q_UNUSED(inFilterChildren);
+
+ m_Filter = inFilter;
+
+ bool theVisibleFlag = inFilter.Filter(m_Property);
+ m_TreeControl->SetVisible(theVisibleFlag);
+ m_TimebarRow->SetVisible(theVisibleFlag);
+ m_ToggleControl->SetVisible(theVisibleFlag);
+ m_PropertyColorControl->SetVisible(theVisibleFlag);
+ m_IsViewable = theVisibleFlag;
+}
+
+//=============================================================================
+/**
+ * @return true if this property is animated and is not currently being filtered out
+ */
+bool CPropertyRow::IsViewable() const
+{
+ return m_Filter.GetProperties();
+}
+
+//=============================================================================
+/**
+ * Call from one of the child controls to select this object.
+ * Currently this just causes the Asset to be selected.
+ */
+void CPropertyRow::Select(bool inIsShiftKeyPressed /*= false */)
+{
+ m_Property->SetSelected();
+
+ if (inIsShiftKeyPressed)
+ m_TimebarRow->SelectAllKeys();
+ else
+ m_Property->ClearKeySelection();
+}
+
+ISnappingListProvider *CPropertyRow::GetSnappingListProvider() const
+{
+ return &m_TimebarRow->GetSnappingListProvider();
+}
+
+void CPropertyRow::SetSnappingListProvider(ISnappingListProvider *inProvider)
+{
+ m_TimebarRow->SetSnappingListProvider(inProvider);
+}
+
+//=============================================================================
+/**
+ * Retrieves the background color for the row based upon the type of asset
+ * passed in. Overridden so that properties can have a different background
+ * color than their parent asset does.
+ * @return background color to use for this row
+ */
+::CColor CPropertyRow::GetTimebarBackgroundColor()
+{
+ return CStudioPreferences::GetPropertyBackgroundColor();
+}
+
+//=============================================================================
+/**
+ * Retrieves the background color for the row when the mouse is over the row
+ * based upon the type of asset passed in. Overridden so that properties can
+ * have a different highlight background color than their parent asset does.
+ * @return background color to use for this row when the mouse is over it
+ */
+::CColor CPropertyRow::GetTimebarHighlightBackgroundColor()
+{
+ return CStudioPreferences::GetPropertyMouseOverColor();
+}
+
+//=============================================================================
+/**
+ * Set the amount of time that is represented by a pixel.
+ * This modifies the length of this control.
+ * @param inTimePerPixel the time per pixel.
+ */
+void CPropertyRow::SetTimeRatio(double inTimeRatio)
+{
+ m_TimeRatio = inTimeRatio;
+ m_TimebarRow->SetTimeRatio(inTimeRatio);
+}
+
+//=============================================================================
+/**
+ * Selects all keyframes of this property that are inside inRect
+ *
+ * @param inRect theRect to check
+ */
+void CPropertyRow::SelectKeysInRect(CRct inRect, bool inModifierKeyDown)
+{
+ CRct theOffsetRect = inRect;
+ CRct myRect(CPt(0, 0), m_TimebarRow->GetSize());
+ theOffsetRect.Offset(-m_TimebarRow->GetPosition());
+ m_TimebarRow->SelectKeysInRect(theOffsetRect, inModifierKeyDown);
+}
+
+//=============================================================================
+/**
+ * CommitSelections: commits all the property keyframe selections by setting their
+ * previous selection state to the current selection state.
+ * This will prevent the keyframes in the current selection
+ *from
+ * switching states as we select other keyframes.
+ *
+ * @param NONE
+ * @return NONE
+ */
+void CPropertyRow::CommitSelections()
+{
+ m_TimebarRow->CommitSelections();
+}
+
+//=============================================================================
+/**
+ * Selects all keyframes
+ */
+void CPropertyRow::SelectAllKeys()
+{
+ m_TimebarRow->SelectAllKeys();
+}
+
+//=============================================================================
+/**
+ * Deletes keyframes on this property row
+ */
+void CPropertyRow::DeleteAllKeys()
+{
+ m_Property->DeleteAllKeys();
+ m_TimebarRow->Invalidate();
+}
+
+//=============================================================================
+/**
+ * Sets all the child control enable states
+ * @param inEnabled the state to set the controls to
+ */
+void CPropertyRow::SetEnabled(bool inEnabled)
+{
+ m_TreeControl->SetEnabled(inEnabled);
+ m_ToggleControl->SetEnabled(inEnabled);
+ m_PropertyColorControl->SetEnabled(inEnabled);
+ m_TimebarRow->SetEnabled(inEnabled);
+}
+
+//=============================================================================
+/**
+ * Callback from the ITimelineProperty.
+ */
+void CPropertyRow::Refresh()
+{
+ if (m_TimebarRow->IsVisible())
+ m_TimebarRow->SetDirty(true);
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyRow.h b/src/Authoring/Studio/Palettes/Timeline/PropertyRow.h
new file mode 100644
index 00000000..49ca60a7
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyRow.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_PROPERTY_ROW_H
+#define INCLUDED_PROPERTY_ROW_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+
+#include "TimelineRow.h"
+#include "StateRow.h"
+#include "Rct.h"
+#include <vector>
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CPropertyColorControl;
+class CBlankControl;
+class CPropertyTreeControl;
+class CPropertyToggleControl;
+class CPropertyTimebarRow;
+class ITimelineItemProperty;
+
+class CPropertyRow : public CTimelineRow
+{
+public:
+ CPropertyRow(ITimelineItemProperty *inProperty);
+ virtual ~CPropertyRow();
+ CControl *GetColorControl() override;
+ CControl *GetTreeControl() override;
+ CControl *GetToggleControl() override;
+ CControl *GetTimebarControl() override;
+
+ void SetTimeRatio(double inTimePerPixel) override;
+ void SetIndent(long inIndent) override;
+ void Filter(const CFilter &inFilter, bool inFilterChildren = true) override;
+ void OnMouseOver();
+ void OnMouseOut();
+ void OnMouseDoubleClick();
+ void Select(bool inIsShiftKeyPressed = false);
+ void SetDetailedView(bool inIsInDetailedView);
+ void CommitSelections();
+ void SelectKeysInRect(CRct inRect, bool inModifierKeyDown);
+ void SelectAllKeys();
+ void DeleteAllKeys();
+ bool IsViewable() const override;
+ void SetEnabled(bool inEnabled);
+
+ ISnappingListProvider *GetSnappingListProvider() const override;
+ void SetSnappingListProvider(ISnappingListProvider *inProvider) override;
+ using CTimelineRow::GetTimebarBackgroundColor;
+ virtual ::CColor GetTimebarBackgroundColor();
+ using CTimelineRow::GetTimebarHighlightBackgroundColor;
+ virtual ::CColor GetTimebarHighlightBackgroundColor();
+
+ void Refresh();
+ ITimelineItemProperty *GetProperty() const { return m_Property; }
+
+ CPropertyTimebarRow *GetTimebar() { return m_TimebarRow; }
+
+protected:
+ CPropertyTreeControl *m_TreeControl;
+ CPropertyToggleControl *m_ToggleControl;
+ CPropertyColorControl *m_PropertyColorControl;
+ CPropertyTimebarRow *m_TimebarRow;
+ bool m_Highlighted;
+ bool m_DetailedView;
+ double m_TimeRatio;
+ CFilter m_Filter;
+ ITimelineItemProperty *m_Property;
+};
+#endif // INCLUDED_PROPERTY_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.cpp
new file mode 100644
index 00000000..ecd3b5df
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.cpp
@@ -0,0 +1,234 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "PropertyTimebarGraph.h"
+#include "IKeyframe.h"
+#include "Renderer.h"
+#include "PropertyGraphKeyframe.h"
+#include "Bindings/ITimelineItemProperty.h"
+#include "StudioUtils.h"
+
+//=============================================================================
+/**
+ * Create a graph for the specified property.
+ * @param inProperty the property this is graphing.
+ */
+CPropertyTimebarGraph::CPropertyTimebarGraph(ITimelineItemProperty *inProperty)
+ : m_Property(inProperty)
+ , m_TimeRatio(0.0f)
+ , m_MaxVal(0.0f)
+ , m_MinVal(0.0f)
+ , m_MinY(0)
+ , m_MaxY(0)
+{
+}
+
+CPropertyTimebarGraph::~CPropertyTimebarGraph()
+{
+ TKeyframeList::iterator thePos = m_Keyframes.begin();
+ for (; thePos != m_Keyframes.end(); ++thePos)
+ delete (*thePos);
+}
+
+//=============================================================================
+/**
+ * Toggle whether this is visible or not.
+ * Overrides CControl::SetVisible. If this is not visible then it removes
+ * a bunch of the refresh logic to speed stuff up.
+ * @param inIsVisible true if this control is to be visible.
+ */
+void CPropertyTimebarGraph::SetVisible(bool inIsVisible)
+{
+ CControl::SetVisible(inIsVisible);
+
+ // If this is visible then add the appropriate keyframes and listeners.
+ if (inIsVisible) {
+ m_MaxVal = m_Property->GetMaximumValue();
+ m_MinVal = m_Property->GetMinimumValue();
+
+ m_MinY = 10;
+ m_MaxY = GetSize().y - m_MinY;
+
+ RefreshKeyframes();
+ } else
+ RemoveKeyframes();
+}
+
+//=============================================================================
+/**
+ * Set the time ratio for this display.
+ * The time ratio controls how much time is displayed in how much space.
+ * @param inTimeRatio the time ratio.
+ */
+void CPropertyTimebarGraph::SetTimeRatio(double inTimeRatio)
+{
+ m_TimeRatio = inTimeRatio;
+}
+
+//=============================================================================
+/**
+ * Draw this to the specified renderer.
+ * This will perform the graphing of all the channels on the property.
+ * @param inRenderer the renderer to draw to.
+ */
+void CPropertyTimebarGraph::Draw(CRenderer *inRenderer)
+{
+ CRct theRect(CPt(0, 0), GetSize());
+ inRenderer->PushClippingRect(theRect);
+
+ // the available line colors, tried to use Rainbow.bvs code to do it dynamically but didn't
+ // quite work.
+ ::CColor theColors[6] = { ::CColor(255, 0, 0), ::CColor(0, 255, 0), ::CColor(0, 0, 255),
+ ::CColor(255, 255, 0), ::CColor(255, 0, 255), ::CColor(0, 255, 255) };
+
+ long theChannelCount = m_Property->GetChannelCount();
+ // Don't want to overflow the color array
+ if (theChannelCount <= 6) {
+ // For each channel graph it.
+ for (long theIndex = 0; theIndex < theChannelCount; ++theIndex)
+ DrawDetailedChannel(inRenderer, theIndex, theColors[theIndex]);
+ }
+
+ inRenderer->PopClippingRect();
+}
+
+void CPropertyTimebarGraph::DrawDetailedChannel(CRenderer *inRenderer, long inChannelIndex,
+ ::CColor inColor)
+{
+ inRenderer->PushPen(inColor, 2);
+
+ CRct theClipRect = inRenderer->GetClippingRect();
+ float theValue = m_Property->GetChannelValueAtTime(inChannelIndex, 0);
+ long theYPos = (long)((1.0 - (theValue - m_MinVal) / (m_MaxVal - m_MinVal)) * (m_MaxY - m_MinY)
+ + m_MinY + .5);
+
+ inRenderer->MoveTo(CPt(0, theYPos));
+
+ long theInterval = 5;
+ long theSize = theClipRect.position.x + theClipRect.size.x + theInterval;
+
+ for (long thePixel = theClipRect.position.x; thePixel < theSize; thePixel += theInterval) {
+ long theTime = ::PosToTime(thePixel, m_TimeRatio); //(long)( thePixel / m_TimeRatio + .5 );
+ theValue = m_Property->GetChannelValueAtTime(inChannelIndex, theTime);
+ theYPos = (long)((1.0 - (theValue - m_MinVal) / (m_MaxVal - m_MinVal)) * (m_MaxY - m_MinY)
+ + m_MinY + .5);
+
+ inRenderer->LineTo(CPt(thePixel, theYPos));
+ }
+
+ inRenderer->PopPen();
+}
+
+void CPropertyTimebarGraph::AddKeyframes()
+{
+ long theChannelCount = m_Property->GetChannelCount();
+ long theKeyframeCount =
+ m_Property->GetKeyframeCount(); // the way it works now (and hence the assumption is), the
+ // number of keyframes for all the channels is the same.
+ for (long theIndex = 0; theIndex < theChannelCount; ++theIndex) {
+ for (long theKeyIndex = 0; theKeyIndex < theKeyframeCount; ++theKeyIndex) {
+ CPropertyGraphKeyframe *theGraphKeyframe = new CPropertyGraphKeyframe(
+ m_Property, theIndex, m_Property->GetKeyframeByIndex(theKeyIndex)->GetTime(),
+ m_TimeRatio, m_MinY, m_MaxY, m_MinVal, m_MaxVal);
+ AddChild(theGraphKeyframe);
+ m_Keyframes.push_back(theGraphKeyframe);
+ }
+ }
+}
+
+void CPropertyTimebarGraph::Invalidate(bool inIsInvalidated)
+{
+ CControl::Invalidate(inIsInvalidated);
+
+ if (inIsInvalidated && GetParent() != nullptr) {
+ GetParent()->Invalidate(inIsInvalidated);
+ }
+}
+
+void CPropertyTimebarGraph::RemoveKeyframes()
+{
+ TKeyframeList::iterator thePos = m_Keyframes.begin();
+ for (; thePos != m_Keyframes.end(); ++thePos) {
+ CPropertyGraphKeyframe *theKeyframe = (*thePos);
+ RemoveChild(theKeyframe);
+ delete theKeyframe;
+ }
+ m_Keyframes.clear();
+}
+
+void CPropertyTimebarGraph::RefreshKeyframes()
+{
+ TKeyframeList::iterator thePos = m_Keyframes.begin();
+ while (thePos != m_Keyframes.end()) {
+ CPropertyGraphKeyframe *theKeyframe = (*thePos);
+ if (m_Property->GetKeyframeByTime(theKeyframe->GetTime())) {
+ theKeyframe->PositionKeyframe();
+ ++thePos;
+ } else {
+ RemoveChild(theKeyframe);
+ delete theKeyframe;
+ thePos = m_Keyframes.erase(thePos);
+ }
+ }
+ long theChannelCount = m_Property->GetChannelCount();
+ long theKeyframeCount =
+ m_Property->GetKeyframeCount(); // the way it works now (and hence the assumption is), the
+ // number of keyframes for all the channels is the same.
+ for (long theIndex = 0; theIndex < theChannelCount; ++theIndex) {
+ for (long theKeyIndex = 0; theKeyIndex < theKeyframeCount; ++theKeyIndex) {
+ IKeyframe *theKeyframe = m_Property->GetKeyframeByIndex(theKeyIndex);
+ CPropertyGraphKeyframe *theExistingKeyframe =
+ GetKeyframe(theKeyframe->GetTime(), theIndex);
+ if (!theExistingKeyframe) {
+ CPropertyGraphKeyframe *theGraphKeyframe =
+ new CPropertyGraphKeyframe(m_Property, theIndex, theKeyframe->GetTime(),
+ m_TimeRatio, m_MinY, m_MaxY, m_MinVal, m_MaxVal);
+ AddChild(theGraphKeyframe);
+
+ m_Keyframes.push_back(theGraphKeyframe);
+ }
+ }
+ }
+
+ Invalidate();
+}
+
+CPropertyGraphKeyframe *CPropertyTimebarGraph::GetKeyframe(long inTime, long inChannelIndex)
+{
+ TKeyframeList::iterator thePos = m_Keyframes.begin();
+ for (; thePos != m_Keyframes.end(); ++thePos) {
+ CPropertyGraphKeyframe *theKeyframe = (*thePos);
+ if (theKeyframe->GetChannelIndex() == inChannelIndex && theKeyframe->GetTime() == inTime) {
+ return theKeyframe;
+ }
+ }
+ return nullptr;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.h b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.h
new file mode 100644
index 00000000..76379bcd
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_PROPERTY_TIMEBAR_GRAPH_H
+#define INCLUDED_PROPERTY_TIMEBAR_GRAPH_H 1
+
+#pragma once
+
+#include "Control.h"
+#include "CColor.h"
+
+class CPropertyGraphKeyframe;
+class ITimelineItemProperty;
+
+class CPropertyTimebarGraph : public CControl
+{
+ typedef std::vector<CPropertyGraphKeyframe *> TKeyframeList;
+
+public:
+ CPropertyTimebarGraph(ITimelineItemProperty *inProperty);
+ virtual ~CPropertyTimebarGraph();
+ void SetVisible(bool inIsVisible) override;
+ void Draw(CRenderer *inRenderer) override;
+ void SetTimeRatio(double inTimeRatio);
+ void Invalidate(bool inIsInvalidated = true) override;
+ void RefreshKeyframes();
+
+protected:
+ void DrawDetailedChannel(CRenderer *inRenderer, long inChannelIndex, ::CColor inColor);
+ void AddKeyframes();
+ void RemoveKeyframes();
+
+ CPropertyGraphKeyframe *GetKeyframe(long inTime, long inChannelIndex);
+
+protected:
+ ITimelineItemProperty *m_Property;
+ double m_TimeRatio;
+ TKeyframeList m_Keyframes;
+ float m_MaxVal;
+ float m_MinVal;
+ long m_MinY;
+ long m_MaxY;
+};
+#endif // INCLUDED_PROPERTY_TIMEBAR_GRAPH_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.cpp
new file mode 100644
index 00000000..428777a8
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.cpp
@@ -0,0 +1,508 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "PropertyTimebarRow.h"
+#include "Renderer.h"
+#include "StudioPreferences.h"
+#include "StudioUtils.h"
+#include "PropertyRow.h"
+#include "MasterP.h"
+#include "KeyframeContextMenu.h"
+#include "PropertyTimelineKeyframe.h"
+#include "HotKeys.h"
+#include "MultiSelectAspect.h"
+#include "Bindings/ITimelineItemProperty.h"
+#include "IKeyframe.h"
+#include "CoreUtils.h"
+
+//=============================================================================
+/**
+ */
+CPropertyTimebarRow::CPropertyTimebarRow(CPropertyRow *inPropertyRow)
+ : m_PropertyRow(inPropertyRow)
+ , m_DetailedView(inPropertyRow->GetProperty())
+ , m_DirtyFlag(false)
+ , m_Refreshing(false)
+ , m_SnappingListProvider(nullptr)
+{
+ m_DetailedView.SetVisible(false);
+
+ m_BackgroundColor = m_PropertyRow->GetTimebarBackgroundColor();
+
+ AddChild(&m_DetailedView);
+ m_Refreshing = false;
+ RefreshKeyframes();
+}
+
+CPropertyTimebarRow::~CPropertyTimebarRow()
+{
+ TTimelineKeyframeList::iterator thePos = m_Keyframes.begin();
+ for (; thePos != m_Keyframes.end(); ++thePos) {
+ CPropertyTimelineKeyframe *theDeletedKey = (*thePos);
+ RemoveChild(theDeletedKey);
+ delete theDeletedKey;
+ }
+}
+
+//=============================================================================
+/**
+ * Draws the this row background.
+ * @param inRenderer the renderer to draw to.
+ */
+void CPropertyTimebarRow::Draw(CRenderer *inRenderer)
+{
+ if (m_DirtyFlag) {
+ RefreshKeyframes();
+ m_DirtyFlag = false;
+ }
+
+ CRct theRect(GetSize());
+ UICDM::TDataTypePair theType = m_PropertyRow->GetProperty()->GetType();
+ if (theType.first == UICDM::DataModelDataType::Float3
+ && theType.second == UICDM::AdditionalMetaDataType::Color) {
+ inRenderer->FillSolidRect(CRct(0, 0, theRect.size.x, theRect.size.y - 1),
+ m_BackgroundColor);
+ DrawColor(inRenderer);
+ } else {
+ inRenderer->FillSolidRect(CRct(0, 0, theRect.size.x, theRect.size.y - 1),
+ m_BackgroundColor);
+ }
+
+ inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor());
+ inRenderer->MoveTo(CPt(0, theRect.size.y - 1));
+ inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y - 1));
+ inRenderer->PopPen();
+}
+
+//=============================================================================
+/**
+ * Draw a colorized background for this property row.
+ * If this is a color object then this will draw the background of this control
+ * as the color that the property is. This will draw a gradient between the
+ * colors over time to show somewhat what the colors look like.
+ * @param inRenderer the renderer to draw to.
+ */
+void CPropertyTimebarRow::DrawColor(CRenderer *inRenderer)
+{
+ UICPROFILE(DrawColor);
+
+ ITimelineItemProperty *theProperty = m_PropertyRow->GetProperty();
+ ASSERT(theProperty->GetChannelCount() == 3); // sanity check
+
+ CColor thePreviousColor;
+ thePreviousColor.SetRed(::dtol(theProperty->GetChannelValueAtTime(0, 0)));
+ thePreviousColor.SetGreen(::dtol(theProperty->GetChannelValueAtTime(1, 0)));
+ thePreviousColor.SetBlue(::dtol(theProperty->GetChannelValueAtTime(2, 0)));
+
+ long thePreviousTime = 0;
+ long theLastPosition = 0;
+ CColor theCurrentColor;
+
+ long theKeyframeCount = theProperty->GetKeyframeCount();
+
+ // Go through all the keyframes and draw a gradient from the previous key to the current key.
+ // Only use the first channel for the keyframes, assume they are all at the same time.
+ for (long theIndex = 0; theIndex < theKeyframeCount; ++theIndex) {
+ long theCurrentTime = theProperty->GetKeyframeByIndex(theIndex)->GetTime();
+ // Get the color at the specified time.
+ theCurrentColor.SetRed(::dtol(theProperty->GetChannelValueAtTime(0, theCurrentTime)));
+ theCurrentColor.SetGreen(::dtol(theProperty->GetChannelValueAtTime(1, theCurrentTime)));
+ theCurrentColor.SetBlue(::dtol(theProperty->GetChannelValueAtTime(2, theCurrentTime)));
+
+ long thePreviousPixel = ::TimeToPos(thePreviousTime, m_TimeRatio);
+ long theCurrentPixel = ::TimeToPos(theCurrentTime, m_TimeRatio);
+
+ // Draw a gradient from the previous keyframe position to the current one.
+ inRenderer->DrawGradient(
+ CRct(thePreviousPixel, 0, theCurrentPixel - thePreviousPixel, GetSize().y),
+ thePreviousColor, theCurrentColor);
+ thePreviousTime = theCurrentTime;
+ thePreviousColor = theCurrentColor;
+ theLastPosition = theCurrentPixel;
+ }
+ // Fill in from the last keyframe to the end of the bar.
+ inRenderer->DrawGradient(CRct(theLastPosition, 0, GetSize().x - theLastPosition, GetSize().y),
+ thePreviousColor, thePreviousColor);
+}
+
+//=============================================================================
+/**
+ * OnMouseOver event, handles the highlighting of the row.
+ * @param inPoint the location of the mouse over this control.
+ * @param inFlags the mouse state flags.
+ */
+void CPropertyTimebarRow::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOver(inPoint, inFlags);
+
+ m_PropertyRow->OnMouseOver();
+}
+
+//=============================================================================
+/**
+ * OnMouseOut event, handles the de-highlighting of this row.
+ * @param inPoint the location of the mouse over this control.
+ * @param inFlags the mouse state flags.
+ */
+void CPropertyTimebarRow::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOut(inPoint, inFlags);
+
+ m_PropertyRow->OnMouseOut();
+}
+
+//=============================================================================
+/**
+ * OnMouseRDown event, pops up a context menu
+ * @param inPoint the location of the mouse over this control.
+ * @param inFlags the modifier key states (shift, alt, and ctrl).
+ */
+bool CPropertyTimebarRow::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ // Only do it if a child has not handled the mouse down.
+ bool theRetVal = CControl::OnMouseRDown(inPoint, inFlags);
+ if (!theRetVal) {
+ m_PropertyRow->Select();
+ CKeyframeContextMenu theMenu(m_PropertyRow->GetProperty()->GetKeyframesManager(),
+ m_PropertyRow->GetProperty());
+ DoPopup(&theMenu, inPoint);
+ theRetVal = true;
+ }
+
+ return theRetVal;
+}
+
+//=============================================================================
+/**
+ * OnMouseOut event, handles the de-highlighting of this row.
+ * @param inPoint the location of the mouse over this control.
+ * @param inFlags the mouse state flags.
+ */
+void CPropertyTimebarRow::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ UICPROFILE(OnMouseMove);
+ CControl::OnMouseMove(inPoint, inFlags);
+}
+//=============================================================================
+/**
+ * Set this control to being highlighted or not.
+ * @param inIsHighlighted true if this is to be highlighted.
+ */
+void CPropertyTimebarRow::SetHighlighted(bool inIsHighlighted)
+{
+ if (inIsHighlighted)
+ m_BackgroundColor = m_PropertyRow->GetTimebarHighlightBackgroundColor();
+ else
+ m_BackgroundColor = m_PropertyRow->GetTimebarBackgroundColor();
+
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Get the state row that this belongs to.
+ */
+CPropertyRow *CPropertyTimebarRow::GetPropertyRow()
+{
+ return m_PropertyRow;
+}
+
+//=============================================================================
+/**
+ * Sets teh time ratio
+ *
+ * @param inTimeRatio the new ratio
+ */
+void CPropertyTimebarRow::SetTimeRatio(double inTimeRatio)
+{
+ m_TimeRatio = inTimeRatio;
+
+ TTimelineKeyframeList::iterator thePos = m_Keyframes.begin();
+ for (; thePos != m_Keyframes.end(); ++thePos) {
+ (*thePos)->SetTimeRatio(inTimeRatio);
+ }
+ m_DetailedView.SetTimeRatio(inTimeRatio);
+
+ Invalidate();
+}
+
+void CPropertyTimebarRow::SetDetailedView(bool inDetailedView)
+{
+ m_DetailedView.SetVisible(inDetailedView);
+}
+
+//=============================================================================
+/**
+ * Sets teh size of this control.
+ * @param inSize size to set the row
+ */
+void CPropertyTimebarRow::SetSize(CPt inSize)
+{
+ CControl::SetSize(inSize);
+
+ m_DetailedView.SetSize(inSize);
+}
+
+//=============================================================================
+/**
+ * called when keyframes need to be updated, this funciton has two loops:
+ * the first loops through and deletes any keys no longer in the sskf list. the
+ * second adds any keys in the sskf list that are not already in the list
+ *
+ */
+void CPropertyTimebarRow::RefreshKeyframes()
+{
+ m_Refreshing = true;
+ UICPROFILE(RefreshKeyframes);
+
+ // First Loop clears any keys that do not correlate to a supersetkey
+ TTimelineKeyframeList::iterator thePos = m_Keyframes.begin();
+ while (thePos != m_Keyframes.end()) {
+ CPropertyTimelineKeyframe *theTimelineKey = (*thePos);
+ CPt theSize = theTimelineKey->GetSize();
+ IKeyframe *theTempKey = nullptr;
+ theTempKey = m_PropertyRow->GetProperty()->GetKeyframeByTime(theTimelineKey->GetTime());
+
+ // If we find a key at this time, then the timeline key doesn't need to be deleted
+ if (!theTempKey) {
+ RemoveChild(theTimelineKey);
+ delete theTimelineKey;
+ thePos = m_Keyframes.erase(thePos);
+ } else if (theTempKey->IsDynamic() != theTimelineKey->IsDynamic()) {
+ theTimelineKey->SetDynamic(theTempKey->IsDynamic());
+ } else {
+ // Set the position
+ theTimelineKey->SetPosition(
+ ::TimeToPos(theTempKey->GetTime(), m_TimeRatio) - (theSize.x / 2), 0);
+ ++thePos;
+ }
+ }
+
+ // Second Loop adds teh remaining keys
+ long theKeyframeCount = m_PropertyRow->GetProperty()->GetKeyframeCount();
+ for (long theKey = 0; theKey < theKeyframeCount; ++theKey) {
+ bool theFoundFlag = false;
+ IKeyframe *theTempKey = m_PropertyRow->GetProperty()->GetKeyframeByIndex(theKey);
+ TTimelineKeyframeList::iterator thePos = m_Keyframes.begin();
+
+ long theKeyframeTime = theTempKey->GetTime();
+ // each key needs to be compared to all the keys in the sskf list to see if it has to be
+ // added.
+ for (; thePos != m_Keyframes.end() && !theFoundFlag; ++thePos) {
+ CPropertyTimelineKeyframe *theCurrentKey = (*thePos);
+ if (theCurrentKey->GetTime() == theKeyframeTime) {
+ theFoundFlag = true;
+ }
+ }
+ if (!theFoundFlag) {
+ // If we don't have a timeline key, then we have to make a new one
+ CPropertyTimelineKeyframe *thePropertyTimelineKey =
+ new CPropertyTimelineKeyframe(this, m_TimeRatio);
+ thePropertyTimelineKey->SetTime(theKeyframeTime);
+ thePropertyTimelineKey->Select(theTempKey->IsSelected());
+ thePropertyTimelineKey->SetDynamic(theTempKey->IsDynamic());
+ thePropertyTimelineKey->SetSize(CPt(15, 16));
+ CPt theSize = thePropertyTimelineKey->GetSize();
+ long theXPosition = ::TimeToPos(theKeyframeTime, m_TimeRatio) - (theSize.x / 2);
+ thePropertyTimelineKey->SetPosition(theXPosition, 0);
+ AddChild(thePropertyTimelineKey);
+ m_Keyframes.push_back(thePropertyTimelineKey);
+ }
+ }
+
+ if (m_DetailedView.IsVisible())
+ m_DetailedView.RefreshKeyframes();
+
+ m_Refreshing = false;
+}
+
+void CPropertyTimebarRow::Invalidate(bool inInvalidate)
+{
+ if (!m_Refreshing) {
+ CControl::Invalidate(inInvalidate);
+ }
+}
+
+//=============================================================================
+/**
+ * Handler for when a child key is selected
+ *
+ * @param inTime time of the key
+ */
+void CPropertyTimebarRow::OnKeySelected(long inTime, bool inSelected)
+{
+ if (inTime >= 0) {
+ m_PropertyRow->GetProperty()->SelectKeyframes(inSelected, inTime);
+ Invalidate();
+ }
+}
+
+//=============================================================================
+/**
+ * Deselects all keyframes
+ */
+void CPropertyTimebarRow::DeselectAllKeyframes()
+{
+ m_PropertyRow->GetProperty()->SelectKeyframes(false);
+}
+
+//=============================================================================
+/**
+ * called when a child changes and the keyframes need to be refreshed
+ *
+ * @param inDirtyFlag true if this object is now dirty
+ *
+ */
+void CPropertyTimebarRow::SetDirty(bool inDirtyFlag)
+{
+ if (m_DirtyFlag == inDirtyFlag)
+ return;
+
+ m_DirtyFlag = inDirtyFlag;
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * SelectKeysInRect: selects any keyframes inside the rect
+ *
+ * @param inRect is used to select keyframes
+ * @param inModifierKeyDown indicates if the control modifier is down
+ */
+void CPropertyTimebarRow::SelectKeysInRect(CRct inRect, bool inModifierKeyDown)
+{
+ CMultiSelectAspect<TTimelineKeyframeList> theMultiSelectAspect(m_Keyframes,
+ m_PropertyRow->GetProperty());
+ theMultiSelectAspect.MultiSelect(inRect, inModifierKeyDown);
+}
+
+//=============================================================================
+/**
+ * CommitSelections: commits all the master keyframe selections by setting their
+ * previous selection state to the current selection state.
+ * This will prevent the keyframes in the current selection
+ *from
+ * switching states as we select other keyframes.
+ *
+ * @param NONE
+ * @return NONE
+ */
+
+void CPropertyTimebarRow::CommitSelections()
+{
+ CMultiSelectAspect<TTimelineKeyframeList> theMultiSelectAspect(m_Keyframes,
+ m_PropertyRow->GetProperty());
+ theMultiSelectAspect.CommitSelections();
+}
+
+//=============================================================================
+/**
+ * true if there are selected keys on this object
+ */
+bool CPropertyTimebarRow::HasSelectedKeys()
+{
+ bool theRetVal = false;
+ TTimelineKeyframeList::iterator thePos = m_Keyframes.begin();
+ for (; thePos != m_Keyframes.end() && !theRetVal; ++thePos) {
+ if ((*thePos)->IsSelected()) {
+ theRetVal = true;
+ }
+ }
+ return theRetVal;
+}
+
+//=============================================================================
+/**
+ * selects all keys for this timebar row
+ */
+void CPropertyTimebarRow::SelectAllKeys()
+{
+ TTimelineKeyframeList::iterator thePos = m_Keyframes.begin();
+ for (; thePos != m_Keyframes.end(); ++thePos) {
+ m_PropertyRow->GetProperty()->SelectKeyframes(true, (*thePos)->GetTime());
+ (*thePos)->Select(true);
+ Invalidate();
+ }
+}
+
+//=============================================================================
+/**
+ * Set this control as being visible or not.
+ * If the control is not visible then it will not be drawn and will not
+ * get mouse clicks.
+ * @param inIsVisible true if this control is to be visible.
+ */
+void CPropertyTimebarRow::SetVisible(bool inIsVisible)
+{
+ if (inIsVisible != IsVisible()) {
+ CControl::SetVisible(inIsVisible);
+ SetDirty(true);
+ }
+}
+
+bool CPropertyTimebarRow::HasKeyframe(long inTime) const
+{
+ return m_PropertyRow->GetProperty()->GetKeyframeByTime(inTime) != nullptr;
+}
+
+//=============================================================================
+/**
+ * @param inTime -1 for all keyframes
+ */
+void CPropertyTimebarRow::SelectKeysByTime(long inTime, bool inSelected)
+{
+ TTimelineKeyframeList::iterator thePos = m_Keyframes.begin();
+ bool theFoundFlag = false;
+ for (; thePos != m_Keyframes.end() && !theFoundFlag; ++thePos) {
+ CPropertyTimelineKeyframe *theKey = (*thePos);
+ if (inTime == -1 || theKey->GetTime() == inTime) {
+ theKey->Select(inSelected);
+ theFoundFlag = (inTime != -1);
+ }
+ }
+ Invalidate();
+}
+
+void CPropertyTimebarRow::SetSnappingListProvider(ISnappingListProvider *inProvider)
+{
+ m_SnappingListProvider = inProvider;
+}
+
+ISnappingListProvider &CPropertyTimebarRow::GetSnappingListProvider() const
+{
+ // sk - If you hit this, it means the setup is incorrect. e.g. the parent row (which is most
+ // probably a staterow) isn't pass 'down' this info.
+ ASSERT(m_SnappingListProvider);
+ return *m_SnappingListProvider;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.h b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.h
new file mode 100644
index 00000000..a07118f9
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_PROPERTY_TIMEBAR_ROW_H
+#define INCLUDED_PROPERTY_TIMEBAR_ROW_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "Control.h"
+#include "PropertyTimebarGraph.h"
+#include "StateRow.h"
+
+//==============================================================================
+// forwards
+//==============================================================================
+class CPropertyRow;
+class CPropertyTimelineKeyframe;
+class ISnappingListProvider;
+
+class CPropertyTimebarRow : public CControl
+{
+ typedef std::vector<CPropertyTimelineKeyframe *> TTimelineKeyframeList;
+
+public:
+ CPropertyTimebarRow(CPropertyRow *inPropertyRow);
+ virtual ~CPropertyTimebarRow();
+
+ void Draw(CRenderer *inRenderer) override;
+ void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+ void SetHighlighted(bool inIsHighlighted);
+ void RefreshKeyframes();
+
+ void SetSize(CPt inSize) override;
+
+ CPropertyRow *GetPropertyRow();
+
+ void SetTimeRatio(double inTimeRatio);
+
+ void SetDetailedView(bool inDetailedView);
+ void OnKeySelected(long inTime, bool inSelected);
+ void DeselectAllKeyframes();
+ void SetDirty(bool inDirtyFlag);
+ void CommitSelections();
+ void SelectKeysInRect(CRct inRect, bool inModifierKeyDown);
+ void SelectAllKeys();
+ bool HasSelectedKeys();
+ void Invalidate(bool inInvalidate = true) override;
+ void SetVisible(bool inIsVisible) override;
+
+ bool HasKeyframe(long inTime) const;
+ void SelectKeysByTime(long inTime, bool inSelected);
+
+ void SetSnappingListProvider(ISnappingListProvider *inProvider);
+ ISnappingListProvider &GetSnappingListProvider() const;
+
+protected:
+ void DrawColor(CRenderer *inRenderer);
+
+protected:
+ TTimelineKeyframeList m_Keyframes; ///< Properties Keyframe List (STL)
+ CPropertyRow *m_PropertyRow;
+ CPropertyTimebarGraph m_DetailedView;
+ ::CColor m_BackgroundColor;
+ double m_TimeRatio;
+
+ bool m_DirtyFlag;
+ bool m_Refreshing;
+ ISnappingListProvider *m_SnappingListProvider;
+};
+#endif // INCLUDED_STATE_TIMEBAR_ROW_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.cpp
new file mode 100644
index 00000000..c3a83e09
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.cpp
@@ -0,0 +1,374 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+#include "Dialogs.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "PropertyTimelineKeyframe.h"
+#include "PropertyTimebarRow.h"
+#include "Renderer.h"
+#include "PropertyRow.h"
+#include "KeyframeContextMenu.h"
+#include "HotKeys.h"
+#include "ResourceCache.h"
+#include "TimelineControl.h"
+#include "Bindings/ITimelineItemProperty.h"
+#include "StudioUtils.h"
+#include "TimeEditDlg.h"
+
+CPropertyTimelineKeyframe::CPropertyTimelineKeyframe(CPropertyTimebarRow *inParentRow,
+ double inTimeRatio)
+ : m_Selected(false)
+ , m_IsMouseDown(false)
+ , m_IsDragging(false)
+{
+ m_ParentRow = inParentRow;
+ m_TimeRatio = inTimeRatio;
+ CResourceCache *theCache = CResourceCache::GetInstance();
+ m_Icon = theCache->GetBitmap("Keyframe-Property-Normal.png");
+ m_DisabledIcon = theCache->GetBitmap("Keyframe-Property-Disabled.png");
+ m_SelectedIcon = theCache->GetBitmap("Keyframe-Property-Selected.png");
+ m_DynamicIcon = theCache->GetBitmap("Keyframe-PropertyDynamic-Normal.png");
+ m_DynamicSelectedIcon = theCache->GetBitmap("Keyframe-PropertyDynamic-Selected.png");
+ m_RectOverHandled = false;
+ m_PreviousSelectState = false;
+}
+
+CPropertyTimelineKeyframe::~CPropertyTimelineKeyframe()
+{
+}
+
+//=============================================================================
+/**
+ * SetRectOverHandled: Sets if mouse rectangle has been handled
+ * param@ inState indicates if the rectangle over has been handled.
+ * return@ NONE
+ */
+void CPropertyTimelineKeyframe::SetRectOverHandled(bool inState)
+{
+ m_RectOverHandled = inState;
+}
+
+//=============================================================================
+/**
+ * GetRectOverHandled: GetRectOverHandled
+ * param@ NONE
+ * return@ m_RectOverHandled, which indicates if the rectangle over has been handled
+ */
+bool CPropertyTimelineKeyframe::GetRectOverHandled()
+{
+ return m_RectOverHandled;
+}
+
+//=============================================================================
+/**
+ * SetPreviousSelectState: Sets if the current keyframe was previously selected
+ * param@ inState is used to set m_PreviousSelectState.
+ * return@ NONE
+ */
+void CPropertyTimelineKeyframe::SetPreviousSelectState(bool inState)
+{
+ m_PreviousSelectState = inState;
+}
+
+//=============================================================================
+/**
+ * GetPreviousSelectState: Returns the keyframe's previous select state
+ * param@ NONE
+ * return@ m_PreviousSelectState that stores the select state for the keyframe
+ */
+bool CPropertyTimelineKeyframe::GetPreviousSelectState()
+{
+ return m_PreviousSelectState;
+}
+
+//=============================================================================
+/**
+ * Gets teh correct image and draws
+ */
+void CPropertyTimelineKeyframe::Draw(CRenderer *inRenderer)
+{
+ if (m_Selected) {
+ inRenderer->DrawBitmap(CPt(0, 0), GetImage());
+ } else {
+ inRenderer->DrawBitmap(CPt(2, 0), GetImage());
+ }
+}
+
+//=============================================================================
+/**
+ * Gets the current bitmap depending on the state of the button, postion of the
+ * mouse, etc. Returns the image for the up state by default.
+ */
+QPixmap CPropertyTimelineKeyframe::GetImage()
+{
+ if (!IsEnabled())
+ return m_DisabledIcon;
+ else if (m_IsDynamic) {
+ if (m_Selected)
+ return m_DynamicSelectedIcon;
+ else
+ return m_DynamicIcon;
+ } else if (m_Selected)
+ return m_SelectedIcon;
+ else
+ return m_Icon;
+}
+
+//=============================================================================
+/**
+ * Handler for left-click events. Allows keyframe dragging. Children are
+ * allowed to handle this event before the parent does.
+ * @param inPoint the point where the mouse is
+ * @param inFlags the state of modifier keys when the event occurred
+ * @return true
+ */
+bool CPropertyTimelineKeyframe::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ // Store the mouse down location in screen coordinates so that we can check the dragging buffer
+ // in OnMouseMove
+ m_MouseDownLoc = inPoint;
+
+ if (!CControl::OnMouseDown(inPoint, inFlags)) {
+ // If the control key is down then we change state, otherwise
+ if (!((CHotKeys::MODIFIER_CONTROL & inFlags) == CHotKeys::MODIFIER_CONTROL)) {
+ if (!m_Selected)
+ GetProperty()->ClearKeySelection();
+
+ m_Selected = true;
+ } else {
+ m_Selected = !m_Selected;
+ }
+ m_ParentRow->OnKeySelected(m_Time, m_Selected);
+ // TODO : sk - Remove this when we are clear on the fact that UpdateClientScene &
+ // FireChangeEvent do nothing useful here.
+ // This call makes no sense. However, if you run into some wierd
+ //behavior related to mouse down events, this might be a clue.
+ // I am leaving this just in case this speeds up debugging for anyone
+ //else looking at this.
+ // CAssetTimelineKeyframe::OnMouseDown does similar things.
+ // m_Doc->UpdateClientScene( true );
+ // m_ParentRow->GetPropertyRow()->GetProperty()->FireChangeEvent( false );
+ m_IsMouseDown = true;
+
+ m_Snapper.Clear();
+ m_Snapper.SetSource(this);
+ m_Snapper.SetSnappingSelectedKeyframes(false);
+ m_ParentRow->GetSnappingListProvider().PopulateSnappingList(&m_Snapper);
+ m_Snapper.BeginDrag(inPoint.x);
+
+ // display the time range tooltip
+ RefreshToolTip(inPoint);
+ }
+
+ return true;
+}
+
+//=============================================================================
+/**
+ * Handler for right-click events. Pops up a context menu. Children are
+ * allowed to handle this event before the parent does.
+ * @param inPoint the point where the mouse is
+ * @param inFlags the state of modifier keys when the event occurred
+ * @return true
+ */
+bool CPropertyTimelineKeyframe::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseRDown(inPoint, inFlags)) {
+ if (!m_Selected) {
+ GetProperty()->ClearKeySelection();
+ m_Selected = true;
+ m_ParentRow->OnKeySelected(m_Time, m_Selected);
+ }
+
+ CKeyframeContextMenu theMenu(GetProperty()->GetKeyframesManager(), GetProperty());
+ theMenu.SetTime(GetTime());
+ DoPopup(&theMenu, inPoint);
+ }
+
+ return true;
+}
+
+//=============================================================================
+/**
+ * called when this key is selected
+ * @param inState the state this key is selected to
+ */
+void CPropertyTimelineKeyframe::Select(bool inState)
+{
+ if (m_Selected != inState) {
+ m_Selected = inState;
+ Invalidate();
+ }
+}
+
+//=============================================================================
+/**
+ * handler for the mouse up event
+ * @param inFlags the state of things when the mouse button was released
+ * @param inPoint the point where the mouse is
+ */
+void CPropertyTimelineKeyframe::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseUp(inPoint, inFlags);
+
+ // If this key is selected, then we need to make sure that it moved all the way to the
+ // mouse up location
+ if (m_Selected && m_IsMouseDown && m_IsDragging) {
+ long theNewTime = m_Snapper.ProcessDrag(m_Time, inPoint.x, inFlags);
+ long theDiffTime = theNewTime - m_Time;
+
+ // theDiffTime can get updated if its invalid.
+ theDiffTime = GetProperty()->OffsetSelectedKeyframes(theDiffTime);
+ // Set this key's time so it won't be recalced in Refresh keyframes in the row
+ SetTime(m_Time + theDiffTime);
+ }
+
+ m_IsMouseDown = false;
+ m_IsDragging = false;
+
+ GetProperty()->CommitChangedKeyframes();
+ HideMoveableWindow();
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * handler for the onMouse Move event. Offsets selected keys.
+ *
+ * @param inFlags the state of things when the mouse was moved
+ * @param inPoint the point where the mouse is
+ */
+void CPropertyTimelineKeyframe::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseMove(inPoint, inFlags);
+
+ // If the mouse is down and this is slected, then offst the keys
+ if (m_IsMouseDown && m_Selected) {
+ // If we are not yet dragging the keyframe
+ if (!m_IsDragging) {
+ long theDiff = ::abs(inPoint.x) - m_MouseDownLoc.x;
+ // Figure out if the mouse has moved far enough to start the drag, and readjust the drag
+ // postion on the snapper
+ m_IsDragging = (::abs(theDiff) > DRAGBUFFER);
+ if (m_IsDragging && (::abs(theDiff) - DRAGBUFFER) > 2) {
+ m_Snapper.BeginDrag(m_MouseDownLoc.x);
+ } else
+ m_Snapper.BeginDrag(inPoint.x);
+ }
+
+ // If we are already dragging the keyframe, procceed as normal
+ if (m_IsDragging) {
+ long theNewTime = m_Snapper.ProcessDrag(m_Time, inPoint.x, inFlags);
+ long theDiffTime = theNewTime - m_Time;
+
+ if (theDiffTime != 0) {
+ // theDiffTime can get updated if its invalid.
+ theDiffTime = GetProperty()->OffsetSelectedKeyframes(theDiffTime);
+ // Set this key's time so it won't be recalced in Refresh keyframes in the row
+ SetTime(m_Time + theDiffTime);
+ Invalidate();
+ }
+ }
+
+ // display the time range tooltip
+ RefreshToolTip(inPoint);
+ }
+}
+
+//=============================================================================
+/**
+ * Sets teh time ratio
+ *
+ * @param inTimeRatio the new ratio
+ */
+void CPropertyTimelineKeyframe::SetTimeRatio(double inTimeRatio)
+{
+ m_TimeRatio = inTimeRatio;
+ CPt theSize = GetSize();
+ SetPosition(::TimeToPos(GetTime(), m_TimeRatio) - (theSize.x / 2), 0);
+}
+
+//=============================================================================
+/**
+ * Pass the double click notification on to the row and have it process it.
+ * The row will do object-specific actions on doubleclicks.
+ * @param inPoint the location of the mouse.
+ * @param inFlags the state of the mouse.
+ * @return true stating that the event was processed.
+ */
+bool CPropertyTimelineKeyframe::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ Q_UNUSED(inPoint);
+ Q_UNUSED(inFlags);
+
+ GetProperty()->OnEditKeyframeTime(m_Time, ASSETKEYFRAME);
+ return true;
+}
+
+//=============================================================================
+/**
+ * @return true if selected
+ */
+bool CPropertyTimelineKeyframe::IsSelected()
+{
+ return m_Selected;
+}
+
+//=============================================================================
+/**
+* Updates the ToolTip and moves it to the correct place on screen.
+* @param inPoint the point that the tooltip is supposed to be placed.
+*/
+void CPropertyTimelineKeyframe::RefreshToolTip(CPt inPoint)
+{
+ CRct theTimelineBounds(m_ParentRow->GetPropertyRow()->GetTopControl()->GetBounds());
+
+ // format label
+ Q3DStudio::CString theCommentText = " " + ::FormatTimeString(GetTime());
+
+ inPoint.y = GetPosition().y - GetSize().y;
+ inPoint.x = GetSize().x / 2;
+ ShowMoveableWindow(inPoint, theCommentText, theTimelineBounds);
+}
+
+//=============================================================================
+/**
+* Helper function to retrieve the ITimelineItemProperty
+*/
+ITimelineItemProperty *CPropertyTimelineKeyframe::GetProperty() const
+{
+ return m_ParentRow->GetPropertyRow()->GetProperty();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.h
new file mode 100644
index 00000000..40c7f05b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_PROPERTY_TIMELINE_KEYFRAME
+#define INCLUDED_PROPERTY_TIMELINE_KEYFRAME 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "Control.h"
+#include "TimelineKeyframe.h"
+#include "Snapper.h"
+
+#include <QPixmap>
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CRenderer;
+class CPropertyTimebarRow;
+class ITimelineItemProperty;
+
+class CPropertyTimelineKeyframe : public CControl, public CTimelineKeyframe
+{
+
+public:
+ CPropertyTimelineKeyframe(CPropertyTimebarRow *inParentRow, double inTimeRatio);
+ ~CPropertyTimelineKeyframe();
+ void Draw(CRenderer *inRenderer) override;
+ QPixmap GetImage();
+
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void Select(bool inState);
+ void SetTimeRatio(double inTimeRatio);
+ bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool IsSelected();
+ void SetRectOverHandled(bool inState);
+ bool GetRectOverHandled();
+ void SetPreviousSelectState(bool inState);
+ bool GetPreviousSelectState();
+
+protected:
+ void RefreshToolTip(CPt inPoint);
+ ITimelineItemProperty *GetProperty() const;
+
+protected:
+ bool m_Selected;
+ bool m_RectOverHandled; ///< Indicates if the mouse rect over has been handled.
+ bool m_PreviousSelectState; ///< Stores the previous select state for the keyframe.
+ CPropertyTimebarRow *m_ParentRow;
+ bool m_IsMouseDown;
+ CPt m_MouseDownLoc; ///< Location of the mouse after an OnMouseDownEvent, in client coordinates
+ bool m_IsDragging; ///< Indicates whether or not the keyframe is currently being dragged,
+ ///determined by the pixel buffer
+ double m_TimeRatio;
+ CSnapper m_Snapper;
+ QPixmap m_Icon;
+ QPixmap m_DisabledIcon;
+ QPixmap m_SelectedIcon;
+ QPixmap m_DynamicIcon;
+ QPixmap m_DynamicSelectedIcon;
+};
+
+#endif // INCLUDED_PROPERTY_TIMELINE_KEYFRAME
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.cpp
new file mode 100644
index 00000000..994ba2fe
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "PropertyToggleControl.h"
+#include "TimelineRow.h"
+#include "PropertyRow.h"
+#include "Renderer.h"
+#include "StudioPreferences.h"
+#include "HotKeys.h"
+
+CPropertyToggleControl::CPropertyToggleControl(CPropertyRow *inPropertyRow)
+ : m_PropertyRow(inPropertyRow)
+{
+ m_BackgroundColor = m_PropertyRow->GetTimebarBackgroundColor();
+}
+
+CPropertyToggleControl::~CPropertyToggleControl()
+{
+}
+
+void CPropertyToggleControl::Draw(CRenderer *inRenderer)
+{
+ CRct theRect(GetSize());
+ inRenderer->FillSolidRect(QRect(0, 0, theRect.size.x + 1, theRect.size.y), m_BackgroundColor);
+
+ // Draw the line at the bottom of this control
+ inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor());
+ inRenderer->MoveTo(CPt(0, theRect.size.y - 1));
+ inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1));
+
+ // Draw the line on the left side of this control
+ inRenderer->MoveTo(CPt(0, 0));
+ inRenderer->LineTo(CPt(0, theRect.size.y - 1));
+
+ // Draw the highlight
+ inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor());
+ inRenderer->MoveTo(CPt(1, 0));
+ inRenderer->LineTo(CPt(1, theRect.size.y - 1));
+ inRenderer->PopPen();
+
+ // Draw the line on the right side of this control
+ inRenderer->PushPen(CStudioPreferences::GetButtonShadowColor());
+ inRenderer->MoveTo(CPt(theRect.size.x - 1, 0));
+ inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y - 1));
+ inRenderer->PopPen();
+}
+
+void CPropertyToggleControl::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOver(inPoint, inFlags);
+
+ m_PropertyRow->OnMouseOver();
+}
+
+void CPropertyToggleControl::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOut(inPoint, inFlags);
+
+ m_PropertyRow->OnMouseOut();
+}
+
+void CPropertyToggleControl::SetHighlighted(bool inIsHighlighted)
+{
+ if (inIsHighlighted)
+ m_BackgroundColor = m_PropertyRow->GetTimebarHighlightBackgroundColor();
+ else
+ m_BackgroundColor = m_PropertyRow->GetTimebarBackgroundColor();
+
+ Invalidate();
+}
+
+//==============================================================================
+/**
+ * Handles the OnMouseDownEvent
+ */
+bool CPropertyToggleControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseDown(inPoint, inFlags))
+ m_PropertyRow->Select((CHotKeys::MODIFIER_SHIFT & inFlags) == CHotKeys::MODIFIER_SHIFT);
+
+ return true;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.h b/src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.h
new file mode 100644
index 00000000..81435cc6
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_PROPERTY_TOGGLE_CONTROL_H
+#define INCLUDED_PROPERTY_TOGGLE_CONTROL_H 1
+
+#pragma once
+
+#include "Control.h"
+#include "CColor.h"
+
+class CPropertyRow;
+
+class CPropertyToggleControl : public CControl
+{
+public:
+ CPropertyToggleControl(CPropertyRow *inPropertyRow);
+ virtual ~CPropertyToggleControl();
+
+ void Draw(CRenderer *inRenderer) override;
+
+ void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+ void SetHighlighted(bool inIsHightlighted);
+
+protected:
+ CPropertyRow *m_PropertyRow;
+ ::CColor m_BackgroundColor;
+};
+#endif // INCLUDED_PROPERTY_TOGGLE_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.cpp b/src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.cpp
new file mode 100644
index 00000000..813f04f3
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.cpp
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 1999-2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "PropertyTreeControl.h"
+#include "PropertyRow.h"
+#include "Renderer.h"
+#include "StudioPreferences.h"
+#include "StudioUtils.h"
+#include "HotKeys.h"
+#include "ResourceCache.h"
+#include "BaseTimelineTreeControl.h"
+#include "Bindings/ITimelineItemProperty.h"
+#include "CoreUtils.h"
+
+CPropertyTreeControl::CPropertyTreeControl(CPropertyRow *inPropRow)
+ : m_Icon(CResourceCache::GetInstance()->GetBitmap("Objects-Property-Normal.png"),
+ CResourceCache::GetInstance()->GetBitmap("Objects-Property-Disabled.png"))
+{
+ m_PropRow = inPropRow;
+
+ CBaseStateRow *theParentRow = m_PropRow->GetParentRow();
+ if (theParentRow) // property row typically should never exists on its own, but to be safe.
+ m_BackgroundColor = m_PropRow->GetTimebarBackgroundColor();
+ else
+ m_BackgroundColor = CStudioPreferences::GetPropertyBackgroundColor();
+
+ AddChild(&m_Icon);
+
+ m_Text.SetData(inPropRow->GetProperty()->GetName());
+ m_Text.SetAlignment(CTextEdit::LEFT);
+ m_Text.SetReadOnly(true);
+
+ AddChild(&m_Text);
+
+ SetIndent(0);
+}
+
+CPropertyTreeControl::~CPropertyTreeControl()
+{
+}
+
+void CPropertyTreeControl::Draw(CRenderer *inRenderer)
+{
+ CRct theRect(GetSize());
+
+ inRenderer->FillSolidRect(theRect, m_BackgroundColor);
+
+ // Draw the line at the bottom of this control
+ CColor theShadowColor = CStudioPreferences::GetPropertyFloorColor();
+ inRenderer->PushPen(theShadowColor);
+ inRenderer->MoveTo(CPt(0, theRect.size.y - 1));
+ inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1));
+ inRenderer->PopPen();
+
+ ::CColor theTextColor = CStudioPreferences::GetNormalColor();
+ if (m_PropRow->GetProperty()->IsMaster())
+ theTextColor = CStudioPreferences::GetMasterColor();
+ m_Text.SetTextColor(theTextColor);
+}
+
+void CPropertyTreeControl::SetIndent(long inIndent)
+{
+ m_Indent = inIndent;
+
+ // place it it's size x2 to the right since we don't have a toggle.
+ m_Icon.SetPosition(CPt(m_Indent + m_Icon.GetSize().x, 0));
+
+ m_Text.SetPosition(CPt(m_Icon.GetPosition().x + m_Icon.GetSize().x + 5, 0));
+ m_Text.SetSize(CPt(200, m_Icon.GetSize().y - 1));
+}
+
+long CPropertyTreeControl::GetIndent()
+{
+ return m_Indent;
+}
+
+void CPropertyTreeControl::SetHighlighted(bool inIsHighlighted)
+{
+ CBaseStateRow *theParentRow = m_PropRow->GetParentRow();
+ if (theParentRow) // property row typically should never exists on its own, but to be safe.
+ m_BackgroundColor = (inIsHighlighted) ? m_PropRow->GetTimebarHighlightBackgroundColor()
+ : m_PropRow->GetTimebarBackgroundColor();
+ else
+ m_BackgroundColor = (inIsHighlighted) ? CStudioPreferences::GetPropertyMouseOverColor()
+ : CStudioPreferences::GetPropertyBackgroundColor();
+
+ Invalidate();
+}
+
+//==============================================================================
+/**
+ * HACK: Trying to scroll the timeline during a drag and drop operation.
+ *
+ * The Property Tree Control will never have a drop candidate, so this function
+ * returns nullptr. However, we still need to scroll the timeline in case we are
+ * at the top or bottom of the window. This is hackish for two reasons. 1) It
+ * points out that CPropertyTreeControl and CStateTreeControl should have a
+ * common base class that handles similar code. 2) The TreeControls should not
+ * have to scroll the timeline automatically. It should be handled through a
+ * timer on the scroller when the mouse is being dragged and hovering near the
+ * border of the scroller. But all of that will be saved for another day.
+ * @param inMousePoint location of the mouse
+ * @param inFlags not used (modifier key flags)
+ * @return nullptr (no drop candidate is ever found)
+ */
+CDropTarget *CPropertyTreeControl::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags)
+{
+ Q_UNUSED(inFlags);
+
+ CPt theSize(GetSize());
+
+ // If the mouse is towards the top of this row, make sure that this row and the
+ // one above it are visible (scroll upwards)
+ if (inMousePoint.y <= ::dtol(theSize.y / 2.0f))
+ EnsureVisible(CRct(CPt(0, -theSize.y), theSize));
+ // Otherwise, the mouse is towards the bottom of this row, so make sure this row
+ // and the one below it are visible (scroll downwards)
+ else
+ EnsureVisible(CRct(CPt(theSize.x, theSize.y * 2)));
+
+ return nullptr;
+}
+
+void CPropertyTreeControl::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOver(inPoint, inFlags);
+
+ m_PropRow->OnMouseOver();
+}
+
+void CPropertyTreeControl::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOut(inPoint, inFlags);
+
+ m_PropRow->OnMouseOut();
+}
+
+//==============================================================================
+/**
+ * Handles the OnMouseDownEvent
+ */
+bool CPropertyTreeControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseDown(inPoint, inFlags))
+ m_PropRow->Select((CHotKeys::MODIFIER_SHIFT & inFlags) == CHotKeys::MODIFIER_SHIFT);
+
+ return true;
+}
+
+bool CPropertyTreeControl::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseDoubleClick(inPoint, inFlags)) {
+ m_PropRow->OnMouseDoubleClick();
+ }
+ return true;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.h b/src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.h
new file mode 100644
index 00000000..5bc61c23
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_PROPERTY_TREE_CONTROL_H
+#define INCLUDED_PROPERTY_TREE_CONTROL_H 1
+
+#pragma once
+
+#include "Control.h"
+#include "SIcon.h"
+#include "StringEdit.h"
+
+class CPropertyRow;
+
+class CPropertyTreeControl : public CControl
+{
+public:
+ CPropertyTreeControl(CPropertyRow *inPropRow);
+ virtual ~CPropertyTreeControl();
+
+ void Draw(CRenderer *inRenderer) override;
+
+ void SetIndent(long inIndent);
+ long GetIndent();
+
+ void SetHighlighted(bool inIsHighlighted);
+
+ CDropTarget *FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags) override;
+
+ void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+protected:
+ long m_Indent;
+ CPropertyRow *m_PropRow;
+ CSIcon m_Icon;
+ CStringEdit m_Text;
+ ::CColor m_BackgroundColor;
+};
+#endif // INCLUDED_PROPERTY_TREE_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/ScalableScroller.cpp b/src/Authoring/Studio/Palettes/Timeline/ScalableScroller.cpp
new file mode 100644
index 00000000..b445db83
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ScalableScroller.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "ScalableScroller.h"
+#include "ScalableScrollerBar.h"
+
+CScalableScroller::CScalableScroller()
+ : CScroller(false)
+ , m_ScalableBar(nullptr)
+ , m_ScalingListener(nullptr)
+{
+ Initialize();
+}
+
+CScalableScroller::~CScalableScroller()
+{
+}
+
+CScrollerBar *CScalableScroller::CreateHorizontalBar()
+{
+ if (m_ScalableBar == nullptr) {
+ m_ScalableBar = new CScalableBar(this);
+ m_ScalableBar->SetOrientation(CScrollerBar::HORIZONTAL);
+ m_ScalableBar->SetScalingListener(m_ScalingListener);
+ }
+ return m_ScalableBar;
+}
+
+void CScalableScroller::SetScalingListener(CScalingListener *inListener)
+{
+ m_ScalingListener = inListener;
+
+ if (m_ScalableBar != nullptr) {
+ m_ScalableBar->SetScalingListener(inListener);
+ }
+}
+
+//====================================================================
+/**
+ * Protected function for seting the display size of the scroller.
+ * Overridden because the scaleable scroller thumb at the bottom of
+ * the timeline was getting messed up. Yes, it's a hack, but I couldn't
+ * fix it any other way.
+ */
+void CScalableScroller::SetVisibleSize(CPt inSize)
+{
+ m_VisibleSize = inSize;
+
+ // Don't call the base class because it messes things up
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/ScalableScroller.h b/src/Authoring/Studio/Palettes/Timeline/ScalableScroller.h
new file mode 100644
index 00000000..9fd6df3b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ScalableScroller.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_SCALABLE_SCROLLER_H
+#define INCLUDED_SCALABLE_SCROLLER_H 1
+
+#pragma once
+
+#include "Scroller.h"
+
+class CScalingListener;
+class CScalableBar;
+
+class CScalableScroller : public CScroller
+{
+public:
+ CScalableScroller();
+ virtual ~CScalableScroller();
+
+ void SetScalingListener(CScalingListener *inScalingListener);
+
+ void SetVisibleSize(CPt inSize) override;
+
+protected:
+ CScrollerBar *CreateHorizontalBar() override;
+
+ CScalableBar *m_ScalableBar;
+
+ CScalingListener *m_ScalingListener;
+};
+#endif // INCLUDED_SCALABLE_SCROLLER_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.cpp b/src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.cpp
new file mode 100644
index 00000000..77c63292
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.cpp
@@ -0,0 +1,359 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "ScrollerBackground.h"
+#include "ScalableScrollerBar.h"
+#include "ScalableScroller.h"
+#include "Renderer.h"
+#include "MouseCursor.h"
+#include "ResourceCache.h"
+
+#include <QApplication>
+
+//=============================================================================
+/**
+ * Creates a new ThumbTab (the scalable ends of the thumb).
+ * @param inThumb the thumb this belongs to.
+ * @param inIsRight true if this is the right side, false for left.
+ * @param inBar the ScalableBar this belongs to.
+ */
+CScalableThumbTab::CScalableThumbTab(CScalableThumb *inThumb, bool inIsRightTab,
+ CScalableBar *inBar)
+ : m_Bar(inBar)
+ , m_IsMouseDown(false)
+ , m_IsRightTab(inIsRightTab)
+{
+ m_Thumb = inThumb;
+}
+
+CScalableThumbTab::~CScalableThumbTab()
+{
+}
+
+//=============================================================================
+/**
+ * MouseOver handler, modifies the cursor.
+ * @param inPoint the mouse location.
+ * @param inFlags the mouse state.
+ */
+void CScalableThumbTab::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOver(inPoint, inFlags);
+
+ setCursorIfNotSet(CMouseCursor::CURSOR_RESIZE_LEFTRIGHT);
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Mouse out handler, invalidates the control to clear the mouse over drawing.
+ * @param inPoint the location of the mouse.
+ * @param inFlags the state of the mouse.
+ */
+void CScalableThumbTab::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOut(inPoint, inFlags);
+
+ if (!m_IsMouseDown)
+ resetCursor();
+
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Mouse move handlers, if this was clicked on then drags the control.
+ * @param inPoint the location of the mouse.
+ * @param inFlags the state of the mouse.
+ */
+void CScalableThumbTab::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseMove(inPoint, inFlags);
+
+ // Only drag if this was clicked on
+ if (m_IsMouseDown) {
+ long theDiff = inPoint.x - m_MouseDownLoc.x;
+ // Fire the scaling event for the delta size.
+ if (m_IsRightTab)
+ m_Bar->OnScalingRight(theDiff);
+ else
+ m_Bar->OnScalingLeft(theDiff);
+ }
+
+ CRct theRect(GetSize());
+ if (theRect.IsInRect(inPoint))
+ setCursorIfNotSet(CMouseCursor::CURSOR_RESIZE_LEFTRIGHT);
+}
+
+//=============================================================================
+/**
+ * Mouse click handler, starts resizing the control.
+ * @param inPoint the location of the mouse.
+ * @param inFlags the state of the mouse.
+ */
+bool CScalableThumbTab::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseDown(inPoint, inFlags);
+
+ setCursorIfNotSet(CMouseCursor::CURSOR_RESIZE_LEFTRIGHT);
+ m_IsMouseDown = true;
+ m_MouseDownLoc = inPoint;
+
+ return true;
+}
+
+//=============================================================================
+/**
+ * Mouse up handler, ends resizing this control.
+ * @param inPoint the location of the mouse.
+ * @param inFlags the state of the mouse.
+ */
+void CScalableThumbTab::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseUp(inPoint, inFlags);
+
+ resetCursor();
+
+ m_IsMouseDown = false;
+}
+
+//=============================================================================
+/**
+ * Draw this control.
+ * @param inRenderer the renderer to draw to.
+ */
+void CScalableThumbTab::Draw(CRenderer *inRenderer)
+{
+ CPt theSize = GetSize();
+ CRct theRect(theSize);
+
+ inRenderer->FillSolidRect(theRect, CStudioPreferences::GetScrollThumbBGColor());
+
+ // Draw the light colored highlight
+ inRenderer->PushPen(CStudioPreferences::GetScrollThumbHighlightColor());
+ inRenderer->MoveTo(CPt(1, theSize.y - 1));
+ inRenderer->LineTo(CPt(1, 1));
+ inRenderer->LineTo(CPt(theSize.x - 1, 1));
+ inRenderer->PopPen();
+
+ // Draw the dark bounding rectangle
+ CColor theGripBoundColor = CStudioPreferences::GetScrollThumbShadowColor();
+ inRenderer->Draw3dRect(theRect, theGripBoundColor, theGripBoundColor);
+}
+
+//=============================================================================
+/**
+ * Create a scalable thumb, this is the dragging component of the bar.
+ * @param inScrollerBar the bar this belongs to.
+ */
+CScalableThumb::CScalableThumb(CScalableBar *inScrollerBar)
+ : CScrollerThumb(inScrollerBar)
+ , m_LeftTab(this, false, inScrollerBar)
+ , m_RightTab(this, true, inScrollerBar)
+{
+ m_ScrollerBar = inScrollerBar;
+
+ m_LeftTab.SetPosition(CPt(0, 0));
+
+ AddChild(&m_LeftTab);
+ AddChild(&m_RightTab);
+}
+
+CScalableThumb::~CScalableThumb()
+{
+}
+
+//=============================================================================
+/**
+ * Set the size of this component, overrides to update the location of the tabs.
+ * @param inSize the new size of this control.
+ */
+void CScalableThumb::SetSize(CPt inSize)
+{
+ CScrollerThumb::SetSize(inSize);
+ m_LeftTab.SetSize(CPt(7, inSize.y));
+ m_RightTab.SetSize(CPt(7, inSize.y));
+ m_RightTab.SetPosition(CPt(inSize.x - m_RightTab.GetSize().x, 0));
+}
+
+//=============================================================================
+/**
+ * On double click this sends off a reset scaling notification.
+ * @param inPoint the mouse location.
+ * @param inFlags the state of the mouse.
+ */
+bool CScalableThumb::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseDoubleClick(inPoint, inFlags))
+ m_ScrollerBar->OnScalingReset();
+
+ return true;
+}
+
+//=============================================================================
+/**
+ * Creates a new scalable scroller bar.
+ * This object can only be used for horizontal scrolling.
+ * @param inScroller the scalable scroller this is operating on.
+ */
+CScalableBar::CScalableBar(CScalableScroller *inScroller)
+ : CScrollerBar(inScroller, false)
+ , m_ScalableScroller(inScroller)
+ , m_Listener(nullptr)
+ , m_Thumb(nullptr)
+{
+ Initialize();
+}
+
+CScalableBar::~CScalableBar()
+{
+}
+
+//=============================================================================
+/**
+ * Create a new thumb control.
+ * This method is here so the ScalableBar can override it and return the Scalable
+ * Thumb instead of a normal thumb.
+ */
+CControl *CScalableBar::CreateThumb()
+{
+ if (m_Thumb == nullptr)
+ m_Thumb = new CScalableThumb(this);
+ return m_Thumb;
+}
+
+//=============================================================================
+/**
+ * This control is not allowed to become disabled (it should always allow scaling).
+ * @param inIsEnabled ignored.
+ */
+void CScalableBar::SetEnabled(bool inIsEnabled)
+{
+ Q_UNUSED(inIsEnabled);
+ CControl::SetEnabled(true);
+}
+
+//=============================================================================
+/**
+ * Set the single scaling listener that is to carry out the actual scaling work.
+ * @param inListener the scaling listener, there is only one.
+ */
+void CScalableBar::SetScalingListener(CScalingListener *inListener)
+{
+ m_Listener = inListener;
+}
+
+//=============================================================================
+/**
+ * Event from the left ThumbTab that it is scaling.
+ * @param inAmount the amount that the left ThumbTab is being scaled by.
+ */
+void CScalableBar::OnScalingLeft(long inAmount)
+{
+ CPt theLoc = m_Thumb->GetPosition();
+ CPt theSize = m_Thumb->GetSize();
+
+ // Don't let the loc go before the end of the control.
+ if (theLoc.x + inAmount < 0)
+ inAmount = -theLoc.x;
+
+ // Anchors the scroller position when its size reaches the minimum size
+ // The algorithm does not modify the inAmount as the scale can be further reduced,
+ // when the scroller reaches the minimum size.
+
+ CPt thePreviousPosition;
+ bool theAnchor = false;
+ if (theSize.x - inAmount < m_Thumb->GetMinimumSize().x) {
+ thePreviousPosition = m_Thumb->GetPosition();
+ theAnchor = true;
+ }
+
+ // Tell the listener of the scaling, it's the listener that will do the actual scaling work.
+ if (m_Listener != nullptr)
+ m_Listener->OnScalingLeft(theSize.x - inAmount, m_Background->GetSize().x,
+ m_Thumb->GetPosition().x + inAmount);
+
+ // When the Anchor flag is true (i.e. when the scroller has reach its minimum size), stop the
+ // scroller
+ // from moving by restoring its previous position.
+ if (theAnchor) {
+ m_Thumb->SetPosition(thePreviousPosition);
+ }
+
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Event from the right ThumbTab that it is scaling.
+ * @param inAmount the amount that the left ThumbTab is being scaled by.
+ */
+void CScalableBar::OnScalingRight(long inAmount)
+{
+ CPt theLoc = m_Thumb->GetPosition();
+ CPt theSize = m_Thumb->GetSize();
+ // Don't let the loc go after the end of the control.
+ if (theLoc.x + theSize.x + inAmount > m_Background->GetSize().x)
+ inAmount = m_Background->GetSize().x - (theLoc.x + theSize.x);
+
+ // Anchors the scroller position when its size reaches the minimum size
+ // The algorithm does not modify the inAmount as the scale can be further reduced,
+ // when the scroller reaches the minimum size.
+
+ CPt thePreviousPosition;
+ bool theAnchor = false;
+ if (theSize.x + inAmount < m_Thumb->GetMinimumSize().x) {
+ thePreviousPosition = m_Thumb->GetPosition();
+ theAnchor = true;
+ }
+
+ // Tell the listener of the scaling, it's the listener that will do the actual scaling work.
+ if (m_Listener != nullptr)
+ m_Listener->OnScalingRight(theSize.x + inAmount, m_Background->GetSize().x,
+ m_Thumb->GetPosition().x);
+
+ // When the Anchor flag is true (i.e. when the scroller has reach its minimum size), stop the
+ // scroller
+ // from moving by restoring its previous position.
+ if (theAnchor) {
+ m_Thumb->SetPosition(thePreviousPosition);
+ }
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Handles scaling reset messages commands, just routes them to the listener.
+ */
+void CScalableBar::OnScalingReset()
+{
+ m_Listener->OnScalingReset();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.h b/src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.h
new file mode 100644
index 00000000..afc0ef1e
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_SCALABLE_SCROLLER_BAR_H
+#define INCLUDED_SCALABLE_SCROLLER_BAR_H 1
+
+#pragma once
+
+#include "ScrollerThumb.h"
+#include "ScrollerBar.h"
+
+#include <QCursor>
+
+class CScalableBar;
+class CScalableScroller;
+class CScalableThumb;
+
+class CScalingListener
+{
+public:
+ virtual void OnScalingLeft(long inLength, long inTotalLength, long inOffset) = 0;
+ virtual void OnScalingRight(long inLength, long inTotalLength, long inOffset) = 0;
+ virtual void OnScalingReset() = 0;
+};
+
+class CScalableThumbTab : public CControl
+{
+public:
+ CScalableThumbTab(CScalableThumb *inThumb, bool inIsRightTab, CScalableBar *inBar);
+ virtual ~CScalableThumbTab();
+
+ void Draw(CRenderer *inRenderer) override;
+
+ void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+protected:
+ CScalableThumb *m_Thumb;
+ CScalableBar *m_Bar;
+ bool m_IsMouseDown;
+ bool m_IsRightTab;
+ CPt m_MouseDownLoc;
+};
+
+class CScalableThumb : public CScrollerThumb
+{
+public:
+ CScalableThumb(CScalableBar *inScrollerBar);
+ virtual ~CScalableThumb();
+
+ void SetSize(CPt inSize) override;
+ bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+protected:
+ CScalableBar *m_ScrollerBar;
+ CScalableThumbTab m_LeftTab;
+ CScalableThumbTab m_RightTab;
+};
+
+class CScalableBar : public CScrollerBar
+{
+public:
+ CScalableBar(CScalableScroller *inScroller);
+ virtual ~CScalableBar();
+
+ void SetEnabled(bool inIsEnabled) override;
+
+ void SetScalingListener(CScalingListener *inListener);
+
+ void OnScalingRight(long inAmount);
+ void OnScalingLeft(long inAmount);
+ void OnScalingReset();
+
+protected:
+ CControl *CreateThumb() override;
+
+ CScalableScroller *m_ScalableScroller;
+
+ CScalingListener *m_Listener;
+ CScalableThumb *m_Thumb;
+};
+
+#endif // INCLUDED_SCALABLE_SCROLLER_BAR_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/SlideRow.cpp b/src/Authoring/Studio/Palettes/Timeline/SlideRow.cpp
new file mode 100644
index 00000000..ac14bee2
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/SlideRow.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "SlideRow.h"
+#include "BlankToggleControl.h"
+#include "ColorControl.h"
+#include "SlideTimebarRow.h"
+#include "Bindings/ITimelineItemBinding.h"
+#include "ITimelineControl.h"
+
+CSlideRow::CSlideRow(ITimelineItemBinding *inTimelineItem)
+ : m_TimelineControl(nullptr)
+{
+ Initialize(inTimelineItem);
+}
+
+CSlideRow::~CSlideRow()
+{
+}
+
+void CSlideRow::SetTimelineControl(ITimelineControl *inTimelineControl)
+{
+ m_TimelineControl = inTimelineControl;
+}
+
+//=============================================================================
+/**
+ * Expand this node of the tree control.
+ * This will display all children the fit the filter.
+ */
+void CSlideRow::Expand(bool inExpandAll /*= false*/, bool inExpandUp)
+{
+ if (!m_Loaded) {
+ m_Loaded = true;
+ LoadChildren();
+ }
+
+ CBaseStateRow::Expand(inExpandAll, inExpandUp);
+}
+
+//=============================================================================
+/**
+ * This do not 'contribute' to its child's active start time
+ */
+bool CSlideRow::CalculateActiveStartTime()
+{
+ return false;
+}
+//=============================================================================
+/**
+ * This do not 'contribute' to its child's active end time
+ */
+bool CSlideRow::CalculateActiveEndTime()
+{
+ return false;
+}
+
+ISnappingListProvider *CSlideRow::GetSnappingListProvider() const
+{
+ ASSERT(m_TimelineControl);
+ return m_TimelineControl->GetSnappingListProvider();
+}
+
+void CSlideRow::SetSnappingListProvider(ISnappingListProvider *inProvider)
+{
+ // does nothing
+ Q_UNUSED(inProvider);
+}
+
+//=============================================================================
+/**
+ * See CBaseStateRow::GetTopControl comments.
+ * This being to "top" row will have the actual pointer
+ */
+ITimelineControl *CSlideRow::GetTopControl() const
+{
+ return m_TimelineControl;
+}
+
+//=============================================================================
+/**
+ * Create a new CStateTimebarRow.
+ * This is virtual and used for objects to return their type specific
+ * timebar rows if they want to.
+ * @return the created timebar row.
+ */
+CBaseTimebarlessRow *CSlideRow::CreateTimebarRow()
+{
+ return new CSlideTimebarRow(this);
+}
+
+bool CSlideRow::PerformFilter(const CFilter &inFilter)
+{
+ Q_UNUSED(inFilter);
+ return true;
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/SlideRow.h b/src/Authoring/Studio/Palettes/Timeline/SlideRow.h
new file mode 100644
index 00000000..d978f11e
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/SlideRow.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_TIME_CONTEXT_ROW_H
+#define INCLUDED_TIME_CONTEXT_ROW_H 1
+
+#pragma once
+
+#include "BaseStateRow.h"
+
+class ISnappingListProvider;
+class ITimelineControl;
+
+class CSlideRow : public CBaseStateRow
+{
+public:
+ CSlideRow(ITimelineItemBinding *inTimelineItem);
+ virtual ~CSlideRow();
+
+ void SetTimelineControl(ITimelineControl *inTimelineControl);
+
+ // BaseStateRow
+ void Expand(bool inExpandAll = false, bool inExpandUp = false) override;
+ bool CalculateActiveStartTime() override;
+ bool CalculateActiveEndTime() override;
+ ISnappingListProvider *GetSnappingListProvider() const override;
+ void SetSnappingListProvider(ISnappingListProvider *inProvider) override;
+ ITimelineControl *GetTopControl() const override;
+
+protected:
+ // CBaseStateRow
+ CBaseTimebarlessRow *CreateTimebarRow() override;
+ bool PerformFilter(const CFilter &inFilter) override;
+
+ ITimelineControl *m_TimelineControl;
+};
+#endif // INCLUDED_TIME_CONTEXT_ROW_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.cpp b/src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.cpp
new file mode 100644
index 00000000..49ce261f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "SlideTimebarRow.h"
+#include "SlideRow.h"
+
+CSlideTimebarRow::CSlideTimebarRow(CSlideRow *inSlideRow)
+ : m_SlideRow(inSlideRow)
+{
+}
+
+CSlideTimebarRow::~CSlideTimebarRow()
+{
+}
+
+void CSlideTimebarRow::CommitSelections()
+{
+}
+
+void CSlideTimebarRow::SelectKeysInRect(CRct inRect, bool inModifierKeyDown)
+{
+ Q_UNUSED(inRect);
+ Q_UNUSED(inModifierKeyDown);
+}
+
+void CSlideTimebarRow::SelectKeysByTime(long inTime, bool inSelected)
+{
+ Q_UNUSED(inTime);
+ Q_UNUSED(inSelected);
+}
+
+void CSlideTimebarRow::SelectAllKeys()
+{
+}
+
+void CSlideTimebarRow::PopulateSnappingList(CSnapper *inSnapper)
+{
+ Q_UNUSED(inSnapper);
+}
+
+CBaseStateRow *CSlideTimebarRow::GetBaseStateRow() const
+{
+ return m_SlideRow;
+}
+
+// This is not applicable to a SlideTimebarRow!!
+ISnappingListProvider &CSlideTimebarRow::GetSnappingListProvider() const
+{
+ throw;
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.h b/src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.h
new file mode 100644
index 00000000..a2f63e33
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_TIME_CONTEXT_TIMEBAR_ROW_H
+#define INCLUDED_TIME_CONTEXT_TIMEBAR_ROW_H 1
+
+#pragma once
+
+#include "BaseTimebarlessRow.h"
+
+class CSlideRow;
+
+class CSlideTimebarRow : public CBaseTimebarlessRow
+{
+public:
+ CSlideTimebarRow(CSlideRow *inSlideRow);
+ virtual ~CSlideTimebarRow();
+
+ void CommitSelections() override;
+
+ void SelectKeysInRect(CRct inRect, bool inModifierKeyDown) override;
+ void SelectKeysByTime(long inTime, bool inSelected) override;
+ void SelectAllKeys() override;
+
+ void PopulateSnappingList(CSnapper *inSnappingList) override;
+ ISnappingListProvider &GetSnappingListProvider() const override;
+
+protected:
+ CBaseStateRow *GetBaseStateRow() const override;
+
+protected:
+ CSlideRow *m_SlideRow;
+};
+#endif // INCLUDED_TIME_CONTEXT_TIMEBAR_ROW_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Snapper.cpp b/src/Authoring/Studio/Palettes/Timeline/Snapper.cpp
new file mode 100644
index 00000000..2b405e70
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Snapper.cpp
@@ -0,0 +1,455 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "Snapper.h"
+#include "StudioPreferences.h"
+#include "Control.h"
+#include "CoreUtils.h"
+#include "StudioUtils.h"
+#include "HotKeys.h"
+
+//=============================================================================
+/**
+ * Create a new snapper object.
+ * @param inTimeRatio the default time ratio.
+ */
+CSnapper::CSnapper(double inTimeRatio)
+ : m_theStartTime(0)
+ , m_theEndTime(0)
+ , m_TimeRatio(inTimeRatio)
+ , m_IsSnappingKeyframes(false)
+ , m_IsSnappingSelectedKeyframes(true)
+ , m_Offset(0)
+ , m_StartHeight(0)
+ , m_EndHeight(0)
+ , m_PeriodicInterval(LONG_MAX)
+ , m_InitialOffset(0)
+ , m_ObjectTimeOffset(0)
+ , m_TimeOffset(0)
+ , m_KeyFrameClicked(false)
+ , m_Source(nullptr)
+{
+ SetSnappingDistance(CStudioPreferences::GetSnapRange());
+}
+
+CSnapper::~CSnapper()
+{
+}
+//=============================================================================
+/**
+ * Set if keyframe is clicked
+ * @param inKeyFrameClicked toggles snapping to end handles at 1 pixel range,
+ * if true.
+ */
+void CSnapper::SetKeyFrameClicked(bool inKeyFrameClicked)
+{
+ m_KeyFrameClicked = inKeyFrameClicked;
+}
+//=============================================================================
+/**
+ * Clear all the snapping points from this.
+ * This effectively erases this object.
+ */
+void CSnapper::Clear()
+{
+ m_PeriodicInterval = LONG_MAX;
+ m_Times.clear();
+ m_KeyFrameClicked = false;
+ SetSnappingDistance(CStudioPreferences::GetSnapRange());
+}
+
+//=============================================================================
+/**
+ * Add a snapping point at the specified time.
+ * @param inTime the time to add the point at.
+ */
+void CSnapper::AddTime(long inTime)
+{
+ m_Times.insert(inTime);
+}
+
+//=============================================================================
+/**
+ * Add a snapping point at the specified pixel location.
+ * @param inPosition the position of the snapping point to add.
+ */
+void CSnapper::AddPixelLocation(long inPosition)
+{
+ AddTime(::PosToTime(inPosition, m_TimeRatio));
+}
+
+//=============================================================================
+/**
+ * Set whether or not keyframes should be added as snapping points.
+ * @param true if keyframes should be added as snapping points.
+ */
+void CSnapper::SetSnappingKeyframes(bool inIsSnappingKeyframes)
+{
+ m_IsSnappingKeyframes = inIsSnappingKeyframes;
+}
+
+//=============================================================================
+/**
+ * Checks whether or not keyframes are being snapped to.
+ * @return true if keyframes should be snapped to.
+ */
+bool CSnapper::IsSnappingKeyframes()
+{
+ return m_IsSnappingKeyframes;
+}
+
+//=============================================================================
+/**
+ * Sets whether or not selected keyframes are being snapped to.
+ * This is used to ignore all selected keyframes when keyframes are being
+ * dragged.
+ * @param inIsSnappingSelectedKeyframes true if selected keys should be snapped.
+ */
+void CSnapper::SetSnappingSelectedKeyframes(bool inIsSnappingSelectedKeyframes)
+{
+ m_IsSnappingSelectedKeyframes = inIsSnappingSelectedKeyframes;
+}
+
+//=============================================================================
+/**
+ * Checks whether or not selected keyframes are being snapped to.
+ * This is used to ignore all selected keyframes when keyframes are being
+ * dragged.
+ * @return true if selected keyframes should be snapping points.
+ */
+bool CSnapper::IsSnappingSelectedKeyframes()
+{
+ return m_IsSnappingKeyframes && m_IsSnappingSelectedKeyframes;
+}
+
+//=============================================================================
+/**
+ * Set the current time ratio.
+ * This will effect all time based positions as well as the intervals. It is
+ * suggested that this is called on an empty snapper when possible for speed.
+ * @param inTimeRatio the new time ratio.
+ */
+void CSnapper::SetTimeRatio(double inTimeRatio)
+{
+ m_SnapDistance = ::dtol(m_SnapDistance * m_TimeRatio / inTimeRatio);
+ m_TimeRatio = inTimeRatio;
+}
+
+//=============================================================================
+/**
+ * Set the visible area of this snapper.
+ * This is used to limit snapping to visible areas only. The visibility limit
+ * is only on vertical because the user can scroll horizontally and expose
+ * previously non visible objects. The heights are relative to the initial
+ * offset and
+ * @param inStartHeight the minimum height for visibility.
+ * @param inEndHeight the maximum height for visibility.
+ */
+void CSnapper::SetVisibleArea(long inStartHeight, long inEndHeight)
+{
+ m_StartHeight = inStartHeight;
+ m_EndHeight = inEndHeight;
+}
+
+//=============================================================================
+/**
+ * Push an offset into this for calculating later visibilities.
+ * This is accumulated with previous offsets.
+ * @param inHeight the amount to modify the offset by.
+ */
+void CSnapper::PushOffset(long inHeight)
+{
+ m_Offsets.push_back(inHeight);
+ m_Offset += inHeight;
+}
+
+//=============================================================================
+/**
+ * Remove an offset that was pushed on.
+ * This will update the current offset to be what it was before the push.
+ */
+void CSnapper::PopOffset()
+{
+ m_Offset -= m_Offsets.back();
+ m_Offsets.pop_back();
+}
+
+//=============================================================================
+/**
+ * Checks to see if an object at inPosition of height inHeight is visible.
+ * This uses the current offset with the visible area to check visibility.
+ * @param inPosition the position of the object to be checked.
+ * @param inHeight the height of the object to be checked.
+ */
+bool CSnapper::IsVisible(long inPosition, long inHeight)
+{
+ return (inPosition + m_Offset < m_EndHeight
+ && inPosition + m_Offset + inHeight > m_StartHeight);
+}
+
+//=============================================================================
+/**
+ * Add a periodic interval to the snapping points.
+ * This will make snapping points at every multiple of inInterval. The interval
+ * starts at time 0.
+ * @param inInterval time in millis for the periodic points.
+ */
+void CSnapper::SetPeriodicInterval(long inInterval)
+{
+ m_PeriodicInterval = inInterval;
+}
+
+//=============================================================================
+/**
+ * Interpret the given position into a snapped/nonsnapped position.
+ * This will use the inFlags to determine whether or not this should be snapping
+ * and uses inPosition to figure out the closest snapping position. If the
+ * closest position is not within the tolerances then inPosition will be
+ * returned.
+ * @param inPosition to position to check for snapping.
+ * @param inFlags the mouse state flags, to determine whether or not snapping.
+ */
+bool CSnapper::InterpretTimeEx(long &ioTime, long inFlags)
+{
+ // Only snap if shift key is down.
+ if (inFlags & CHotKeys::MODIFIER_SHIFT)
+ return GetSnapTime(ioTime, true);
+ else
+ return GetSnapTime(ioTime, false);
+}
+
+//=============================================================================
+/**
+ * Interpret the given position into a snapped/nonsnapped position.
+ * This will use the inFlags to determine whether or not this should be snapping
+ * and uses inPosition to figure out the closest snapping position. If the
+ * closest position is not within the tolerances then inPosition will be
+ * returned.
+ * @param inPosition to position to check for snapping.
+ * @param inFlags the mouse state flags, to determine whether or not snapping.
+ */
+long CSnapper::InterpretTime(long inTime, long inFlags)
+{
+ if (inFlags & CHotKeys::MODIFIER_SHIFT) {
+ GetSnapTime(inTime, true);
+ return inTime;
+ }
+ GetSnapTime(inTime, false);
+ return inTime;
+}
+
+//=============================================================================
+/**
+ * Set the maximum distance that snapping will occur at.
+ * This sets the maximum tolerances for a position to be away from a snapping
+ * point and still get snapped to it.
+ * @param inSnapDistance the snap distance, in pixels.
+ */
+void CSnapper::SetSnappingDistance(long inSnapDistance)
+{
+ m_SnapDistance = ::dtol(inSnapDistance / m_TimeRatio);
+}
+
+//=============================================================================
+/**
+ * Helper method to find the closer of two values to a third.
+ * If both values are the same distance then the first value will be returned.
+ * @param inFirst the first value to check the distance to inBase.
+ * @param inSecond the second value to check the distance to inBase.
+ * @param inBase the value the others are being compared to.
+ * @return the value, either first or second, that is closest to inBase.
+ */
+long GetClosestValue(long inFirst, long inSecond, long inBase)
+{
+ return (::labs(inFirst - inBase) <= ::labs(inSecond - inBase)) ? inFirst : inSecond;
+}
+
+//=============================================================================
+/**
+ * Given the current time, it is adjusted if necessary to snap.
+ * @param ioTime the current time on input; on output the adjusted time
+ * @param inShiftKeyDown true if the shift key was down, otherwise false
+ * @return true if a snap occurred, otherwise false
+ */
+bool CSnapper::GetSnapTime(long &ioTime, bool inShiftKeyDown)
+{
+ bool theReturnValue = false;
+
+ if (inShiftKeyDown) // If user hits the shift key (i.e. snapping is toggled on)
+ {
+ long thePreviousTime = 0;
+ long theNextTime = 0;
+
+ // Go through all the snapping positions finding the positions on either
+ // side of ioPosition. Bsically just loop through until a snap position
+ // is larger than in position and use that with the previous value to get
+ // the closest snapping location.
+ TTimeList::iterator thePos = m_Times.begin();
+ for (; thePos != m_Times.end(); ++thePos) {
+ thePreviousTime = theNextTime;
+ theNextTime = (*thePos);
+
+ // Don't need to go any further because we've hit the first point larget than
+ // ioPosition.
+ if (theNextTime >= ioTime) {
+ break;
+ }
+ }
+
+ // Use the last snap position less than ioPosition and the first snap position greater than
+ // ioPosition
+ // to find the closest of the two.
+ long theClosestTime = GetClosestValue(thePreviousTime, theNextTime, ioTime);
+ long theClosestInterval = GetClosestPeriodicInterval(ioTime);
+
+ // Get the closest snapping position between the periodic interval and the position
+ theClosestTime = GetClosestValue(theClosestTime, theClosestInterval, ioTime);
+
+ // If the closest position is within tolerances then use it, otherwise return the original
+ // value.
+ if (::labs(theClosestTime - ioTime) <= m_SnapDistance) {
+ ioTime = theClosestTime;
+ theReturnValue = true;
+ }
+ } else // If user does not hit the shift key (i.e. snapping is toggled off)
+ {
+ // Snap to end handles at 1 pixel range if the current object dragged
+ // is a keyframe
+ if (m_KeyFrameClicked) {
+ // Returns if the startTime or the endTime of a Time Bar is closer to the dragged
+ // keyframe
+ long theClosestTime = GetClosestValue(m_theStartTime, m_theEndTime, ioTime);
+
+ // Set snapping range to 1 pixel and converts it to time.
+ // The snapping range of 1 pixel applies for keyframes that are dragged really
+ // close to the end handles.
+ long thePixel = 1;
+ long theTime = ::dtol(thePixel / m_TimeRatio);
+
+ // Determines if the closest time is within 1 pixel range
+ // If so returns the closest time, which is the snapping time, and true indicating
+ // that snapping occurs.
+ if (::labs(theClosestTime - ioTime) <= theTime) {
+ ioTime = theClosestTime;
+ theReturnValue = true;
+ }
+ }
+ }
+
+ return theReturnValue;
+}
+//=============================================================================
+/**
+ * Get the closest periodic interval to inPosition.
+ * Since it is too expensive to store every possible periodic interval in the
+ * snapping list, this just dynamically figures out the closest periodic
+ * interval.
+ */
+void CSnapper::SetStartEndTime(long theStartTime, long theEndTime)
+{
+ m_theStartTime = theStartTime;
+ m_theEndTime = theEndTime;
+}
+//=============================================================================
+/**
+ * Get the closest periodic interval to inPosition.
+ * Since it is too expensive to store every possible periodic interval in the
+ * snapping list, this just dynamically figures out the closest periodic
+ * interval.
+ */
+long CSnapper::GetClosestPeriodicInterval(long inTime)
+{
+ long theIntervalLow = inTime / m_PeriodicInterval * m_PeriodicInterval;
+ long theIntervalHigh = (inTime / m_PeriodicInterval + 1) * m_PeriodicInterval;
+
+ return GetClosestValue(theIntervalLow, theIntervalHigh, inTime);
+}
+
+//=============================================================================
+/**
+ * Used to pass off snapping logic to this for objects being dragged.
+ * This does all the work of an object when the object itself is being dragged
+ * and it's position is being modified by the drag, but it needs to be snapped
+ * as well. It is not necessary to call this unless ProcessDrag is being
+ * used.
+ * @param inClickPosition the mouse click location, usually just inPoint.x.
+ * @param inCenterOffset the center of the object where it should be snapped to.
+ */
+void CSnapper::BeginDrag(long inClickLocation, long inCenterTimeOffset)
+{
+ m_InitialOffset = inClickLocation;
+ m_ObjectTimeOffset = inCenterTimeOffset;
+}
+
+//=============================================================================
+/**
+ * Process an object's drag event and figure out where the object should be.
+ * This does all the work of figuring out where the object should be snapped
+ * to. It is not necessary to call this, but it may make implementing snapping
+ * much easier. BeginDrag needs to be called on OnMouseDown to use this.
+ * @param inPosition the position of the mouse, GetPosition( ).x + inPoint.x.
+ * @param inFlags the mouse state flags, used to determine snapping state.
+ */
+long CSnapper::ProcessDrag(long inTime, long inOffset, long inFlags)
+{
+ long theModPos = inTime + m_TimeOffset + ::dtol((inOffset - m_InitialOffset) / m_TimeRatio);
+ InterpretTimeEx(theModPos, inFlags);
+ theModPos -= m_TimeOffset;
+
+ return theModPos;
+}
+
+//=============================================================================
+/**
+ * Set the source for this Snapper object.
+ * This is so that objects may choose to no add themselves to snapping lists
+ * that they originated. This is only meant for comparison with the 'this' ptr.
+ * @param inSource the source object for this snapping list.
+ */
+void CSnapper::SetSource(void *inSource)
+{
+ m_Source = inSource;
+}
+
+//=============================================================================
+/**
+ * Get the source for this snapper object.
+ * @return the source of the snapping.
+ */
+void *CSnapper::GetSource()
+{
+ return m_Source;
+}
+
+void CSnapper::SetTimeOffset(long inTimeOffset)
+{
+ m_TimeOffset = inTimeOffset;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Snapper.h b/src/Authoring/Studio/Palettes/Timeline/Snapper.h
new file mode 100644
index 00000000..ea230bc0
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/Snapper.h
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_SNAPPER_H
+#define INCLUDED_SNAPPER_H 1
+
+#pragma once
+
+#include <set>
+#include <vector>
+
+class CSnapper
+{
+ typedef std::set<long> TTimeList;
+ typedef std::vector<long> TOffsetList;
+
+public:
+ CSnapper(double inTimeRatio = .1);
+ virtual ~CSnapper();
+
+ void AddTime(long inTime);
+ void AddPixelLocation(long inPixelLoc);
+
+ void SetSnappingKeyframes(bool inIsSnappingKeyframes);
+ bool IsSnappingKeyframes();
+ void SetSnappingSelectedKeyframes(bool inIsSnappingSelectedKeyframes);
+ bool IsSnappingSelectedKeyframes();
+
+ void Clear();
+
+ void SetVisibleArea(long inStartHeight, long inEndHeight);
+ void PushOffset(long inHeight);
+ void PopOffset();
+ bool IsVisible(long inPosition, long inHeight);
+
+ void SetTimeRatio(double inTimeRatio);
+
+ void SetPeriodicInterval(long inInterval);
+
+ bool InterpretTimeEx(long &ioTime, long inFlags);
+ long InterpretTime(long inTime, long inFlags);
+
+ void SetSnappingDistance(long inSnapDistance);
+
+ void BeginDrag(long inPosition, long inOffset = 0);
+ long ProcessDrag(long inTime, long inPosition, long inFlags);
+
+ void SetSource(void *inSource);
+ void *GetSource();
+
+ void SetTimeOffset(long inTimeOffset);
+ void SetStartEndTime(long theStartTime, long theEndTime);
+ void SetKeyFrameClicked(bool inKeyFrameClicked);
+
+protected:
+ bool GetSnapTime(long &inTime, bool inShiftKeyDown);
+ long GetClosestPeriodicInterval(long inTime);
+
+ long m_theStartTime;
+ long m_theEndTime;
+
+ TTimeList m_Times;
+ TOffsetList m_Offsets;
+
+ double m_TimeRatio;
+
+ bool m_IsSnappingKeyframes;
+ bool m_IsSnappingSelectedKeyframes;
+ long m_Offset;
+ long m_StartHeight;
+ long m_EndHeight;
+ long m_SnapDistance;
+
+ long m_PeriodicInterval;
+
+ long m_InitialOffset;
+ long m_ObjectTimeOffset;
+ long m_TimeOffset;
+ bool m_KeyFrameClicked;
+ void *m_Source;
+};
+
+// Interface that will provider the info for snapping logic in the timebars and keyframes
+class ISnappingListProvider
+{
+public:
+ virtual ~ISnappingListProvider() {}
+
+ virtual void PopulateSnappingList(CSnapper *inSnappingList) = 0;
+};
+
+#endif // INCLUDED_SNAPPER_H \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/StateRow.cpp b/src/Authoring/Studio/Palettes/Timeline/StateRow.cpp
new file mode 100644
index 00000000..bdc07a11
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/StateRow.cpp
@@ -0,0 +1,311 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "StateRow.h"
+#include "TimelineControl.h"
+#include "TimelineTimelineLayout.h"
+#include "ColorControl.h"
+#include "ToggleControl.h"
+#include "PropertyRow.h"
+#include "StateTimebarRow.h"
+#include "BaseTimebarlessRow.h"
+#include "BaseTimelineTreeControl.h"
+#include "Bindings/ITimelineItemBinding.h"
+
+//=============================================================================
+/**
+ * Creates a new CStateRow for the Asset.
+ * @param inParentRow the parent of this row.
+ */
+CStateRow::CStateRow(CBaseStateRow *inParentRow)
+{
+ m_ParentRow = inParentRow;
+}
+
+CStateRow::~CStateRow()
+{
+}
+
+CBlankToggleControl *CStateRow::CreateToggleControl()
+{
+ return (m_TimelineItemBinding->ShowToggleControls())
+ ? new CToggleControl(this, m_TimelineItemBinding)
+ : CBaseStateRow::CreateToggleControl();
+}
+
+//=============================================================================
+/**
+ * Create a new CStateTimebarRow.
+ * This is virtual and used for objects to return their type specific
+ * timebar rows if they want to.
+ * @return the created timebar row.
+ */
+CBaseTimebarlessRow *CStateRow::CreateTimebarRow()
+{
+ return new CStateTimebarRow(this);
+}
+
+//=============================================================================
+/**
+ * Initialize this object.
+ * This must be called after construction and may only be called once.
+ */
+void CStateRow::Initialize(ITimelineItemBinding *inTimelineItemBinding,
+ ISnappingListProvider *inProvider)
+{
+ CBaseStateRow::Initialize(inTimelineItemBinding);
+
+ // cache these numbers. I believe caching these numbers is to avoid having to incur expensive
+ // recursive calculations on ever draw.
+ CalculateActiveStartTime();
+ CalculateActiveEndTime();
+
+ SetSnappingListProvider(inProvider);
+
+ if (GetTimelineItem()->IsExpanded()) // this is stored for the current opened presentation and
+ // conveniently help you remember the last view before you
+ // switch slides.
+ Expand();
+ // sk - Delay loading till this is expanded. I think it makes more sense to not have to incur
+ // work till the UI needs to be displayed
+ // Plus it would not work now since the parent always needs to be 'fully' initialized for the
+ //SnappingListProvider, prior to any child creation.
+ // else
+ // LoadChildren( );
+}
+
+//=============================================================================
+/**
+ * Expand this node of the tree control.
+ * This will display all children the fit the filter.
+ */
+void CStateRow::Expand(bool inExpandAll /*= false*/, bool inExpandUp)
+{
+ // Only RecalcLayout if loaded children or expanded.
+ bool theDoRecalLayout = !m_Loaded;
+
+ if (!m_Loaded)
+ LoadChildren();
+
+ bool theWasExpanded = m_IsExpanded;
+ CBaseStateRow::Expand(inExpandAll, inExpandUp);
+ // Check if this is expanded
+ theDoRecalLayout |= (theWasExpanded != m_IsExpanded);
+ GetTimelineItem()->SetExpanded(
+ m_IsExpanded); // remember this setting so that it persist when this row is recreated
+
+ if (theDoRecalLayout)
+ DoTimelineRecalcLayout();
+}
+
+//=============================================================================
+/**
+ * Collapse this node of the tree control.
+ * This will hide all children of this control.
+ */
+void CStateRow::Collapse(bool inCollapseAll /* = false */)
+{
+ bool theWasExpanded = m_IsExpanded;
+ CBaseStateRow::Collapse(inCollapseAll);
+
+ GetTimelineItem()->SetExpanded(
+ m_IsExpanded); // remember this setting so that it persist when this row is recreated
+ // only RecalcLayout if this is collapsed
+ if (theWasExpanded != m_IsExpanded)
+ DoTimelineRecalcLayout();
+}
+
+bool CStateRow::PerformFilter(const CFilter &inFilter)
+{
+ return inFilter.Filter(m_TimelineItemBinding->GetTimelineItem());
+}
+
+//=============================================================================
+/**
+ * Set the indent of this control.
+ * This controls how far to the right the toggle and text display on this
+ * control. The indent should be increased for every level of sub-controls.
+ * @param inIndent how much this control should be indented.
+ */
+void CStateRow::SetIndent(long inIndent)
+{
+ CTimelineRow::SetIndent(inIndent);
+
+ m_TreeControl->SetIndent(inIndent);
+
+ TStateRowList::iterator thePos = m_StateRows.begin();
+ for (; thePos != m_StateRows.end(); ++thePos)
+ (*thePos)->SetIndent(inIndent + CTimelineRow::TREE_INDENT);
+
+ // For each property on this object
+ TPropertyRowList::iterator thePropPos = m_PropertyRows.begin();
+ for (; thePropPos != m_PropertyRows.end(); ++thePropPos) {
+ CPropertyRow *thePropRow = (*thePropPos);
+ if (thePropRow)
+ thePropRow->SetIndent(inIndent + CTimelineRow::TREE_INDENT);
+ }
+}
+
+bool CStateRow::HasVisibleChildren()
+{
+ if (!m_Loaded) {
+ CTimelineItemOrderedIterator theChildren(m_TimelineItemBinding);
+ // Return true if has children but do not load the children.
+ if (!theChildren.IsDone()) {
+ return true;
+ }
+ CTimelineItemPropertyIterator theProperties(m_TimelineItemBinding);
+ if (!theProperties.IsDone()) {
+ return true;
+ }
+ }
+ return CBaseStateRow::HasVisibleChildren();
+}
+
+ISnappingListProvider *CStateRow::GetSnappingListProvider() const
+{
+ CStateTimebarRow *theTimebarControl = dynamic_cast<CStateTimebarRow *>(m_TimebarControl);
+ return (theTimebarControl) ? &theTimebarControl->GetSnappingListProvider() : nullptr;
+}
+
+void CStateRow::SetSnappingListProvider(ISnappingListProvider *inProvider)
+{
+ CStateTimebarRow *theTimebarControl = dynamic_cast<CStateTimebarRow *>(m_TimebarControl);
+ if (theTimebarControl)
+ theTimebarControl->SetSnappingListProvider(inProvider);
+}
+
+//=============================================================================
+/**
+ * Trigger any external applications where applicable.
+ */
+void CStateRow::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ Q_UNUSED(inPoint);
+ Q_UNUSED(inFlags);
+
+ if (!m_TimelineItemBinding
+ ->OpenAssociatedEditor()) // if not handled, fall backon the base class
+ CBaseStateRow::OnMouseDoubleClick(inPoint, inFlags);
+}
+
+void CStateRow::OnTimeChange()
+{
+ CalculateActiveStartTime();
+ CalculateActiveEndTime();
+
+ // sk - I don't see the need to DoTimelineRecalcLayout here, because that is usually when height
+ // of the control change
+ // this should just change width.. but maybe I am missing something, so I am leaving this
+ //here for 'easy' debugging
+ // DoTimelineRecalcLayout( );
+
+ m_TimebarControl->UpdateTime(GetStartTime(), GetEndTime());
+
+ GetTopControl()->OnLayoutChanged();
+}
+
+//=============================================================================
+/**
+ * calculate the active start time... this function set the active start to its
+ * parent's start time if it comes after the objects start time
+ */
+bool CStateRow::CalculateActiveStartTime()
+{
+ long theRetVal = GetStartTime();
+
+ if (m_ParentRow) {
+ if (m_ParentRow->CalculateActiveStartTime()) {
+ long theParentActiveStart = m_ParentRow->GetActiveStart();
+ if (theParentActiveStart > theRetVal)
+ theRetVal = theParentActiveStart;
+ }
+ }
+ m_ActiveStart = theRetVal;
+ return true;
+}
+
+//=============================================================================
+/**
+ * calculate the active end time... this function set the active end to its
+ * parent's end time if it comes before the objects end time
+ */
+bool CStateRow::CalculateActiveEndTime()
+{
+ long theRetVal = GetEndTime();
+ if (m_ParentRow) {
+ if (m_ParentRow->CalculateActiveEndTime()) {
+ long theParentActiveEnd = m_ParentRow->GetActiveEnd();
+ if (theParentActiveEnd < theRetVal)
+ theRetVal = theParentActiveEnd;
+ }
+ }
+ m_ActiveEnd = theRetVal;
+ return true;
+}
+
+//==============================================================================
+/**
+ *
+ */
+long CStateRow::GetLatestEndTime()
+{
+ if (m_IsExpanded) // if its children are not visible, they do not have any affect
+ return CBaseStateRow::GetLatestEndTime();
+
+ return GetActiveEnd();
+}
+
+//=============================================================================
+/**
+ * Load all the properties on this object.
+ */
+void CStateRow::LoadProperties()
+{
+ m_TimelineItemBinding->LoadProperties();
+}
+
+//==============================================================================
+/**
+ * Tells the timeline timeline layout to recalc its layout. Should only be called
+ * from this class, that's why it's protected.
+ */
+void CStateRow::DoTimelineRecalcLayout()
+{
+ GetTopControl()->OnLayoutChanged();
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/StateRow.h b/src/Authoring/Studio/Palettes/Timeline/StateRow.h
new file mode 100644
index 00000000..f03682e3
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/StateRow.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_STATE_ROW_H
+#define INCLUDED_STATE_ROW_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "BaseStateRow.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CButtonControl;
+class CButtonDownListener;
+class CColorControl;
+class CStateTreeControl;
+class CToggleControl;
+class CStateTimebarlessRow;
+class CPropertyRow;
+class CCmdBatch;
+class CSnapper;
+class CResImage;
+
+class CStateRow : public CBaseStateRow
+{
+public:
+ CStateRow(CBaseStateRow *inParentRow);
+ virtual ~CStateRow();
+
+ using CBaseStateRow::Initialize;
+ virtual void Initialize(ITimelineItemBinding *inTimelineItemBinding,
+ ISnappingListProvider *inProvider);
+
+ void Expand(bool inExpandAll = false, bool inExpandUp = false) override;
+ void Collapse(bool inCollapseAll = false) override;
+ void SetIndent(long inIndent) override;
+ virtual void OnTimeChange();
+
+ long GetLatestEndTime() override;
+ bool CalculateActiveStartTime() override;
+ bool CalculateActiveEndTime() override;
+ bool HasVisibleChildren() override;
+ ISnappingListProvider *GetSnappingListProvider() const override;
+ void SetSnappingListProvider(ISnappingListProvider *inProvider) override;
+
+ // CControl
+ void OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+protected:
+ CBlankToggleControl *CreateToggleControl() override;
+ CBaseTimebarlessRow *CreateTimebarRow() override;
+
+ bool PerformFilter(const CFilter &inFilter) override;
+ void LoadProperties() override;
+ void DoTimelineRecalcLayout();
+};
+#endif // INCLUDED_STATE_ROW_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/StateRowFactory.cpp b/src/Authoring/Studio/Palettes/Timeline/StateRowFactory.cpp
new file mode 100644
index 00000000..921b4b04
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/StateRowFactory.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "StateRowFactory.h"
+#include "Bindings/ITimelineItemBinding.h"
+#include "StateRow.h"
+
+//=============================================================================
+/**
+ * Create the type specific StateRow for the Asset.
+ * Different asset use different derivations of StateRow, and this will
+ * return the proper state row for the asset.
+ * @param inTimelineItem the timeline item to create the state row for.
+ * @param inParentRow the parent row of the state row being created.
+ * @param inSnappingListProvider For keyframe/timebar snapping
+ * @return CStateRow the row that represents the state, or nullptr if it should not show up.
+ */
+CStateRow *CStateRowFactory::CreateStateRow(ITimelineItemBinding *inTimelineItem,
+ CBaseStateRow *inParentRow,
+ ISnappingListProvider *inSnappingListProvider)
+{
+ CStateRow *theRow = nullptr;
+ if (inTimelineItem) {
+ theRow = new CStateRow(inParentRow);
+
+ if (theRow != nullptr) {
+ theRow->Initialize(inTimelineItem, inSnappingListProvider);
+ }
+ }
+
+ return theRow;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/StateRowFactory.h b/src/Authoring/Studio/Palettes/Timeline/StateRowFactory.h
new file mode 100644
index 00000000..d818f4cd
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/StateRowFactory.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_STATE_ROW_FACTORY_H
+#define INCLUDED_STATE_ROW_FACTORY_H 1
+
+#pragma once
+
+class ITimelineItemBinding;
+class CStateRow;
+class CBaseStateRow;
+class ISnappingListProvider;
+
+class CStateRowFactory
+{
+protected:
+ CStateRowFactory();
+ virtual ~CStateRowFactory();
+
+public:
+ static CStateRow *CreateStateRow(ITimelineItemBinding *inTimelineItem, CBaseStateRow *inParent,
+ ISnappingListProvider *inSnappingListProvider);
+};
+#endif // INCLUDED_STATE_ROW_FACTORY_H \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.cpp b/src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.cpp
new file mode 100644
index 00000000..0a0ba258
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "StateTimebarRow.h"
+#include "Renderer.h"
+#include "StateRow.h"
+#include "StudioPreferences.h"
+#include "TimebarControl.h"
+#include "MasterP.h"
+#include "Snapper.h"
+#include "Bindings/ITimelineItemBinding.h"
+
+//=============================================================================
+/**
+ * Creates a new CStateTimebarRow for the StateRow.
+ * @param inStateRow the State Row that this is on.
+ * @param inCreateTimebar true if the constructor is responsible for creating a timebar, otherwise
+ * the derived class will take care of the construction.
+ *
+ */
+CStateTimebarRow::CStateTimebarRow(CStateRow *inStateRow, bool inCreateTimebar /*=true*/)
+ : CStateTimebarlessRow(inStateRow)
+ , m_Timebar(nullptr)
+{
+ if (inCreateTimebar) {
+ m_Timebar = new CTimebarControl(this, inStateRow->GetTimelineItemBinding());
+ m_Timebar->SetMinimumSize(CPt(0, CStudioPreferences::GetRowSize()));
+
+ AddChild(m_Timebar);
+ }
+}
+
+CStateTimebarRow::~CStateTimebarRow()
+{
+ delete m_Timebar;
+}
+
+//=============================================================================
+/**
+ * OnMouseRDown event, handles context menus for this object.
+ * @param inPoint the location of the mouse over this control.
+ * @param inFlags the mouse state flags.
+ */
+bool CStateTimebarRow::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CStateTimebarlessRow::OnMouseRDown(inPoint, inFlags)) {
+ CPt theTimebarPoint = inPoint - m_Timebar->GetPosition();
+ m_Timebar->ShowContextMenu(theTimebarPoint, false);
+ }
+ return true;
+}
+
+//=============================================================================
+/**
+ * Set the amount of time that is being represented per pixel.
+ * @param inTimerPerPixel the amound of time being represented per pixel.
+ */
+void CStateTimebarRow::SetTimeRatio(double inTimeRatio)
+{
+ CStateTimebarlessRow::SetTimeRatio(inTimeRatio);
+
+ m_Timebar->SetTimeRatio(inTimeRatio);
+}
+
+//=============================================================================
+/**
+ * Notification that the object that this row is representing has been selected.
+ */
+void CStateTimebarRow::OnSelect()
+{
+ CStateTimebarlessRow::OnSelect();
+
+ m_Timebar->SetSelected(true);
+}
+
+//=============================================================================
+/**
+ * Notification that the object that this row is representing has been deselected.
+ */
+void CStateTimebarRow::OnDeselect()
+{
+ CStateTimebarlessRow::OnDeselect();
+
+ m_Timebar->SetSelected(false);
+}
+
+//=============================================================================
+/**
+ * Notification from the Asset that it's time has changed.
+ * @param inStartTime the new start time.
+ * @param inEndTime the new end time.
+ */
+void CStateTimebarRow::UpdateTime(long inStartTime, long inEndTime)
+{
+ m_Timebar->Refresh(inStartTime, inEndTime);
+ Invalidate();
+}
+
+void CStateTimebarRow::PopulateSnappingList(CSnapper *inSnappingList)
+{
+ if (inSnappingList->GetSource() != m_Timebar) {
+ inSnappingList->AddTime(m_Timebar->GetStartTime());
+ inSnappingList->AddTime(m_Timebar->GetEndTime());
+ }
+ m_Timebar->PopulateSnappingList(inSnappingList);
+ CStateTimebarlessRow::PopulateSnappingList(inSnappingList);
+}
+
+//=============================================================================
+/**
+ * called when meta data for this row is changed... should be overridden by the
+ * timebar row
+ */
+void CStateTimebarRow::RefreshRowMetaData()
+{
+ Invalidate();
+ m_Timebar->RefreshMetaData();
+}
+
+void CStateTimebarRow::SetSnappingListProvider(ISnappingListProvider *inProvider)
+{
+ m_Timebar->SetSnappingListProvider(inProvider);
+}
+
+ISnappingListProvider &CStateTimebarRow::GetSnappingListProvider() const
+{
+ return m_Timebar->GetSnappingListProvider();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.h b/src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.h
new file mode 100644
index 00000000..7b62e3fd
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_STATE_TIMEBAR_ROW_H
+#define INCLUDED_STATE_TIMEBAR_ROW_H 1
+
+#pragma once
+
+#include "Control.h"
+#include "StateTimebarlessRow.h"
+
+class CStateRow;
+class CTimebarControl;
+class CSnapper;
+class ITimelineItemBinding;
+
+class CStateTimebarRow : public CStateTimebarlessRow
+{
+public:
+ CStateTimebarRow(CStateRow *inStateRow, bool inCreateTimebar = true);
+ virtual ~CStateTimebarRow();
+
+ // CControl
+ bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+ void SetTimeRatio(double inTimeRatio) override;
+
+ void OnSelect() override;
+ void OnDeselect() override;
+ void UpdateTime(long inStartTime, long inEndTime) override;
+
+ void PopulateSnappingList(CSnapper *inSnappingList) override;
+ void RefreshRowMetaData() override;
+
+ void SetSnappingListProvider(ISnappingListProvider *inProvider);
+ ISnappingListProvider &GetSnappingListProvider() const override;
+
+protected:
+ CTimebarControl *m_Timebar;
+};
+#endif // INCLUDED_STATE_TIMEBAR_ROW_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.cpp b/src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.cpp
new file mode 100644
index 00000000..6eebd0c4
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.cpp
@@ -0,0 +1,364 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "StateTimebarlessRow.h"
+#include "IKeyframe.h"
+#include "Renderer.h"
+#include "StateRow.h"
+#include "MasterP.h"
+#include "KeyframeContextMenu.h"
+#include "Snapper.h"
+#include "MultiSelectAspect.h"
+#include "PropertyTimebarRow.h"
+#include "PropertyRow.h"
+#include "AssetTimelineKeyframe.h"
+#include "Bindings/ITimelineItemBinding.h"
+#include "StudioUtils.h"
+
+//=============================================================================
+/**
+ * Creates a new CStateTimebarRow for the StateRow.
+ * @param inStateRow the State Row that this is on.
+ */
+CStateTimebarlessRow::CStateTimebarlessRow(CStateRow *inStateRow)
+ : m_StateRow(inStateRow)
+ , m_Selected(false)
+ , m_Refreshing(false)
+{
+ m_BackgroundColor = m_StateRow->GetTimebarBackgroundColor(m_StateRow->GetObjectType());
+}
+
+CStateTimebarlessRow::~CStateTimebarlessRow()
+{
+ TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin();
+ for (; thePos != m_Keyframes.end(); ++thePos) {
+ CAssetTimelineKeyframe *theDeletedKey = (*thePos);
+ RemoveChild(theDeletedKey);
+ delete theDeletedKey;
+ }
+}
+
+void CStateTimebarlessRow::OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation)
+{
+ CControl::OnDraw(inRenderer, inDirtyRect, inIgnoreValidation);
+}
+
+//=============================================================================
+/**
+ * Draws the this row background.
+ * @param inRenderer the renderer to draw to.
+ */
+void CStateTimebarlessRow::Draw(CRenderer *inRenderer)
+{
+ UICPROFILE(Draw);
+
+ if (m_DirtyFlag) {
+ RefreshKeyframes();
+ m_DirtyFlag = false;
+ }
+
+ CBaseTimebarlessRow::Draw(inRenderer);
+}
+
+//=============================================================================
+/**
+ * OnMouseRDown event, handles context menus for this object.
+ * @param inPoint the location of the mouse over this control.
+ * @param inFlags the mouse state flags.
+ */
+bool CStateTimebarlessRow::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ m_StateRow->Select(SBaseStateRowSelectionKeyState()); // ensure this is selected, but doesn't
+ // affect any key selections, because this
+ // can be triggered from a key being
+ // selected
+ return CControl::OnMouseRDown(inPoint, inFlags);
+}
+
+//=============================================================================
+/**
+ * Set the amount of time that is being represented per pixel.
+ * @param inTimerPerPixel the amound of time being represented per pixel.
+ */
+void CStateTimebarlessRow::SetTimeRatio(double inTimeRatio)
+{
+ CBaseTimebarlessRow::SetTimeRatio(inTimeRatio);
+
+ TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin();
+ for (; thePos != m_Keyframes.end(); ++thePos) {
+ (*thePos)->SetTimeRatio(inTimeRatio);
+ }
+}
+
+//=============================================================================
+/**
+ * Get the state row that this belongs to.
+ */
+CStateRow *CStateTimebarlessRow::GetStateRow()
+{
+ return m_StateRow;
+}
+
+//=============================================================================
+/**
+ * Handler for when a child key is selected
+ *
+ * @param inTime time of the key
+ */
+void CStateTimebarlessRow::OnKeySelected(long inTime, bool inSelected,
+ bool inClearPreviouslySelectedKeys)
+{
+ ITimelineItemBinding *theTimelineItemBinding = m_StateRow->GetTimelineItemBinding();
+ if (inSelected)
+ theTimelineItemBinding->SetSelected(false);
+
+ if (inClearPreviouslySelectedKeys)
+ theTimelineItemBinding->ClearKeySelection();
+
+ theTimelineItemBinding->SelectKeyframes(inSelected, inTime);
+ RefreshKeyframes();
+ Invalidate();
+}
+
+CBaseStateRow *CStateTimebarlessRow::GetBaseStateRow() const
+{
+ return m_StateRow;
+}
+
+//=============================================================================
+/**
+ * Checks the data binding, instead of the property rows since they may not be created
+ * (delayed-loading) if this is not expanded.
+ */
+bool CStateTimebarlessRow::PropertiesHaveKeyframe(long inTime)
+{
+ bool theResult = false;
+
+ ITimelineItemBinding *theTimelineItemBinding = m_StateRow->GetTimelineItemBinding();
+ long theNumProps = theTimelineItemBinding->GetPropertyCount();
+ for (long theIndex = 0; theIndex < theNumProps; ++theIndex) {
+ ITimelineItemProperty *theProp = theTimelineItemBinding->GetProperty(theIndex);
+ if (theProp && theProp->GetKeyframeByTime(inTime)) {
+ theResult = true;
+ break;
+ }
+ }
+ return theResult;
+}
+
+//=============================================================================
+/**
+ * called when keyframes need to be updated, this funciton has two loops:
+ * the first loops through and deletes any keys no longer in the sskf list. the
+ * second adds any keys in the sskf list that are not already in the list
+ *
+ */
+void CStateTimebarlessRow::RefreshKeyframes()
+{
+ UICPROFILE(RefreshKeyframes);
+
+ m_Refreshing = true;
+
+ ITimelineItemBinding *theTimelineItemBinding = m_StateRow->GetTimelineItemBinding();
+ long theKeyframeCount = theTimelineItemBinding->GetKeyframeCount();
+ TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin();
+
+ // First Loop clears any keys that do not correlate to a supersetkey
+ while (thePos != m_Keyframes.end()) {
+ CAssetTimelineKeyframe *theTimelineKey = (*thePos);
+ IKeyframe *theTempKey = nullptr;
+ theTempKey = theTimelineItemBinding->GetKeyframeByTime(theTimelineKey->GetTime());
+
+ // If we find a key at this time, then the timeline key doesn't need to be deleted
+ if (!theTempKey || !PropertiesHaveKeyframe(theTimelineKey->GetTime())) {
+ RemoveChild(theTimelineKey);
+ delete theTimelineKey;
+ thePos = m_Keyframes.erase(thePos);
+ } else if (theTempKey->IsDynamic() != theTimelineKey->IsDynamic()) {
+ theTimelineKey->SetDynamic(theTempKey->IsDynamic());
+ } else {
+ // Set the position
+ theTimelineKey->SetPosition(::TimeToPos(theTempKey->GetTime(), m_TimeRatio)
+ - (theTimelineKey->GetSize().x / 2),
+ 0);
+ ++thePos;
+ }
+ }
+
+ // Second Loop adds the remaining keys
+ for (long theKey = 0; theKey < theKeyframeCount; ++theKey) {
+ bool theFoundFlag = false;
+ IKeyframe *theTempKey = theTimelineItemBinding->GetKeyframeByIndex(theKey);
+ TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin();
+
+ // each key needs to be compared to all the keys in the sskf list to see if it has to be
+ // added.
+ for (; thePos != m_Keyframes.end() && !theFoundFlag; ++thePos) {
+ CAssetTimelineKeyframe *theCurrentKey = (*thePos);
+ if (theCurrentKey->GetTime() == theTempKey->GetTime()) {
+ theFoundFlag = true;
+ }
+ }
+ if (!theFoundFlag && PropertiesHaveKeyframe(theTempKey->GetTime())) {
+ // If we don't have a timeline key, then we have to make a new one
+ CAssetTimelineKeyframe *theAssetTimelineKey =
+ new CAssetTimelineKeyframe(this, m_TimeRatio);
+ theAssetTimelineKey->SetTime(theTempKey->GetTime());
+ theAssetTimelineKey->Select(theTempKey->IsSelected());
+ theAssetTimelineKey->SetDynamic(theTempKey->IsDynamic());
+ theAssetTimelineKey->SetSize(CPt(17, 16));
+ theAssetTimelineKey->SetPosition(::TimeToPos(theTempKey->GetTime(), m_TimeRatio)
+ - (theAssetTimelineKey->GetSize().x / 2),
+ 0);
+ AddChild(theAssetTimelineKey);
+ m_Keyframes.push_back(theAssetTimelineKey);
+ }
+ }
+ m_Refreshing = false;
+}
+
+void CStateTimebarlessRow::Invalidate(bool inInvalidate)
+{
+ if (!m_Refreshing) {
+ CControl::Invalidate(inInvalidate);
+ }
+}
+
+//=============================================================================
+/**
+ * called when a list has a member change selection
+ * @param inTime -1 to affect all keyframes.
+ *
+ */
+void CStateTimebarlessRow::SelectKeysByTime(long inTime, bool inSelected)
+{
+ TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin();
+ bool theFoundFlag = false;
+ for (; thePos != m_Keyframes.end() && !theFoundFlag; ++thePos) {
+ CAssetTimelineKeyframe *theKey = (*thePos);
+ if (inTime == -1 || theKey->GetTime() == inTime) {
+ theKey->Select(inSelected);
+ theFoundFlag = (inTime != -1);
+ }
+ }
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * SelectKeysInRect: selects any keyframes inside the rect
+ *
+ * @param inRect the Rect to select the keyframes in
+ * @return NONE.
+ */
+void CStateTimebarlessRow::SelectKeysInRect(CRct inRect, bool inModifierKeyDown)
+{
+ CMultiSelectAspect<TTimelineAssetKeyframeList> theMultiSelectAspect(
+ m_Keyframes, m_StateRow->GetTimelineItemBinding());
+ theMultiSelectAspect.MultiSelect(inRect, inModifierKeyDown);
+}
+
+//=============================================================================
+/**
+ * CommitSelections: commits all the master keyframe selections by setting their
+ * previous selection state to the current selection state.
+ * This will prevent the current keyframe states from
+ *changing.
+ *
+ * @param NONE
+ * @return NONE
+ */
+
+void CStateTimebarlessRow::CommitSelections()
+{
+ CMultiSelectAspect<TTimelineAssetKeyframeList> theMultiSelectAspect(
+ m_Keyframes, m_StateRow->GetTimelineItemBinding());
+ theMultiSelectAspect.CommitSelections();
+}
+
+//=============================================================================
+/**
+ * true if there are selected keys on this object
+ */
+bool CStateTimebarlessRow::HasSelectedKeys()
+{
+ bool theRetVal = false;
+ TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin();
+ for (; thePos != m_Keyframes.end() && !theRetVal; ++thePos) {
+ if ((*thePos)->IsSelected()) {
+ theRetVal = true;
+ }
+ }
+ return theRetVal;
+}
+
+//=============================================================================
+/**
+ * selects all keys for this timebar row
+ */
+void CStateTimebarlessRow::SelectAllKeys()
+{
+ m_StateRow->GetTimelineItemBinding()->SelectKeyframes(true, -1);
+
+ TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin();
+ for (; thePos != m_Keyframes.end(); ++thePos)
+ (*thePos)->Select(true);
+
+ Invalidate();
+}
+
+//=============================================================================
+/**
+ * Populates the snapping list with any snapping points that may be on this.
+ * This will add the timebar ends, master keyframes to the snapping list, and
+ * time labels to the snapping list.
+ * @param inSnapper the snapper to add the points to.
+ */
+void CStateTimebarlessRow::PopulateSnappingList(CSnapper *inSnapper)
+{
+ // Only add points if this is not the object originating the snapping.
+ if (inSnapper->GetSource() != this) {
+ // Add Keyframes
+ TTimelineAssetKeyframeList::iterator thePos = m_Keyframes.begin();
+ for (; thePos != m_Keyframes.end(); ++thePos) {
+ if (inSnapper->IsSnappingSelectedKeyframes())
+ inSnapper->AddTime((*thePos)->GetTime());
+ else if (!(*thePos)->IsSelected())
+ inSnapper->AddTime((*thePos)->GetTime());
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.h b/src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.h
new file mode 100644
index 00000000..1812e365
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_STATE_TIMEBARLESS_ROW_H
+#define INCLUDED_STATE_TIMEBARLESS_ROW_H 1
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "BaseTimebarlessRow.h"
+#include "DispatchListeners.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CStateRow;
+class CSnapper;
+class CAssetTimelineKeyframe;
+class ITimelineItemBinding;
+
+class CStateTimebarlessRow : public CBaseTimebarlessRow
+{
+ typedef std::vector<CAssetTimelineKeyframe *> TTimelineAssetKeyframeList;
+
+public:
+ CStateTimebarlessRow(CStateRow *inStateRow);
+ virtual ~CStateTimebarlessRow();
+
+ void OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation = false) override;
+ void Draw(CRenderer *inRenderer) override;
+
+ bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+ void OnKeySelected(long inTime, bool inState, bool inClearPreviouslySelectedKeys);
+
+ void SetTimeRatio(double inTimeRatio) override;
+
+ virtual void RefreshKeyframes();
+ void Invalidate(bool inInvalidate = true) override;
+ void CommitSelections() override;
+ void SelectKeysInRect(CRct inRect, bool inModifierKeyDown) override;
+ void SelectAllKeys() override;
+ void SelectKeysByTime(long inTime, bool inSelected) override;
+ bool HasSelectedKeys();
+ CStateRow *GetStateRow();
+ void PopulateSnappingList(CSnapper *inSnapper) override;
+
+protected:
+ CBaseStateRow *GetBaseStateRow() const override;
+ bool PropertiesHaveKeyframe(long inTime);
+
+protected:
+ CStateRow *m_StateRow;
+ bool m_Selected;
+ TTimelineAssetKeyframeList m_Keyframes; ///<Master Keyframe list ( STL )
+ bool m_Refreshing;
+};
+#endif // INCLUDED_STATE_TIMEBARLESS_ROW_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.cpp b/src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.cpp
new file mode 100644
index 00000000..5ef32619
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//==============================================================================
+// Includes
+//==============================================================================
+#include "stdafx.h"
+#include "TimeEditAspect.h"
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CTimeEditAspect::CTimeEditAspect()
+{
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CTimeEditAspect::~CTimeEditAspect()
+{
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.h b/src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.h
new file mode 100644
index 00000000..f8cf0599
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_TIME_EDIT_ASPECT_H
+#define INCLUDED_TIME_EDIT_ASPECT_H 1
+
+#pragma once
+//==============================================================================
+// Prefix
+//==============================================================================
+
+//==============================================================================
+/**
+ * @class CTimeEditAspect: It contains cross-platform codes that handles the Time Edit
+ * processing for the the time edit dialog box in Mac and Win
+ */
+//==============================================================================
+class CTimeEditAspect
+{
+protected:
+public:
+ CTimeEditAspect();
+ ~CTimeEditAspect();
+};
+#endif // INCLUDED_TIME_EDIT_ASPECT_H \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeMeasure.cpp b/src/Authoring/Studio/Palettes/Timeline/TimeMeasure.cpp
new file mode 100644
index 00000000..9735499a
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimeMeasure.cpp
@@ -0,0 +1,340 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "TimeMeasure.h"
+#include "Renderer.h"
+#include "StudioPreferences.h"
+#include "StudioUtils.h"
+#include "TimelineTimelineLayout.h"
+#include "Snapper.h"
+#include "UICDMSignals.h"
+
+const long AUTO_TICK_AMNT = 60;
+using namespace Q3DStudio;
+
+//=============================================================================
+/**
+ * Create a new time measure.
+ * @param inLayout the layout this is representing, used for modifying time.
+ * @param inTimeRatio the current time ratio.
+ * @param inIsTransparent true if the background of this control should not be drawn.
+ */
+CTimeMeasure::CTimeMeasure(CTimelineTimelineLayout *inLayout, double inTimeRatio,
+ bool inFillBackground /*= true */)
+ : CBaseMeasure(inTimeRatio, inFillBackground)
+ , m_ScrollDir(0)
+ , m_TimePerPixel(0)
+ , m_IsMouseDown(false)
+ , m_TimelineLayout(inLayout)
+{
+ SetTimeRatio(inTimeRatio);
+ SetName("TimeMeasure");
+
+ m_EdgeMargin = 2;
+ // the large tickmark is shorter than the medium to leave room for the text
+ m_LargeHashOffset = 5;
+}
+
+CTimeMeasure::~CTimeMeasure()
+{
+}
+
+//=============================================================================
+/**
+ * Set the amount of time that is represented for each pixel.
+ * @param inTimePerPixel the amount of time represented for each pixel.
+ */
+void CTimeMeasure::SetTimeRatio(double inTimeRatio)
+{
+ m_Ratio = inTimeRatio;
+
+ double theTimePerPixel = (double)(1 / inTimeRatio);
+
+ // Only go through this if it has actually changed
+ if (theTimePerPixel != m_TimePerPixel) {
+ m_TimePerPixel = theTimePerPixel;
+
+ // Go through the possible hash settings and find the one that best suits the
+ // time per pixel.
+ double theMillisPerLargeHash = theTimePerPixel * 50;
+ if (theMillisPerLargeHash <= 100) // 100ms
+ theMillisPerLargeHash = 100;
+ else if (theMillisPerLargeHash <= 200) // 200ms
+ theMillisPerLargeHash = 200;
+ else if (theMillisPerLargeHash <= 500) // .5s
+ theMillisPerLargeHash = 500;
+ else if (theMillisPerLargeHash <= 1000) // 1s
+ theMillisPerLargeHash = 1000;
+ else if (theMillisPerLargeHash <= 2000) // 2s
+ theMillisPerLargeHash = 2000;
+ else if (theMillisPerLargeHash <= 5000) // 5s
+ theMillisPerLargeHash = 5000;
+ else if (theMillisPerLargeHash <= 10000) // 10s
+ theMillisPerLargeHash = 10000;
+ else if (theMillisPerLargeHash <= 20000) // 20s
+ theMillisPerLargeHash = 20000;
+ else if (theMillisPerLargeHash <= 30000) // 30s
+ theMillisPerLargeHash = 30000;
+ else if (theMillisPerLargeHash <= 60000) // 1m
+ theMillisPerLargeHash = 60000;
+ else if (theMillisPerLargeHash <= 120000) // 2m
+ theMillisPerLargeHash = 120000;
+ else if (theMillisPerLargeHash <= 300000) // 5m
+ theMillisPerLargeHash = 300000;
+ else if (theMillisPerLargeHash <= 600000) // 10m
+ theMillisPerLargeHash = 600000;
+ else if (theMillisPerLargeHash <= 1200000) // 20m
+ theMillisPerLargeHash = 1200000;
+ else if (theMillisPerLargeHash <= 1800000) // 30m
+ theMillisPerLargeHash = 1800000;
+ else if (theMillisPerLargeHash <= 3600000) // 1h
+ theMillisPerLargeHash = 3600000;
+ else
+ theMillisPerLargeHash = 7200000; // 2h
+
+ // Set the distances between the hashes
+ m_LargeHashInterval = theMillisPerLargeHash;
+ m_MediumHashInterval = theMillisPerLargeHash / 2;
+ m_SmallHashInterval = theMillisPerLargeHash / 10;
+
+ // update to StudioPreferences so that the ',' '.' and '<' '>' keys would respond
+ // accordingly
+ CStudioPreferences::SetTimeAdvanceAmount(static_cast<long>(m_SmallHashInterval));
+ CStudioPreferences::SetBigTimeAdvanceAmount(static_cast<long>(m_MediumHashInterval));
+
+ Invalidate();
+ }
+}
+//=============================================================================
+/**
+ * Get the time formatted as a string.
+ * This will figure out the best way to display the time and return it as a
+ * string.
+ * @param inTime the time to display in milliseconds.
+ * @return the time formatted in a string.
+ */
+Q3DStudio::CString CTimeMeasure::FormatTime(long inTime)
+{
+ long theHours = inTime / 3600000;
+ long theMinutes = inTime % 3600000 / 60000;
+ long theSeconds = inTime % 60000 / 1000;
+ long theMillis = inTime % 1000;
+
+ bool theHoursOnlyFlag = theHours != 0 && theMinutes == 0 && theSeconds == 0 && theMillis == 0;
+ bool theMinutesOnlyFlag =
+ !theHoursOnlyFlag && theMinutes != 0 && theSeconds == 0 && theMillis == 0;
+ bool theSecondsOnlyFlag = !theMinutesOnlyFlag && theMillis == 0;
+
+ Q3DStudio::CString theTime;
+ // If only hours are being displayed then format it as hours.
+ if (theHoursOnlyFlag) {
+ theTime.Format(_UIC("%dh"), theHours);
+ }
+ // If only minutes are being displayed then format it as minutes.
+ else if (theMinutesOnlyFlag) {
+ theTime.Format(_UIC("%dm"), theMinutes);
+ }
+ // If only seconds are being displayed then format as seconds
+ else if (theSecondsOnlyFlag) {
+ theTime.Format(_UIC("%ds"), theSeconds);
+ }
+ // If the intervals are correct then this should only be tenths of seconds, so do that.
+ else {
+ theTime.Format(_UIC("0.%ds"), theMillis / 100);
+ }
+
+ return theTime;
+}
+
+//=============================================================================
+/**
+ * Set the amount of time that this time measure is offset by.
+ * @param inTimeOffset the offset time in milliseconds.
+ */
+void CTimeMeasure::SetTimeOffset(long inTimeOffset)
+{
+ if (inTimeOffset != m_Offset) {
+ m_Offset = inTimeOffset;
+
+ Invalidate();
+ }
+}
+
+//=============================================================================
+/**
+ * Notification that the left mouse button was clicked.
+ * This tells the timeline to move the playhead to the current loc.
+ * @param inPoint the location where the mouse was clicked.
+ * @param inFlags the state of the mouse.
+ */
+bool CTimeMeasure::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseDown(inPoint, inFlags)) {
+ m_IsMouseDown = true;
+
+ m_TimelineLayout->OnTimeMeasureMouseDown(inPoint, inFlags);
+ }
+
+ return true;
+}
+
+//=============================================================================
+/**
+ * Notification that the mouse is moving over this control.
+ * If the mouse was clicked on this control this will drag the playhead.
+ * @param inPoint the location where the mouse was clicked.
+ * @param inFlags the state of the mouse.
+ */
+void CTimeMeasure::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ m_TimerConnection = std::shared_ptr<UICDM::ISignalConnection>();
+
+ // subtract out the button width since the playhead is never allowed into that area on the right
+ // side
+ // of the timeline and use it for the initial autoscrolling place
+ if (inPoint.x > 0 && inPoint.x <= GetSize().x - CStudioPreferences::GetDefaultButtonWidth()) {
+ CControl::OnMouseMove(inPoint, inFlags);
+ if (m_IsMouseDown)
+ m_TimelineLayout->OnTimeMeasureMouseDown(inPoint, inFlags);
+ m_ScrollDir = 0;
+ } else if (m_IsMouseDown) {
+ if (inPoint.x < 0)
+ m_ScrollDir = -1;
+ else if (inPoint.x > GetSize().x - CStudioPreferences::GetDefaultButtonWidth())
+ m_ScrollDir = 1;
+ m_TimerConnection = ITickTock::GetInstance().AddTimer(
+ 150, true, std::bind(&CTimeMeasure::OnTimer, this), "CTimeMeasure::OnMouseMove");
+ OnTimer();
+ }
+}
+
+//=============================================================================
+/**
+ * Call back for the timer that was set in on mouse move
+ */
+void CTimeMeasure::OnTimer()
+{
+ CPt theOffset;
+ if (m_ScrollDir > 0)
+ theOffset.x =
+ GetSize().x - 2 * CStudioPreferences::GetDefaultButtonWidth() + AUTO_TICK_AMNT;
+ else if (m_ScrollDir < 0)
+ theOffset.x = -AUTO_TICK_AMNT;
+ m_TimelineLayout->OnTimeMeasureMouseDown(theOffset, 0);
+ ;
+}
+
+//=============================================================================
+/**
+ * Notification that the mouse was unclicked.
+ * This stops dragging of the playhead if it was dragging it.
+ * @param inPoint the location where the mouse was unclicked.
+ * @param inFlags the state of the mouse.
+ */
+void CTimeMeasure::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseUp(inPoint, inFlags);
+ m_TimerConnection = std::shared_ptr<UICDM::ISignalConnection>();
+ m_IsMouseDown = false;
+}
+
+//=============================================================================
+/**
+ * Notification that the mouse was unclicked.
+ * This stops dragging of the playhead if it was dragging it.
+ * @param inPoint the location where the mouse was unclicked.
+ * @param inFlags the state of the mouse.
+ */
+void CTimeMeasure::OnMouseRUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseUp(inPoint, inFlags);
+ m_TimerConnection = std::shared_ptr<UICDM::ISignalConnection>();
+ m_IsMouseDown = false;
+}
+
+//=============================================================================
+/**
+ * Add the tick marks to the snapping list.
+ * This uses the user preference for the tick marks and adds them.
+ */
+void CTimeMeasure::PopulateSnappingList(CSnapper *inSnapper)
+{
+ // Only if this is supposed to snap to time markers.
+ if (CStudioPreferences::IsTimelineSnappingGridActive()) {
+ // Check the resolution to snap to
+ ESnapGridResolution theResolution = CStudioPreferences::GetTimelineSnappingGridResolution();
+ double thePeriodicInterval;
+ if (theResolution == SNAPGRID_TICKMARKS) {
+ thePeriodicInterval = m_SmallHashInterval;
+ } else if (theResolution == SNAPGRID_HALFSECONDS) {
+ thePeriodicInterval = m_MediumHashInterval;
+ } else {
+ thePeriodicInterval = m_LargeHashInterval;
+ }
+
+ // Set a periodic interval for snapping
+ inSnapper->SetPeriodicInterval(::dtol(thePeriodicInterval));
+ }
+}
+
+void CTimeMeasure::OnLoseFocus()
+{
+ m_TimerConnection = std::shared_ptr<UICDM::ISignalConnection>();
+ m_IsMouseDown = false;
+}
+
+//=============================================================================
+/**
+ * Draw the time at the specified position.
+ * @param inRenderer the renderer to draw to.
+ * @param inPosition the position to draw the time to, the time will be centered here.
+ * @param inTime the time to draw.
+ */
+void CTimeMeasure::DrawMeasureText(CRenderer *inRenderer, long inPosition, long inMeasure)
+{
+ Q3DStudio::CString theTimeFormat(FormatTime(inMeasure));
+ // Offset the position by half the text size to center it over the hash.
+ const auto textSize = inRenderer->GetTextSize(theTimeFormat.toQString());
+ inPosition -= ::dtol(textSize.width() / 2);
+
+ inRenderer->DrawText((float)inPosition, -3, theTimeFormat.toQString(),
+ QRect(0, 0, GetSize().x, GetSize().y),
+ CStudioPreferences::GetRulerTickColor().getQColor());
+}
+
+//=============================================================================
+/**
+ * Calculate the position of a time value on the time measure
+ */
+long CTimeMeasure::CalculatePos(double inNewValue)
+{
+ return ::TimeToPos(inNewValue, m_Ratio);
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeMeasure.h b/src/Authoring/Studio/Palettes/Timeline/TimeMeasure.h
new file mode 100644
index 00000000..7e72a52c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimeMeasure.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_TIME_MEASURE_H
+#define INCLUDED_TIME_MEASURE_H 1
+
+#pragma once
+
+#include "BaseMeasure.h"
+#include "ITickTock.h"
+
+class CTimelineTimelineLayout;
+class CSnapper;
+
+class CTimeMeasure : public CBaseMeasure
+{
+public:
+ CTimeMeasure(CTimelineTimelineLayout *inLayout, double inTimeRatio,
+ bool inFillBackground = true);
+ virtual ~CTimeMeasure();
+
+ void SetTimeRatio(double inTimeRatio);
+ void SetTimeOffset(long inTimeOffset);
+
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseRUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+ void PopulateSnappingList(CSnapper *inSnapper);
+
+ virtual void OnTimer();
+ void OnLoseFocus() override;
+
+protected:
+ // CBaseMeasure
+ void DrawMeasureText(CRenderer *inRenderer, long inPosition, long inMeasure) override;
+ long CalculatePos(double inNewValue) override;
+
+ Q3DStudio::CString FormatTime(long inTime);
+
+ long m_ScrollDir;
+ double m_TimePerPixel;
+ bool m_IsMouseDown;
+ CTimelineTimelineLayout *m_TimelineLayout;
+ std::shared_ptr<UICDM::ISignalConnection> m_TimerConnection;
+};
+#endif // INCLUDED_TIME_MEASURE_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeToolbar.cpp b/src/Authoring/Studio/Palettes/Timeline/TimeToolbar.cpp
new file mode 100644
index 00000000..639e61d2
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimeToolbar.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+
+#include "TimeToolbar.h"
+#include "Renderer.h"
+#include "StudioPreferences.h"
+#include "BlankControl.h"
+#include "IDoc.h"
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CTimeToolbar::CTimeToolbar(IDoc *inDoc)
+{
+ m_Doc = inDoc;
+ m_TimeEdit = new CTimeEdit(inDoc);
+ m_Color = CStudioPreferences::GetBaseColor();
+ m_TimeEdit->SetBackgroundColor(m_Color);
+ AddChild(m_TimeEdit);
+
+ m_TimeEdit->AddTimeChangeListener(this);
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CTimeToolbar::~CTimeToolbar()
+{
+ delete m_TimeEdit;
+}
+
+//=============================================================================
+/**
+ * Fills in the background color for this layout.
+ */
+void CTimeToolbar::Draw(CRenderer *inRenderer)
+{
+ // Fill in the background color and draw the child controls
+
+ // Draw the shadow lines at the top and bottom of the layout
+ CRct theRect(GetSize());
+ inRenderer->FillSolidRect(theRect, m_Color);
+
+ inRenderer->PushPen(CStudioPreferences::GetButtonShadowColor());
+ inRenderer->MoveTo(CPt(0, 0));
+ inRenderer->LineTo(CPt(theRect.size.x, 0));
+ inRenderer->MoveTo(CPt(0, 0));
+ inRenderer->LineTo(CPt(0, theRect.size.y - 2));
+ inRenderer->MoveTo(CPt(0, theRect.size.y - 2));
+ inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 2));
+ inRenderer->PopPen();
+ inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor());
+ inRenderer->MoveTo(CPt(0, theRect.size.y - 1));
+ inRenderer->LineTo(CPt(theRect.size.x, theRect.size.y - 1));
+ inRenderer->PopPen();
+}
+
+//=============================================================================
+/**
+ * Override of Control's set size to reposition the TimeEdit.
+ * @param inSize the new size.
+ */
+void CTimeToolbar::SetSize(CPt inSize)
+{
+ m_TimeEdit->SetSize(CPt(m_TimeEdit->GetWidth(), inSize.y - 4));
+ m_TimeEdit->SetPosition(inSize.x - m_TimeEdit->GetWidth(), 2);
+
+ CControl::SetSize(inSize);
+}
+
+//=============================================================================
+/**
+ * Call from the TimelineView (or thereabouts) that the scene time changed.
+ * @param inTime the new time.
+ */
+void CTimeToolbar::SetTime(long inTime)
+{
+ m_TimeEdit->SetTime(inTime);
+}
+//=============================================================================
+/**
+ * Returns the playhead time
+ */
+long CTimeToolbar::GetTime()
+{
+ return m_TimeEdit->GetTime();
+}
+
+//=============================================================================
+/**
+ * Callback from the TimeEdit that it's time was manually changed.
+ * @param inNewTime the new time.
+ */
+void CTimeToolbar::OnTimeChanged(long inNewTime)
+{
+ m_Doc->NotifyTimeChanged(inNewTime);
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeToolbar.h b/src/Authoring/Studio/Palettes/Timeline/TimeToolbar.h
new file mode 100644
index 00000000..c1ed948d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimeToolbar.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+
+#ifndef INCLUDED_TIME_TOOLBAR_H
+#define INCLUDED_TIME_TOOLBAR_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+
+#include "TimeEdit.h"
+#include "Control.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CRenderer;
+class IDoc;
+
+//=============================================================================
+/**
+ * Control at the top of the time display and a header for the toggle column.
+ */
+class CTimeToolbar : public CControl, public CTimeEditChangeListener
+{
+public:
+ CTimeToolbar(IDoc *inDoc);
+ virtual ~CTimeToolbar();
+ void Draw(CRenderer *inRenderer) override;
+
+ void SetSize(CPt inSize) override;
+ void SetTime(long inTime);
+ virtual long GetTime();
+
+ void OnTimeChanged(long inNewTime) override;
+
+protected:
+ CTimeEdit *m_TimeEdit;
+ IDoc *m_Doc;
+ CColor m_Color;
+};
+
+#endif // INCLUDED_TIME_TOOLBAR_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimebarControl.cpp b/src/Authoring/Studio/Palettes/Timeline/TimebarControl.cpp
new file mode 100644
index 00000000..af0084aa
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimebarControl.cpp
@@ -0,0 +1,690 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "TimebarControl.h"
+#include "StateTimebarRow.h"
+#include "StateRow.h"
+#include "Renderer.h"
+#include "ColorControl.h"
+#include "StudioPreferences.h"
+#include "Views.h"
+#include "TimelineControl.h"
+#include "TimelineTimelineLayout.h"
+#include "ResourceCache.h"
+#include "HotKeys.h"
+#include "Preferences.h"
+#include "Bindings/ITimelineItemBinding.h"
+#include "Bindings/ITimelineTimebar.h"
+#include "StudioApp.h"
+#include "Core.h"
+#include "Doc.h"
+#include "CoreUtils.h"
+#include "StudioUtils.h"
+#include "MasterP.h"
+
+const float SCALING_FACTOR = 0.50;
+
+//=============================================================================
+/**
+ * Create a timebar control on the specified state timebar row.
+ * Attaches a new ToolTip to it that displays the time range this timebar control
+ * encompasses.
+ * @param inRow the row on which this timebar is attached.
+ */
+CTimebarControl::CTimebarControl(CStateTimebarRow *inRow,
+ ITimelineItemBinding *inTimelineItemBinding)
+ : m_IsSelected(false)
+ , m_IsMouseDown(false)
+ , m_MaybeDragStart(false)
+ , m_LeftLeftTip(this, true)
+ , m_LeftTip(this, true)
+ , m_RightTip(this, false)
+ , m_RightRightTip(this, false)
+ , m_SnappingListProvider(nullptr)
+{
+ m_TimebarRow = inRow;
+ m_TimelineItemBinding = inTimelineItemBinding;
+ // Start/End times
+ ITimelineTimebar *theTimelineTimebar = GetTimebar();
+ m_StartTime = theTimelineTimebar->GetStartTime();
+ m_EndTime = theTimelineTimebar->GetEndTime();
+ bool theShowHandleBars = theTimelineTimebar->ShowHandleBars();
+ m_LeftLeftTip.ShowHandles(theShowHandleBars);
+ m_RightRightTip.ShowHandles(theShowHandleBars);
+
+ m_LeftLeftTip.SetSize(CStudioPreferences::GetTimebarTipSize(),
+ CStudioPreferences::GetRowSize());
+ m_LeftTip.SetPosition(CPt(0, 0));
+ m_LeftTip.SetSize(CStudioPreferences::GetTimebarInnerTipSize(),
+ CStudioPreferences::GetRowSize());
+ m_LeftTip.SetPosition(CPt(m_LeftLeftTip.GetSize().x, 0));
+
+ m_RightTip.SetSize(CStudioPreferences::GetTimebarInnerTipSize(),
+ CStudioPreferences::GetRowSize());
+ m_RightRightTip.SetSize(CStudioPreferences::GetTimebarTipSize(),
+ CStudioPreferences::GetRowSize());
+
+ m_EditControl = new CCommentEdit(theTimelineTimebar);
+ m_EditControl->SetPosition(CStudioPreferences::GetTimebarTipSize() * 2, 1);
+ m_EditControl->SetSize(CPt(100, 15));
+ m_EditControl->SetFillBackground(false);
+ AddChild(m_EditControl);
+ AddChild(&m_LeftTip);
+ AddChild(&m_RightTip);
+ AddChild(&m_RightRightTip);
+ AddChild(&m_LeftLeftTip);
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CTimebarControl::~CTimebarControl()
+{
+ delete m_EditControl;
+}
+
+//=============================================================================
+/**
+ * Draw this timebar control to the renderer.
+ * @param inRenderer the renderer to draw to.
+ */
+void CTimebarControl::Draw(CRenderer *inRenderer)
+{
+ CStateRow *theRow = m_TimebarRow->GetStateRow();
+ CRct theRect(GetSize());
+
+ ::CColor theNormalColor = GetTimebar()->GetTimebarColor();
+ ::CColor theSelectedColor = CColorControl::CalculateSelectedColor(theNormalColor);
+
+ ::CColor theBorderColor = CStudioPreferences::GetTimeBarBorderColor();
+ ::CColor theDarkExtendedColor = CStudioPreferences::GetExtendedObjectDarkColor();
+ ::CColor theLightExtendedColor = CStudioPreferences::GetExtendedObjectLightColor();
+
+ long theTipOffset = CStudioPreferences::GetTimebarTipSize();
+
+ if (!IsEnabled()) {
+ theNormalColor = CStudioPreferences::GetLockedTimebarColor();
+ theBorderColor = CStudioPreferences::GetLockedBorderColor();
+ theDarkExtendedColor = CStudioPreferences::GetExtendedLockedDarkColor();
+ theLightExtendedColor = CStudioPreferences::GetExtendedLockedLightColor();
+ }
+
+ // Calculate the start/end/activestart
+ long theObjectLifeStart = ::TimeToPos(m_StartTime, m_TimeRatio);
+ long theStartPos = ::TimeToPos(theRow->GetActiveStart(), m_TimeRatio) - theObjectLifeStart;
+ long theEndPos = ::TimeToPos(theRow->GetActiveEnd(), m_TimeRatio) - theObjectLifeStart;
+ long theObjectLifeEnd = ::TimeToPos(m_EndTime, m_TimeRatio) - theObjectLifeStart;
+
+ CRct theGradientRct(theStartPos + theTipOffset, 0, theEndPos - theStartPos, theRect.size.y - 1);
+
+ if (theEndPos > theStartPos) {
+ inRenderer->DrawGradientBitmap(theGradientRct, theNormalColor, 0, SCALING_FACTOR);
+ // Calculate the gradient rect a bit differently depending on selection
+ if (m_IsSelected) {
+ CRct theSelectedRct(CPt(theGradientRct.position.x, theGradientRct.position.y + 3),
+ CPt(theGradientRct.size.x, theGradientRct.size.y - 7));
+ inRenderer->FillSolidRect(theSelectedRct, theSelectedColor);
+ }
+ }
+
+ inRenderer->PushPen(theBorderColor);
+ // Check to see if we need some hashes at the end
+ if (theObjectLifeEnd > theEndPos) {
+ long theUpdatedStartTime = theEndPos;
+ if (theStartPos > theUpdatedStartTime)
+ theUpdatedStartTime = theStartPos;
+ else {
+ inRenderer->MoveTo(theEndPos + theTipOffset, 0);
+ inRenderer->LineTo(theEndPos + theTipOffset, theRect.size.y - 1);
+ }
+ CRct theClippingRect(CPt(theUpdatedStartTime + theTipOffset + 1, 0),
+ CPt(theObjectLifeEnd - theUpdatedStartTime - 1, theRect.size.y - 1));
+ inRenderer->PushClippingRect(theClippingRect);
+
+ // Draw the hashed background
+ DrawHashedBackgroundX(inRenderer, theDarkExtendedColor, theLightExtendedColor,
+ theClippingRect);
+ inRenderer->PopClippingRect();
+ }
+
+ // Check to see if we need some hashes at the beginning
+ if (theStartPos > 0) {
+ long theUpdatedEndTime = theStartPos;
+ if (theObjectLifeEnd < theUpdatedEndTime)
+ theUpdatedEndTime = theObjectLifeEnd;
+ else {
+ inRenderer->MoveTo(theStartPos + theTipOffset, 0);
+ inRenderer->LineTo(theStartPos + theTipOffset, theRect.size.y - 1);
+ }
+ CRct theClippingRect(CPt(theTipOffset, 0), CPt(theUpdatedEndTime, theRect.size.y - 1));
+ inRenderer->PushClippingRect(theClippingRect);
+
+ // Draw the hashed background
+ DrawHashedBackgroundX(inRenderer, theDarkExtendedColor, theLightExtendedColor,
+ theClippingRect);
+ inRenderer->PopClippingRect();
+ }
+
+ // Draw the border stuff
+ inRenderer->MoveTo(CPt(theTipOffset, 0));
+ inRenderer->LineTo(CPt(theTipOffset, theRect.size.y - 1));
+ inRenderer->MoveTo(CPt(theObjectLifeEnd + theTipOffset, 0));
+ inRenderer->LineTo(CPt(theObjectLifeEnd + theTipOffset, theRect.size.y - 1));
+
+ inRenderer->PopPen();
+ // Setting the position with the active time
+ m_EditControl->SetPosition(CStudioPreferences::GetTimebarTipSize() * 2, 1);
+}
+
+//=============================================================================
+/**
+ * Draws a hashed background in a given clipping rect
+ *
+ * @param inStartX the x position to start from
+ * @param inSizeY the y size the you want the lines to range from
+ * @param inEndX one after the last place where lines can be drawn from
+ * @inRenderer the renderer to draw to
+ * @param inFirstColor the first hash color
+ * @param inSecondColor the second hash color
+ * @para inRect the clipping rect
+ */
+void CTimebarControl::DrawHashedBackgroundX(CRenderer *inRenderer, ::CColor inFirstColor,
+ ::CColor inSecondColor, CRct inRect)
+{
+ inRenderer->FillSolidRect(inRect, inFirstColor);
+ if (m_IsSelected) {
+ CRct theSelectedRct(CPt(inRect.position.x, inRect.position.y + 4),
+ CPt(inRect.size.x, inRect.size.y - 8));
+ inRenderer->FillSolidRect(
+ theSelectedRct, CColorControl::CalculateSelectedColor(GetTimebar()->GetTimebarColor()));
+ }
+
+ inRenderer->FillHashed(inRect, inSecondColor);
+}
+
+//=============================================================================
+/**
+ * Set the current time ratio.
+ * The time ratio controls the length of this control and is the ratio of
+ * pixels to milliseconds.
+ * @param inTimeRatio the new time ratio.
+ */
+void CTimebarControl::SetTimeRatio(double inTimeRatio)
+{
+ m_TimeRatio = inTimeRatio;
+
+ Refresh();
+}
+
+//=============================================================================
+/**
+ * Set the size of this control.
+ * @param inSize the new size of this control.
+ */
+void CTimebarControl::SetSize(CPt inSize)
+{
+ CControl::SetSize(CPt(inSize.x, inSize.y));
+
+ CStateRow *theRow = m_TimebarRow->GetStateRow();
+ long theTipSize =
+ CStudioPreferences::GetTimebarTipSize() + CStudioPreferences::GetTimebarInnerTipSize();
+ long theCommentSize = CStudioPreferences::GetDefaultCommentSize();
+ if (inSize.x < theCommentSize)
+ theCommentSize = inSize.x;
+
+ // Recalculate the comment size depending on where the timebar is and how large it is
+ long theDiff = ::dtol((theRow->GetActiveEnd() - theRow->GetActiveStart()) * m_TimeRatio);
+ if (theDiff < theCommentSize) {
+ theCommentSize = theDiff - theTipSize;
+ if (theCommentSize < 0)
+ theCommentSize = 0;
+ }
+
+ m_EditControl->SetSize(CPt(theCommentSize, 15));
+
+ // Set the two right tips depending on where the right side is
+ m_RightTip.SetPosition(CPt(inSize.x - theTipSize, 0));
+ m_RightRightTip.SetPosition(CPt(inSize.x - m_RightRightTip.GetSize().x + 1, 0));
+}
+
+//=============================================================================
+/**
+ * Set whether this control is selected or not.
+ * If this is selected then it will modify how this control looks.
+ * @param inIsSelected true if this control is to be selected.
+ */
+void CTimebarControl::SetSelected(bool inIsSelected)
+{
+ if (inIsSelected != m_IsSelected) {
+ m_IsSelected = inIsSelected;
+ m_EditControl->SetSelected(m_IsSelected);
+ Invalidate();
+ }
+}
+
+void CTimebarControl::RefreshMetaData()
+{
+ m_EditControl->RefreshMetaData();
+}
+
+//=============================================================================
+/**
+ * Request for this control to refresh it's properties.
+ * This checks the size of the asset and adjusts it's size the the asset's
+ * length. Called when the time ratio or properties have changed.
+ * If the time has changed then Refresh( long, long ) must be called with the
+ * new times.
+ */
+void CTimebarControl::Refresh()
+{
+ Refresh(m_StartTime, m_EndTime);
+}
+
+//=============================================================================
+/**
+ * Request for this control to refresh it's properties.
+ * This updates all the properties of this control and resize it as necessary.
+ * Called when the time changes on the asset, the time ratio changes or any
+ * properties that this displays change.
+ * @param inStartTime the asset's start time.
+ * @param inEndTime the asset's end time.
+ */
+void CTimebarControl::Refresh(long inStartTime, long inEndTime)
+{
+ m_StartTime = inStartTime;
+ m_EndTime = inEndTime;
+
+ long thePosition = ::TimeToPos(inStartTime, m_TimeRatio);
+ long theSize = ::dtol((inEndTime - inStartTime) * m_TimeRatio);
+
+ SetPosition(thePosition - CStudioPreferences::GetTimebarTipSize(), GetPosition().y);
+
+ SetSize(CPt(theSize + 2 * CStudioPreferences::GetTimebarTipSize(), GetMinimumSize().y));
+ if (IsInvalidated())
+ m_TimebarRow->Invalidate();
+}
+
+//=============================================================================
+/**
+ * Get the interface to the timebar item in the data model
+ */
+ITimelineTimebar *CTimebarControl::GetTimebar()
+{
+ return m_TimelineItemBinding->GetTimelineItem()->GetTimebar();
+}
+
+//=============================================================================
+/**
+* Updates the ToolTip and moves it to the correct place on screen.
+* @param inPoint the point that the tooltip is supposed to be placed.
+*/
+void CTimebarControl::RefreshToolTip(CPt inPoint)
+{
+ Q3DStudio::CString theCommentText;
+ CStateRow *theRow = m_TimebarRow->GetStateRow();
+
+ CRct theTimelineBounds(GetTopControlBounds());
+ // format label as: startTime - endTime (timeDifference)
+ theCommentText = " " + FormatTimeString(theRow->GetStartTime()) + " - "
+ + FormatTimeString(theRow->GetEndTime()) + " ("
+ + FormatTimeString(theRow->GetEndTime() - theRow->GetStartTime()) + ")";
+ inPoint.y = GetPosition().y - GetSize().y;
+ ShowMoveableWindow(inPoint, theCommentText, theTimelineBounds);
+}
+
+//=============================================================================
+/**
+ * OnMouseDoubleClick: Pop up a dialog box for the editing of the timebar start
+ * and end time.
+ */
+bool CTimebarControl::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseDoubleClick(inPoint, inFlags)
+ && !m_TimelineItemBinding->IsLockedEnabled()) {
+ CTimeEditDlg theTimeEditDlg;
+ theTimeEditDlg.ShowDialog(m_StartTime, m_EndTime, g_StudioApp.GetCore()->GetDoc(), TIMEBAR,
+ this);
+ }
+
+ return true;
+}
+
+//=============================================================================
+/**
+ * Allows this timebar control to add any times it wishes to the snapper list
+ * @param inSnapper the Snapper that is handling the snapping functions for this timebar
+ */
+void CTimebarControl::PopulateSnappingList(CSnapper *inSnapper)
+{
+ Q_UNUSED(inSnapper);
+}
+
+//=============================================================================
+/**
+ * Start drag handler, puts this control into drag mode.
+ * @param inPoint the point where the mouse was clicked.
+ * @param inFlags the mouse state.
+ */
+bool CTimebarControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseDown(inPoint, inFlags)) {
+ m_IsMouseDown = true;
+ m_MaybeDragStart = true;
+ m_MouseDownLoc = inPoint;
+
+ OnBeginDrag();
+
+ m_TimebarRow->GetStateRow()->Select(SBaseStateRowSelectionKeyState());
+
+ m_Snapper.Clear();
+ m_Snapper.SetSource(this);
+
+ GetSnappingListProvider().PopulateSnappingList(&m_Snapper);
+ m_Snapper.BeginDrag(inPoint.x);
+
+ if (HasFocus(m_EditControl) && !m_EditControl->HitTest(inPoint)) {
+ m_EditControl->OnLoseFocus();
+ }
+
+ // display the time range tooltip
+ RefreshToolTip(inPoint);
+ }
+ return true;
+}
+
+//=============================================================================
+/**
+ * Puts up the context menu.
+ * @param inPoint the point where the mouse was clicked.
+ * @param inFlags the mouse state.
+ */
+bool CTimebarControl::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseRDown(inPoint, inFlags)) {
+ if (m_IsMouseDown) {
+ m_IsMouseDown = false;
+ CommitTimeChange();
+ HideMoveableWindow();
+ }
+ // only right-clicking ON the timebar will show the timebar (text and color) properties'
+ // options
+ ShowContextMenu(inPoint, true);
+ }
+
+ return true;
+}
+
+//=============================================================================
+/**
+ * Notification that the drag has finished.
+ * @param inPoint the point where the mouse was let go.
+ * @param inFlags the state of the mouse.
+ */
+void CTimebarControl::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ // try to prevent stuck mousetips on exceptions
+ try {
+ CControl::OnMouseUp(inPoint, inFlags);
+ CommitTimeChange();
+ } catch (...) {
+ }
+ m_IsMouseDown = false;
+ m_MaybeDragStart = false;
+ HideMoveableWindow();
+}
+
+//=============================================================================
+/**
+ * Handler for the mouse move messages.
+ * If the mouse is down then this will drag the control and offset the timebar.
+ * @param inPoint the current location of the mouse.
+ * @param inFlags the state of the mouse.
+ */
+void CTimebarControl::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseMove(inPoint, inFlags);
+
+ bool theCommentEditMode = m_EditControl->GetEditMode();
+
+ // If we are in edit Comment mode or locked, then we do not drag the timebar.
+ if (!theCommentEditMode && m_IsMouseDown && !m_TimelineItemBinding->IsLockedEnabled()) {
+ UICPROFILE(OnMouseMove);
+
+ if (m_MaybeDragStart) {
+ // Dragging in the first 5 pixels will be ignored to avoid unconsciously accidental
+ // moves
+ CPt theDragDistance = inPoint - m_MouseDownLoc;
+ if (theDragDistance.x * theDragDistance.x + theDragDistance.y * theDragDistance.y <= 25)
+ return;
+
+ m_MaybeDragStart = false;
+ }
+
+ long theNewTime = m_Snapper.ProcessDrag(m_StartTime, inPoint.x, inFlags);
+ if (theNewTime < 0)
+ theNewTime = 0;
+ long theDiffTime = theNewTime - m_StartTime;
+
+ if (theDiffTime) {
+ GetTimebar()->OffsetTime(theDiffTime);
+ // display the time range tooltip
+ RefreshToolTip(inPoint);
+ }
+ }
+}
+
+//=============================================================================
+/**
+ * Call from the left TimebarTab to resize the control.
+ * @param inTime the time to set the start time to.
+ */
+void CTimebarControl::ResizeTimebarLeftTo(long inTime)
+{
+ // TOOD: sk - Figure out what this does
+ // if ( inTime != 0 )
+ {
+ // The whole idea is to not do anything additional once times passes 0 (negatively)
+ // unless it is valid that time is negative on the timebar
+ if (inTime < 0 && m_StartTime > 0)
+ inTime = -m_StartTime; // so that it decrements to 0
+
+ if (m_StartTime > 0 || (m_StartTime == 0 && inTime > 0))
+ GetTimebar()->ChangeTime(inTime, true);
+ }
+}
+
+//=============================================================================
+/**
+ * Call from the right TimebarTab to resize the control.
+ * @param inTime the time to set the start time to.
+ */
+void CTimebarControl::ResizeTimebarRightTo(long inTime)
+{
+ GetTimebar()->ChangeTime(inTime, false);
+}
+
+//=============================================================================
+/**
+ * Sets the Actual string of text
+ * @param inText the text to set the comment text to
+ */
+void CTimebarControl::SetText(const Q3DStudio::CString &inText)
+{
+ m_EditControl->SetData(inText);
+}
+
+//=============================================================================
+/**
+ * Sets the Text Color on the edit control
+ * @param inColor the color
+ */
+void CTimebarControl::SetTextColor(::CColor inColor)
+{
+ m_EditControl->SetTextColor(inColor);
+}
+
+long CTimebarControl::GetStartTime()
+{
+ return m_StartTime;
+}
+
+long CTimebarControl::GetEndTime()
+{
+ return m_EndTime;
+}
+
+//=============================================================================
+/**
+ * Sets whether or not this control is enabled.
+ * If the control is not enabled then it is still drawn and still intercepts
+ * mouse clicks, but it will not actually process them.
+ * @param inIsEnabled true if this control is to be enabled.
+ */
+void CTimebarControl::SetEnabled(bool inIsEnabled)
+{
+ CControl::SetEnabled(inIsEnabled);
+}
+
+//=============================================================================
+/**
+ * COMMENT!!!!!!!!!!!!!!!!!!!!!!
+ */
+void CTimebarControl::OnLoseFocus()
+{
+ if (m_IsMouseDown) {
+ m_IsMouseDown = false;
+ CommitTimeChange();
+ HideMoveableWindow();
+ }
+ CControl::OnLoseFocus();
+}
+
+//=============================================================================
+/**
+ * Setup prior to dragging.
+ */
+void CTimebarControl::OnBeginDrag()
+{
+ GetTimebar()->OnBeginDrag();
+}
+
+void CTimebarControl::ChangeStartTime(long inTime)
+{
+ ResizeTimebarLeftTo(inTime);
+}
+
+void CTimebarControl::ChangeEndTime(long inTime)
+{
+ ResizeTimebarRightTo(inTime);
+}
+
+void CTimebarControl::Commit()
+{
+ GetTimebar()->CommitTimeChange();
+}
+void CTimebarControl::Rollback()
+{
+ GetTimebar()->RollbackTimeChange();
+}
+
+void CTimebarControl::ShowContextMenu(CPt inPoint, bool inShowTimebarPropertiesOptions)
+{
+ CTimebarKeyframeContextMenu theMenu(this, m_TimelineItemBinding->GetKeyframesManager(),
+ inShowTimebarPropertiesOptions);
+ DoPopup(&theMenu, inPoint);
+}
+
+void CTimebarControl::CommitTimeChange()
+{
+ GetTimebar()->CommitTimeChange();
+}
+
+//=============================================================================
+/**
+ * The binding is a keyframes holder
+ */
+ITimelineItemKeyframesHolder *CTimebarControl::GetKeyframesHolder()
+{
+ return m_TimelineItemBinding;
+}
+
+//=============================================================================
+/**
+ * Start editing the timebar comment
+ */
+void CTimebarControl::OnEditTimeComment()
+{
+ GrabFocus(m_EditControl);
+ m_EditControl->DoChangeComment();
+}
+
+//=============================================================================
+/**
+ * Need to invalidate all timebars to redraw
+ */
+void CTimebarControl::OnToggleTimebarHandles()
+{
+ Invalidate();
+}
+
+void CTimebarControl::SetTimebarTime()
+{
+ GetTimebar()->SetTimebarTime(this);
+}
+
+::CColor CTimebarControl::GetTimebarColor()
+{
+ return GetTimebar()->GetTimebarColor();
+}
+
+void CTimebarControl::SetTimebarColor(const ::CColor &inColor)
+{
+ GetTimebar()->SetTimebarColor(inColor);
+}
+
+void CTimebarControl::SetSnappingListProvider(ISnappingListProvider *inProvider)
+{
+ m_SnappingListProvider = inProvider;
+}
+
+ISnappingListProvider &CTimebarControl::GetSnappingListProvider() const
+{
+ // sk - If you hit this, it means the setup order is incorrect. e.g. loading children is done
+ // depth first, ie your child's children is loaded before parent, doesn't work that way.
+ ASSERT(m_SnappingListProvider);
+ return *m_SnappingListProvider;
+}
+
+CRct CTimebarControl::GetTopControlBounds() const
+{
+ return m_TimebarRow->GetStateRow()->GetTopControl()->GetBounds();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimebarControl.h b/src/Authoring/Studio/Palettes/Timeline/TimebarControl.h
new file mode 100644
index 00000000..ec37d134
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimebarControl.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_TIMEBAR_CONTROL_H
+#define INCLUDED_TIMEBAR_CONTROL_H 1
+
+#pragma once
+
+#include "Control.h"
+#include "Snapper.h"
+#include "CommentEdit.h"
+#include "TimebarTip.h"
+#include "TimeEditDlg.h"
+#include "KeyframeContextMenu.h"
+
+class CStateTimebarRow;
+class ITimelineItemBinding;
+class ISnappingListProvider;
+
+//=============================================================================
+/**
+ * Interface to a timebar control
+ */
+class ITimebarControl
+{
+public:
+ virtual ~ITimebarControl() {}
+
+ virtual ITimelineItemKeyframesHolder *GetKeyframesHolder() = 0;
+ virtual void OnEditTimeComment() = 0;
+ virtual void OnToggleTimebarHandles() = 0;
+ virtual void SetTimebarTime() = 0;
+ virtual ::CColor GetTimebarColor() = 0;
+ virtual void SetTimebarColor(const ::CColor &inColor) = 0;
+};
+
+class CTimebarControl : public CControl, public ITimeChangeCallback, public ITimebarControl
+{
+public:
+ CTimebarControl(CStateTimebarRow *inRow, ITimelineItemBinding *inTimelineItemBinding);
+ virtual ~CTimebarControl();
+ void Draw(CRenderer *inRenderer) override;
+ void SetSize(CPt inSize) override;
+ void SetSelected(bool inIsSelected);
+ void SetTimeRatio(double inTimeRatio);
+ void Refresh();
+ void Refresh(long inStartTime, long inEndTime);
+ void RefreshMetaData();
+
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void ResizeTimebarLeftTo(long inTime);
+ void ResizeTimebarRightTo(long inTime);
+ void SetText(const Q3DStudio::CString &inText);
+ void SetTextColor(::CColor inColor = ::CColor(0, 0, 0));
+ void SetEnabled(bool inIsEnabled) override;
+
+ long GetStartTime();
+ long GetEndTime();
+
+ virtual void PopulateSnappingList(CSnapper *inSnapper);
+ void OnLoseFocus() override;
+
+ void OnBeginDrag();
+
+ // ITimeChangeCallback
+ void ChangeStartTime(long) override;
+ void ChangeEndTime(long) override;
+ void Commit() override;
+ void Rollback() override;
+
+ void ShowContextMenu(CPt inPoint, bool inShowTimebarPropertiesOptions);
+ void CommitTimeChange();
+
+ // ITimebarControl
+ ITimelineItemKeyframesHolder *GetKeyframesHolder() override;
+ void OnEditTimeComment() override;
+ void OnToggleTimebarHandles() override;
+ void SetTimebarTime() override;
+ ::CColor GetTimebarColor() override;
+ void SetTimebarColor(const ::CColor &inColor) override;
+
+ void SetSnappingListProvider(ISnappingListProvider *inProvider);
+ ISnappingListProvider &GetSnappingListProvider() const;
+
+ CRct GetTopControlBounds() const;
+
+protected:
+ ITimelineTimebar *GetTimebar();
+
+ void RefreshToolTip(CPt inPoint);
+ void DrawHashedBackgroundX(CRenderer *inRenderer, ::CColor inFirstColor, ::CColor inSecondColor,
+ CRct inRect);
+
+ CStateTimebarRow *m_TimebarRow;
+ bool m_IsSelected;
+ double m_TimeRatio;
+ bool m_IsMouseDown;
+ bool m_MaybeDragStart;
+ CPt m_MouseDownLoc;
+ long m_StartTime;
+ long m_EndTime;
+
+ CTimebarTip m_LeftLeftTip;
+ CTimebarTip m_LeftTip;
+
+ CTimebarTip m_RightTip;
+ CTimebarTip m_RightRightTip;
+ CCommentEdit *m_EditControl;
+ CSnapper m_Snapper;
+
+ ITimelineItemBinding *m_TimelineItemBinding;
+ ISnappingListProvider *m_SnappingListProvider;
+};
+#endif // INCLUDED_TIMEBAR_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimebarTip.cpp b/src/Authoring/Studio/Palettes/Timeline/TimebarTip.cpp
new file mode 100644
index 00000000..9968a838
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimebarTip.cpp
@@ -0,0 +1,235 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "TimebarTip.h"
+#include "TimebarControl.h"
+#include "MouseCursor.h"
+#include "TimelineControl.h"
+#include "ResourceCache.h"
+#include "Renderer.h"
+#include "StudioUtils.h"
+
+#include <QApplication>
+
+//=============================================================================
+/**
+ * Create a timebar tip for the timebar.
+ * This handles displaying the resize cursor and processing the mouse commands.
+ * @param inTimebar the timebar on which this tip is attached.
+ * @param inIsLeft true if this is the left timebar tip.
+ */
+CTimebarTip::CTimebarTip(CTimebarControl *inTimebar, bool inIsLeft, bool inHasHandle /*=false*/)
+ : m_IsMouseDown(false)
+ , m_MaybeDragStart(false)
+ , m_HasHandle(false)
+{
+ m_Timebar = inTimebar;
+ m_IsLeft = inIsLeft;
+
+ ShowHandles(inHasHandle);
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CTimebarTip::~CTimebarTip()
+{
+}
+
+//=============================================================================
+/**
+* Updates the ToolTip and moves it to the correct place on screen.
+* @param inPoint the point that the tooltip is supposed to be placed.
+*/
+void CTimebarTip::RefreshToolTip(CPt inPoint)
+{
+ Q3DStudio::CString theCommentText;
+
+ // format label as: startTime - endTime (timeDifference)
+ theCommentText = " " + FormatTimeString(m_Timebar->GetStartTime()) + " - "
+ + FormatTimeString(m_Timebar->GetEndTime()) + " ("
+ + FormatTimeString(m_Timebar->GetEndTime() - m_Timebar->GetStartTime()) + ")";
+
+ CRct theTimelineBounds(m_Timebar->GetTopControlBounds());
+ inPoint.y = GetPosition().y - GetSize().y;
+ ShowMoveableWindow(inPoint, theCommentText, theTimelineBounds);
+}
+
+//=============================================================================
+/**
+ * Starts the dragging of the timebar tip.
+ * @param inPoint the location of the mouse.
+ * @param inFlags the state of the mouse.
+ */
+bool CTimebarTip::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseDown(inPoint, inFlags);
+
+ m_Timebar->OnBeginDrag();
+
+ m_Snapper.Clear();
+ m_Snapper.SetSource(m_Timebar);
+ m_Timebar->GetSnappingListProvider().PopulateSnappingList(&m_Snapper);
+ m_Snapper.BeginDrag(inPoint.x);
+
+ m_IsMouseDown = true;
+ m_MaybeDragStart = true;
+ m_MouseDownLoc = inPoint;
+
+ setCursorIfNotSet(CMouseCursor::CURSOR_RESIZE_LEFTRIGHT);
+
+ // display the time range tooltip
+ RefreshToolTip(inPoint);
+
+ return true;
+}
+
+//=============================================================================
+/**
+ * Ends the dragging of the tip and commits the commands.
+ * @param inPoint the location of the mouse.
+ * @param inFlags the state of the mouse.
+ */
+void CTimebarTip::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ // try to prevent stuck mousetips on exceptions
+ try {
+ CControl::OnMouseUp(inPoint, inFlags);
+
+ // Commit the current command so it will not be merged with drag commands if this gets
+ // dragged again.
+ m_Timebar->CommitTimeChange();
+ } catch (...) {
+ }
+
+ m_IsMouseDown = false;
+ m_MaybeDragStart = false;
+ HideMoveableWindow();
+ resetCursor();
+}
+
+//=============================================================================
+/**
+ * If the mouse is down then this handles the resizing of the timebar.
+ * @param inPoint the location of the mouse.
+ * @param inFlags the state of the mouse.
+ */
+void CTimebarTip::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseMove(inPoint, inFlags);
+
+ // Don't show the cursor if the mouse is down from someone else.
+ if (!(inFlags & CHotKeys::MOUSE_RBUTTON) && !(inFlags & CHotKeys::MOUSE_LBUTTON))
+ setCursorIfNotSet(CMouseCursor::CURSOR_RESIZE_LEFTRIGHT);
+
+ if (m_IsMouseDown) {
+ if (m_MaybeDragStart) {
+ // Dragging in the first 5 pixels will be ignored to avoid unconsciously accidental
+ // moves
+ CPt theDragDistance = inPoint - m_MouseDownLoc;
+ if (theDragDistance.x * theDragDistance.x + theDragDistance.y * theDragDistance.y <= 25)
+ return;
+
+ m_MaybeDragStart = false;
+ }
+
+ // Figure out which method to call based on which tip we are.
+ if (m_IsLeft) {
+ long theNewTime = m_Snapper.ProcessDrag(m_Timebar->GetStartTime(), inPoint.x, inFlags);
+ m_Timebar->ResizeTimebarLeftTo(theNewTime);
+ } else {
+ long theNewTime = m_Snapper.ProcessDrag(m_Timebar->GetEndTime(), inPoint.x, inFlags);
+ m_Timebar->ResizeTimebarRightTo(theNewTime);
+ }
+
+ // display the time range tooltip
+ RefreshToolTip(inPoint);
+ }
+}
+
+//=============================================================================
+/**
+ * Resets the cursor back to normal.
+ * @param inPoint the location of the mouse.
+ * @param inFlags the state of the mouse/modifier buttons.
+ */
+void CTimebarTip::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOut(inPoint, inFlags);
+
+ resetCursor();
+}
+
+//=============================================================================
+/**
+ * Draws timebar handles if necessary.
+ */
+void CTimebarTip::Draw(CRenderer *inRenderer)
+{
+ if (m_HasHandle) { // to show or not is based on Studio preferences
+ bool theShowHandle =
+ CPreferences::GetUserPreferences("Timeline").GetValue("ShowTimebarHandles", false);
+ if (theShowHandle) {
+ if (IsEnabled())
+ inRenderer->DrawBitmap(CPt(0, 0), m_HandleImage);
+ else
+ inRenderer->DrawBitmap(CPt(0, 0), m_HandleDisabledImage);
+ }
+ }
+}
+
+void CTimebarTip::ShowHandles(bool inShowHandles)
+{
+ m_HasHandle = inShowHandles;
+
+ // If this tip can have a handle
+ if (m_HasHandle) {
+ if (!m_HandleImage) {
+ // If this is a tip on the left side, load the images for the left side
+ const char *theBitMap =
+ (m_IsLeft) ? "timebarhandle-left.png" : "timebarhandle-right.png";
+ m_HandleImage = CResourceCache::GetInstance()->GetBitmap(theBitMap);
+ }
+
+ if (!m_HandleDisabledImage) {
+ const char *theBitMap =
+ (m_IsLeft) ? "timebarhandle-disabled-left.png" : "timebarhandle-disabled-right.png";
+ m_HandleDisabledImage = CResourceCache::GetInstance()->GetBitmap(theBitMap);
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimebarTip.h b/src/Authoring/Studio/Palettes/Timeline/TimebarTip.h
new file mode 100644
index 00000000..4aca03a7
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimebarTip.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_TIMEBAR_TIP
+#define INCLUDED_TIMEBAR_TIP 1
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "Control.h"
+#include "Snapper.h"
+
+#include <QCursor>
+#include <QPixmap>
+//==============================================================================
+// Forwards
+//==============================================================================
+class CTimebarControl;
+class CRenderer;
+
+//==============================================================================
+/**
+ * Class for the tips of timebar controls. Allows the user to resize timebars
+ * by grabbing the tips.
+ */
+class CTimebarTip : public CControl
+{
+public:
+ CTimebarTip(CTimebarControl *inTimebarControl, bool inIsLeft, bool inHasHandle = false);
+ virtual ~CTimebarTip();
+
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void Draw(CRenderer *inRenderer) override;
+
+ void ShowHandles(bool inShowHandles);
+
+protected:
+ void RefreshToolTip(CPt inPoint);
+
+ CTimebarControl *m_Timebar;
+ bool m_IsMouseDown;
+ bool m_MaybeDragStart;
+ CPt m_MouseDownLoc;
+ bool m_IsLeft;
+ bool m_HasHandle;
+ QPixmap m_HandleImage;
+ QPixmap m_HandleDisabledImage;
+ CSnapper m_Snapper;
+};
+
+#endif // INCLUDED_TIMEBAR_TIP
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineControl.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineControl.cpp
new file mode 100644
index 00000000..9e0f4303
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineControl.cpp
@@ -0,0 +1,587 @@
+/****************************************************************************
+**
+** Copyright (C) 1999-2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "TimelineControl.h"
+#include "TimelineSplitter.h"
+#include "StudioApp.h"
+#include "Dispatch.h"
+#include "TimelineTreeLayout.h"
+#include "TimelineTimelineLayout.h"
+#include "SlideRow.h"
+#include "IDoc.h"
+#include "InsertionLine.h"
+#include "InsertionOverlay.h"
+#include "Renderer.h"
+#include "StudioPreferences.h"
+#include "BreadCrumbControl.h"
+#include "BaseTimelineTreeControl.h"
+#include "Bindings/TimelineTranslationManager.h"
+#include "Doc.h"
+#include "Core.h"
+#include "MasterP.h"
+
+// Data model specific
+#include "TimelineDropTarget.h"
+
+#include "ClientDataModelBridge.h"
+#include "UICDMStudioSystem.h"
+#include "UICDMSlides.h"
+
+IMPLEMENT_OBJECT_COUNTER(CTimelineControl)
+
+CTimelineControl::CTimelineControl()
+ : m_SuspendRecalcLayout(false)
+ , m_TranslationManager(nullptr)
+{
+ ADDTO_OBJECT_COUNTER(CTimelineControl)
+
+ m_TranslationManager = new CTimelineTranslationManager();
+
+ m_Splitter = new CTimelineSplitter();
+ AddChild(m_Splitter);
+
+ CDoc *theDoc = g_StudioApp.GetCore()->GetDoc();
+ m_TreeLayout = new CTimelineTreeLayout(this, theDoc);
+ m_Splitter->AddChild(m_TreeLayout);
+
+ m_TimelineLayout = new CTimelineTimelineLayout(this, theDoc);
+ m_Splitter->AddChild(m_TimelineLayout);
+
+ m_Splitter->SetSplitDirection(CSplitter::SPLIT_VERTICAL);
+ m_Splitter->SetSplitLocation(CStudioPreferences::GetTimelineSplitterLocation());
+
+ CDispatch *theDispatch = g_StudioApp.GetCore()->GetDispatch();
+ theDispatch->AddPresentationChangeListener(this);
+ theDispatch->AddClientPlayChangeListener(this);
+
+ // Insertion line
+ m_InsertionLine = new CInsertionLine();
+ m_InsertionLine->SetName("TimelineInsertionLine");
+ AddChild(m_InsertionLine);
+
+ // Insertion overlay marker
+ m_InsertionOverlay = new CInsertionOverlay();
+ m_InsertionOverlay->SetName("TimelineInsertionOverlay");
+ AddChild(m_InsertionOverlay);
+
+ m_Splitter->SetPosition(CPt(0, CStudioPreferences::GetHeaderHeight()));
+
+ m_BreadCrumbToolbar = new CBreadCrumbControl();
+ AddChild(m_BreadCrumbToolbar);
+
+ SetPreferredSize(CPt(400, 200));
+}
+
+CTimelineControl::~CTimelineControl()
+{
+ CDispatch *theDispatch = g_StudioApp.GetCore()->GetDispatch();
+ theDispatch->RemovePresentationChangeListener(this);
+ theDispatch->RemoveClientPlayChangeListener(this);
+
+ delete m_InsertionOverlay;
+ delete m_InsertionLine;
+ delete m_TimelineLayout;
+ delete m_TreeLayout;
+ delete m_Splitter;
+ delete m_BreadCrumbToolbar;
+
+ REMOVEFROM_OBJECT_COUNTER(CTimelineControl)
+}
+
+//=============================================================================
+/**
+ * Returns the playhead time
+ */
+long CTimelineControl::GetTime()
+{
+ return m_TreeLayout->GetTime();
+}
+
+//=============================================================================
+/**
+ * Clear the contents of this view.
+ * This will empty out this view and leave it ready for inspecting other objects.
+ */
+void CTimelineControl::ClearView()
+{
+ m_TimelineLayout->ClearRows();
+ m_TreeLayout->ClearRows();
+ m_ActiveSlide = 0;
+
+ // clean out all previous translations, because the bindings are not guaranteed to be valid when
+ // switching from one slide to another.
+ m_TranslationManager->Clear();
+}
+
+//=============================================================================
+/**
+ * Populates this view with the provided state.
+ * This will set the state as being the root object on this view. ClearView
+ * should be called before this is called.
+ * The object will become the root object of this and will become the active
+ * root of the doc.
+ * @param inState the state to be viewed as the root asset.
+ */
+void CTimelineControl::ViewSlide(UICDM::CUICDMSlideHandle inSlide)
+{
+ m_ActiveSlide = inSlide;
+
+ UICDM::ISlideSystem *theSlideSystem = GetDoc()->GetStudioSystem()->GetSlideSystem();
+ UICDM::CUICDMInstanceHandle theSlideInstance = theSlideSystem->GetSlideInstance(inSlide);
+ CSlideRow *theSlideRow = new CSlideRow(m_TranslationManager->GetOrCreate(theSlideInstance));
+ theSlideRow->SetTimelineControl(this);
+
+ m_TreeLayout->AddRow(theSlideRow);
+ m_TimelineLayout->AddRow(theSlideRow);
+
+ // Since this would be loading the entire context's assets, fire the OnTimelineLayoutChange
+ // event just once.
+ SuspendLayoutChanges(true);
+ try {
+ theSlideRow->LoadChildren();
+ theSlideRow->Expand();
+ } catch (...) { // restore the 'states' before passing the exception up
+ SuspendLayoutChanges(false);
+ throw;
+ }
+ // Update breadcrumbs
+ m_BreadCrumbToolbar->RefreshTrail(m_TranslationManager->GetBreadCrumbProvider());
+
+ SuspendLayoutChanges(false);
+ OnLayoutChanged();
+}
+
+//=============================================================================
+/**
+ * Notification from the StudioFullSystem signal provider that a we have a new active slide.
+ * This will populate this view with the new context.
+ */
+void CTimelineControl::OnActiveSlide(UICDM::CUICDMSlideHandle inSlide)
+{
+ ClearView();
+ ViewSlide(inSlide);
+
+ double theStoredRatio = m_TimelineLayout->GetTimelineRatio(inSlide);
+ if (theStoredRatio != -1)
+ m_TimelineLayout->SetTimeRatio(theStoredRatio);
+ else
+ m_TimelineLayout->OnScalingReset();
+
+ m_TimelineLayout->RecalcLayout();
+}
+
+void CTimelineControl::OnNewPresentation()
+{
+ m_TranslationManager->OnNewPresentation();
+
+ // Register callback
+ UICDM::IStudioFullSystemSignalProvider *theSignalProvider =
+ GetDoc()->GetStudioSystem()->GetFullSystemSignalProvider();
+ m_Connections.push_back(theSignalProvider->ConnectActiveSlide(
+ std::bind(&CTimelineControl::OnActiveSlide, this, std::placeholders::_3)));
+ m_Connections.push_back(theSignalProvider->ConnectSlideDeleted(
+ std::bind(&CTimelineControl::OnDeleteSlide, this, std::placeholders::_1)));
+ CDispatch *theDispatch = g_StudioApp.GetCore()->GetDispatch();
+ m_Connections.push_back(theDispatch->ConnectSelectionChange(
+ std::bind(&CTimelineControl::OnSelectionChange, this, std::placeholders::_1)));
+}
+
+//=============================================================================
+/**
+ * Notification from the dispatch that the presentation is being closed.
+ * This will clear all the objects from this presentation.
+ */
+void CTimelineControl::OnClosingPresentation()
+{
+ ClearView();
+ m_TimelineLayout->ClearAllTimeRatios();
+ m_BreadCrumbToolbar->RefreshTrail(nullptr);
+
+ m_Connections.clear();
+}
+
+//=============================================================================
+/**
+ * Accessor for the root object being displayed in this view.
+ */
+UICDM::CUICDMSlideHandle CTimelineControl::GetActiveSlide()
+{
+ return m_ActiveSlide;
+}
+
+//=============================================================================
+/**
+ * Gets the timeline layout which is the portion of the timeline to the right
+ * of the splitter. The timeline layout contains the timebars.
+ */
+CTimelineTimelineLayout *CTimelineControl::GetTimelineLayout()
+{
+ return m_TimelineLayout;
+}
+
+//=============================================================================
+/**
+ * Gets the tree layout which is the portion of the timeline to the left
+ * of the splitter. The tree layout contains the tree controls for expanding
+ * rows in the timeline.
+ */
+CTimelineTreeLayout *CTimelineControl::GetTreeLayout()
+{
+ return m_TreeLayout;
+}
+
+//=============================================================================
+/**
+ * Notification from the dispatch that the presentation is going into play mode.
+ */
+void CTimelineControl::OnPlayStart()
+{
+}
+
+//=============================================================================
+/**
+ * Notification from the dispatch that the presentation is exiting play state.
+ */
+void CTimelineControl::OnPlayStop()
+{
+}
+
+//=============================================================================
+/**
+ * Notification from the dispatch that the time has changed.
+ * This is used to update the playhead location and view time.
+ * @param inNewTime the new time that this should display.
+ */
+void CTimelineControl::OnTimeChanged(long inNewTime)
+{
+ SetTime(inNewTime);
+}
+
+//==============================================================================
+// CSelectionChangeListener
+//==============================================================================
+void CTimelineControl::OnSelectionChange(Q3DStudio::SSelectedValue inNewSelectable)
+{
+ // testing for nullptr selection OR if the selected is not displayed in the timeline
+ bool theLoseFocus = !inNewSelectable.empty();
+ if (!theLoseFocus) {
+ Q3DStudio::SelectedValueTypes::Enum theSelectionType = inNewSelectable.getType();
+ // for now, its just UICDM objects
+ theLoseFocus = theSelectionType != Q3DStudio::SelectedValueTypes::Instance; // UICDM objects
+ }
+ if (theLoseFocus)
+ m_TreeLayout->OnLoseFocus();
+
+ GetTranslationManager()->OnSelectionChange(inNewSelectable);
+
+ // The drag&drop doesn't have any sort of callback after a drop
+ // so for now, this acts as a "event-trigger" after a drop ( because new items are always
+ // selcted after a drop )
+ HideInsertionMarkers();
+}
+
+//=============================================================================
+/**
+ * Callback when individual rows has affected the layout, such that the treelayout needs to be
+ * synchronized with the timelinelayout or vice versa.
+ */
+void CTimelineControl::OnLayoutChanged()
+{
+ if (m_SuspendRecalcLayout) // optimization where this is explicitly shutoff.
+ return;
+
+ m_TreeLayout->RecalcLayout();
+ m_TimelineLayout->OnTimelineLayoutChanged();
+}
+
+//=============================================================================
+/**
+ * typically for displaying tooltip
+ */
+CRct CTimelineControl::GetBounds() const
+{
+ return CRct(GetGlobalPosition(CPt(0, 0)), GetSize());
+}
+
+void CTimelineControl::HideTimelineMoveableTooltip()
+{
+ HideMoveableWindow();
+}
+
+//=============================================================================
+/**
+ * For snapping timebars/keyframes
+ */
+ISnappingListProvider *CTimelineControl::GetSnappingListProvider() const
+{
+ return m_TimelineLayout;
+}
+
+//=============================================================================
+/**
+ * Sets the current time as seen in this palette.
+ * This will update the Playhead time and the time view time.
+ * @param inNewTime the time to set on this.
+ */
+void CTimelineControl::SetTime(long inNewTime)
+{
+ m_TimelineLayout->SetTime(inNewTime);
+ m_TreeLayout->SetTime(inNewTime);
+}
+
+void CTimelineControl::HideInsertionMarkers()
+{
+ bool theInvalidate = false;
+ if (m_InsertionOverlay->IsVisible()) {
+ m_InsertionOverlay->SetVisible(false);
+ theInvalidate = true;
+ }
+ if (m_InsertionLine->IsVisible()) {
+ m_InsertionLine->SetVisible(false);
+ theInvalidate = true;
+ }
+ if (theInvalidate) {
+ m_TreeLayout->Invalidate();
+ Invalidate();
+ }
+}
+
+void CTimelineControl::SetSize(CPt inSize)
+{
+ CControl::SetSize(inSize);
+
+ m_Splitter->SetSize(CPt(inSize.x, inSize.y));
+}
+
+//=============================================================================
+/**
+ * Scrolls both sides of the timeline along the y-axis so that they stay synced.
+ * @param inSource Scroller that generated the scroll messsage
+ * @param inPositionY New vertical scroll bar position
+ */
+void CTimelineControl::SetScrollPositionY(CScroller *inSource, long inPositionY)
+{
+ m_TreeLayout->SetScrollPositionY(inSource, inPositionY);
+ m_TimelineLayout->SetScrollPositionY(inSource, inPositionY);
+}
+
+//=============================================================================
+/**
+ * Override OnDraw to provide Timeline only draw profiling stats.
+ */
+void CTimelineControl::OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation)
+{
+ UICPROFILE(OnDraw);
+ CControl::OnDraw(inRenderer, inDirtyRect, inIgnoreValidation);
+}
+
+//=============================================================================
+/**
+ * Fills the whole control with the base (gray) color, then other controls will
+ * draw on top of that.
+ * @param inRenderer renderer to draw to
+ */
+void CTimelineControl::Draw(CRenderer *inRenderer)
+{
+ const auto size = GetSize();
+ inRenderer->FillSolidRect(QRect(0, 0, size.x, size.y), CStudioPreferences::GetBaseColor());
+}
+
+//=============================================================================
+/**
+ * Overriden from CControl. We want to propagate keydown (specifically F2)
+ * messages to the selected row regardless if the control has focus or not.
+ */
+void CTimelineControl::OnGainFocus()
+{
+ CControl::OnGainFocus();
+
+ CBaseStateRow *theRow = m_TranslationManager->GetSelectedRow();
+ if (theRow)
+ theRow->SetFocus();
+}
+
+//=============================================================================
+/**
+ * Overridden to draw insertion lines
+ */
+CDropTarget *CTimelineControl::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags)
+{
+ CDropTarget *theDropTarget = CControl::FindDropCandidate(inMousePoint, inFlags);
+
+ bool theHideInsertionMarkers = true;
+ CTimeLineDropTarget *theTimelineDropTarget = nullptr;
+ if (theDropTarget
+ && (theTimelineDropTarget = dynamic_cast<CTimeLineDropTarget *>(theDropTarget))) {
+ CControl *theInsertionOverControl = theTimelineDropTarget->GetInsertionMarkerRow();
+ if (theInsertionOverControl) {
+ CRct theTreeRect = GetVisibleTreeLayoutArea();
+ EDROPDESTINATION theDropDest = theTimelineDropTarget->GetDestination();
+ switch (theDropDest) {
+ case EDROPDESTINATION_ABOVE:
+ case EDROPDESTINATION_BELOW: {
+ // the insertion line starts from the indent to the end of the row
+ long theIndent = theTimelineDropTarget->GetInsertionMarkerIndent();
+ if (theDropDest == EDROPDESTINATION_ABOVE)
+ m_InsertionLine->SetPosition(theInsertionOverControl->GetGlobalPosition(
+ CPt(theIndent, -GetPosition().y)));
+ else
+ m_InsertionLine->SetPosition(theInsertionOverControl->GetGlobalPosition(CPt(
+ theIndent, theInsertionOverControl->GetSize().y - 1 - GetPosition().y)));
+
+ long theWidth =
+ theTreeRect.size.x + theTreeRect.position.x - m_InsertionLine->GetPosition().x;
+ m_InsertionLine->SetLineWidth(theWidth);
+ m_InsertionLine->SetVisible(true);
+ m_InsertionOverlay->SetVisible(false);
+ } break;
+ case EDROPDESTINATION_ON: {
+ // insertion overlay spans the width of the row
+ m_InsertionOverlay->SetPosition(theInsertionOverControl->GetGlobalPosition(
+ CPt(theTreeRect.position.x, -GetPosition().y)));
+
+ long theWidth = theTreeRect.size.x + theTreeRect.position.x
+ - m_InsertionOverlay->GetPosition().x;
+ m_InsertionOverlay->SetWidth(theWidth);
+ m_InsertionOverlay->SetVisible(true);
+ m_InsertionLine->SetVisible(false);
+ } break;
+ }
+ theHideInsertionMarkers = false;
+ }
+ }
+ // not drawn
+ if (theHideInsertionMarkers)
+ HideInsertionMarkers();
+
+ return theDropTarget;
+}
+
+void CTimelineControl::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseOut(inPoint, inFlags);
+ HideInsertionMarkers();
+}
+
+void CTimelineControl::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseUp(inPoint, inFlags);
+ HideInsertionMarkers();
+}
+
+//=============================================================================
+/**
+ * Gets the insertion line for the timeline. The insertion line should be used
+ * to indicate when you can drag-and-drop and item between two other items.
+ * Call SetVisible on this control to show/hide it.
+ * @return the insertion line control
+ */
+CInsertionLine *CTimelineControl::GetInsertionLine()
+{
+ return m_InsertionLine;
+}
+
+//=============================================================================
+/**
+ * Gets the insertion overlay marker for the timeline. This control should be
+ * used to indicate that you can drag-and-drop and object onto another item in
+ * the timeline. Call SetVisible on this control to show/hide it.
+ * @return the insertion overlay marker for the timeline
+ */
+CInsertionOverlay *CTimelineControl::GetInsertionOverlay()
+{
+ return m_InsertionOverlay;
+}
+
+//=============================================================================
+/**
+ * Fetches the bounding rect for the CTimelineTreeLayout section of the
+ * timeline. This is the section that contains toggles and text names of items
+ * in the timeline. The actual tree layout might be bigger than this rect
+ * specifies. This is because portions of the tree layout might be overlapped
+ * by other controls.
+ * @return rectangle describing visible area of the tree control
+ */
+CRct CTimelineControl::GetVisibleTreeLayoutArea()
+{
+ return m_TreeLayout->GetVisibleArea();
+}
+
+void CTimelineControl::RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler)
+{
+ m_TimelineLayout->RegisterGlobalKeyboardShortcuts(inShortcutHandler);
+}
+
+//=============================================================================
+/**
+ * event that takes place just before a save or export, on lose focus will commit changes
+ * in text boxes
+ */
+void CTimelineControl::OnSavingPresentation(const CUICFile *inNewPresentationFile)
+{
+ Q_UNUSED(inNewPresentationFile);
+ OnLoseFocus();
+}
+
+//=============================================================================
+/**
+ * Notification from the StudioFullSystem signal provider that a slide has been deleted.
+ */
+void CTimelineControl::OnDeleteSlide(UICDM::CUICDMSlideHandle inSlide)
+{
+ m_TimelineLayout->DeleteTimelineRatio(inSlide);
+}
+
+//==============================================================================
+/**
+ * When caller knows that there are 'batch' changes to the timeline layout,
+ * to prevent unnecessary calls to recalclayout
+ */
+void CTimelineControl::SuspendLayoutChanges(bool inSuspend)
+{
+ m_SuspendRecalcLayout = inSuspend;
+}
+
+CDoc *CTimelineControl::GetDoc()
+{
+ return g_StudioApp.GetCore()->GetDoc();
+}
+
+CClientDataModelBridge *CTimelineControl::GetBridge()
+{
+ return GetDoc()->GetStudioSystem()->GetClientDataModelBridge();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineControl.h b/src/Authoring/Studio/Palettes/Timeline/TimelineControl.h
new file mode 100644
index 00000000..470a10a5
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineControl.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 1999-2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#ifndef INCLUDED_TIMELINE_CONTROL_H
+#define INCLUDED_TIMELINE_CONTROL_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "Control.h"
+#include "DispatchListeners.h"
+#include "TimelineRow.h"
+#include "ITimelineControl.h"
+
+#include "UICDMHandles.h"
+#include "UICDMSignals.h"
+#include "SelectedValueImpl.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CDoc;
+class CDropTarget;
+class CTimelineSplitter;
+class CTimelineTreeLayout;
+class CTimelineTimelineLayout;
+class CScroller;
+class CInsertionLine;
+class CInsertionOverlay;
+class CRenderer;
+class CHotKeys;
+class CBreadCrumbControl;
+class CTimelineTranslationManager;
+class CClientDataModelBridge;
+
+//==============================================================================
+// Classes
+//==============================================================================
+
+class CTimelineControl : public CControl,
+ public CPresentationChangeListener,
+ public CClientPlayChangeListener,
+ public ITimelineControl
+{
+public:
+ CTimelineControl();
+ ~CTimelineControl();
+
+ DEFINE_OBJECT_COUNTER(CTimelineControl)
+
+ // CControl
+ void OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation = false) override;
+ void Draw(CRenderer *inRenderer) override;
+ void OnGainFocus() override;
+ CDropTarget *FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+
+ // Presentation Change Listener
+ void OnNewPresentation() override;
+ void OnClosingPresentation() override;
+ void OnSavingPresentation(const CUICFile *inNewPresentationFile) override;
+
+ // ClientPlayChangeListener
+ void OnPlayStart() override;
+ void OnPlayStop() override;
+ void OnTimeChanged(long inNewTime) override;
+
+ // CSelectionChangeListener,
+ virtual void OnSelectionChange(Q3DStudio::SSelectedValue inNewSelectable);
+
+ // ITimelineControl
+ void OnLayoutChanged() override;
+ CRct GetBounds() const override;
+ void HideTimelineMoveableTooltip() override;
+ ISnappingListProvider *GetSnappingListProvider() const override;
+
+ void ClearView();
+ void ViewSlide(UICDM::CUICDMSlideHandle inSlide);
+ UICDM::CUICDMSlideHandle GetActiveSlide();
+
+ CTimelineTimelineLayout *GetTimelineLayout();
+ CTimelineTreeLayout *GetTreeLayout();
+
+ void SetSize(CPt inSize) override;
+ long GetTime();
+ void SetScrollPositionY(CScroller *inSource, long inPositionY);
+
+ CInsertionLine *GetInsertionLine();
+ CInsertionOverlay *GetInsertionOverlay();
+ CRct GetVisibleTreeLayoutArea();
+
+ void RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler);
+
+ CTimelineTranslationManager *GetTranslationManager() const { return m_TranslationManager; }
+
+protected:
+ void SuspendLayoutChanges(bool inSuspend);
+ void SetTime(long inNewTime);
+
+ void HideInsertionMarkers();
+
+ // UICDM callbacks
+ void OnActiveSlide(UICDM::CUICDMSlideHandle inSlide);
+ void OnDeleteSlide(UICDM::CUICDMSlideHandle inSlide);
+
+ // Helper functions
+ inline CDoc *GetDoc();
+ inline CClientDataModelBridge *GetBridge();
+
+ CTimelineSplitter *m_Splitter;
+ CTimelineTreeLayout *m_TreeLayout;
+ CTimelineTimelineLayout *m_TimelineLayout;
+ UICDM::CUICDMSlideHandle m_ActiveSlide;
+ CInsertionLine
+ *m_InsertionLine; ///< Drag-and-drop insertion line for dropping between timeline items
+ CInsertionOverlay
+ *m_InsertionOverlay; ///< Drag-and-drop insertion marker for dropping on a timeline item
+ CBreadCrumbControl *m_BreadCrumbToolbar;
+ bool m_SuspendRecalcLayout;
+
+ CTimelineTranslationManager *m_TranslationManager;
+
+ std::vector<std::shared_ptr<UICDM::ISignalConnection>>
+ m_Connections; /// connections to the UICDM
+};
+#endif // INCLUDED_TIMELINE_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineFilter.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineFilter.cpp
new file mode 100644
index 00000000..5ef25911
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineFilter.cpp
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "TimelineFilter.h"
+#include "Bindings/ITimelineItemProperty.h"
+#include "Bindings/ITimelineItem.h"
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CFilter::CFilter()
+ : m_ShowBehaviors(true)
+ , m_ShowMaterials(true)
+ , m_ShowProperties(true)
+ , m_ShowShy(true)
+ , m_ShowLocked(true)
+ , m_ShowVisible(true)
+ , m_IsExpanded(true)
+{
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CFilter::~CFilter()
+{
+}
+
+//=============================================================================
+/**
+ * @return true if behaviors should be shown, false if they should be hidden
+ */
+bool CFilter::GetBehaviors() const
+{
+ return m_ShowBehaviors;
+}
+
+//=============================================================================
+/**
+ * @return true if materials should be shown, false if they should be hidden
+ */
+bool CFilter::GetMaterials() const
+{
+ return m_ShowMaterials;
+}
+
+//=============================================================================
+/**
+ * @return true if properties should be shown, false if they should be hidden
+ */
+bool CFilter::GetProperties() const
+{
+ return m_ShowProperties;
+}
+
+//=============================================================================
+/**
+ * @return true if shy objects should still be shown, false if they should be hidden
+ */
+bool CFilter::GetShy() const
+{
+ return m_ShowShy;
+}
+
+//=============================================================================
+/**
+ * @return true if locked objects should still be shown, false if they should be hidden
+ */
+bool CFilter::GetLocked() const
+{
+ return m_ShowLocked;
+}
+
+//=============================================================================
+/**
+ * Sets whether or not to show behaviors on objects.
+ * @param inShow true to show behaviors, false to hide behaviors
+ */
+void CFilter::SetBehaviors(bool inShow /*= true*/)
+{
+ m_ShowBehaviors = inShow;
+}
+
+//=============================================================================
+/**
+ * Sets whether or not to show materials on objects.
+ * @param inShow true to show materials, false to hide materials
+ */
+void CFilter::SetMaterials(bool inShow /*= true*/)
+{
+ m_ShowMaterials = inShow;
+}
+
+//=============================================================================
+/**
+ * Sets whether or not to show properties on objects.
+ * @param inShow true to show properties, false to hide properties
+ */
+void CFilter::SetProperties(bool inShow /*= true*/)
+{
+ m_ShowProperties = inShow;
+}
+
+//=============================================================================
+/**
+ * Sets whether or not to show objects with the shy flag.
+ * @param inShow true to show shy objects, false to hide shy objects
+ */
+void CFilter::SetShy(bool inShow /*= true*/)
+{
+ m_ShowShy = inShow;
+}
+
+//=============================================================================
+/**
+ * Sets whether or not to show objects with the locked flag.
+ * @param inShow true to show locked objects, false to hide locked objects
+ */
+void CFilter::SetLocked(bool inShow /*= true*/)
+{
+ m_ShowLocked = inShow;
+}
+
+//=============================================================================
+/**
+ * Sets whether or not the parent object is expanded.
+ * If the parent is not expanded then nothing should be visible.
+ */
+void CFilter::SetExpanded(bool inIsExpanded /*= true*/)
+{
+ m_IsExpanded = inIsExpanded;
+}
+
+//=============================================================================
+/**
+ * Sets whether or not to show objects that are not visible.
+ * @param inIsVisible true to show non-visible objects, false to hide them.
+ */
+void CFilter::SetVisible(bool inIsVisible /*= true*/)
+{
+ m_ShowVisible = inIsVisible;
+}
+
+//=============================================================================
+/**
+ * Gets whether or not non-visible objects should be displayed.
+ * @return true if non-visible objects should be displayed.
+ */
+bool CFilter::GetVisible() const
+{
+ return m_ShowVisible;
+}
+
+//=============================================================================
+/**
+ * Gets whether or not the parent object is expanded.
+ * If the parent is not expanded then nothing should be visible.
+ */
+bool CFilter::IsExpanded() const
+{
+ return m_IsExpanded;
+}
+
+//=============================================================================
+/**
+ * Checks to see if the specified property should be displayed or not.
+ * @return true if the property should be visible.
+ */
+bool CFilter::Filter(ITimelineItemProperty *inTimelineItemProperty) const
+{
+ Q_UNUSED(inTimelineItemProperty);
+
+ bool theVisibleFlag = GetProperties();
+ theVisibleFlag &= IsExpanded();
+
+ return theVisibleFlag;
+}
+
+//=============================================================================
+/**
+ * Checks to see if the specified state should be displayed or not.
+ * @return true if the state should be visible.
+ */
+bool CFilter::Filter(ITimelineItem *inTimelineItem) const
+{
+ bool theVisibleFlag = true;
+
+ // If this row is shy, we need to check the filter for shy objects
+ if (inTimelineItem->IsShy())
+ theVisibleFlag &= GetShy();
+
+ // If this row is locked, we need to check the filter for locked objects
+ if (inTimelineItem->IsLocked())
+ theVisibleFlag &= GetLocked();
+
+ // This is for hiding visible eye toggle objects
+ if (!inTimelineItem->IsVisible())
+ theVisibleFlag &= GetVisible();
+
+ // If this row is a behavior, we need to check the filter for behaviors
+ if (inTimelineItem->GetObjectType() == OBJTYPE_BEHAVIOR)
+ theVisibleFlag &= GetBehaviors();
+
+ // If this row is a material, we need to check the filter for materials
+ if (inTimelineItem->GetObjectType() == OBJTYPE_MATERIAL)
+ theVisibleFlag &= GetMaterials();
+
+ return theVisibleFlag;
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineFilter.h b/src/Authoring/Studio/Palettes/Timeline/TimelineFilter.h
new file mode 100644
index 00000000..e956b4da
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineFilter.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+
+#ifndef INCLUDED_FILTER_H
+#define INCLUDED_FILTER_H 1
+
+#pragma once
+
+//==============================================================================
+// Forward
+//==============================================================================
+class ITimelineItem;
+class ITimelineItemProperty;
+
+//=============================================================================
+/**
+ * Filter class for determining what objects to show in the timeline.
+ */
+class CFilter
+{
+public:
+ CFilter();
+ virtual ~CFilter();
+
+ bool GetBehaviors() const;
+ bool GetMaterials() const;
+ bool GetProperties() const;
+ bool GetShy() const;
+ bool GetLocked() const;
+ bool GetVisible() const;
+ void SetBehaviors(bool inShow = true);
+ void SetMaterials(bool inShow = true);
+ void SetProperties(bool inShow = true);
+ void SetShy(bool inShow = true);
+ void SetLocked(bool inShow = true);
+ void SetVisible(bool inShow = true);
+
+ void SetExpanded(bool inExpanded = true);
+ bool IsExpanded() const;
+
+ bool Filter(ITimelineItemProperty *inTimelineItemProperty) const;
+ bool Filter(ITimelineItem *inTimelineItem) const;
+
+protected:
+ bool m_ShowBehaviors;
+ bool m_ShowMaterials;
+ bool m_ShowProperties;
+ bool m_ShowShy;
+ bool m_ShowLocked;
+ bool m_ShowVisible;
+ bool m_IsExpanded;
+};
+
+#endif // INCLUDED_FILTER_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.cpp
new file mode 100644
index 00000000..36946432
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "TimelineKeyframe.h"
+#include "Renderer.h"
+
+CTimelineKeyframe::CTimelineKeyframe()
+ : m_Time(0)
+ , m_IsDynamic(false)
+{
+}
+
+CTimelineKeyframe::~CTimelineKeyframe()
+{
+}
+
+void CTimelineKeyframe::SetTime(long inTime)
+{
+ m_Time = inTime;
+}
+
+long CTimelineKeyframe::GetTime()
+{
+ return m_Time;
+}
+
+//=============================================================================
+/**
+ * called when this key is made dynamic
+ * @param inIsDynamic true if the keyframe is dynamic
+ */
+void CTimelineKeyframe::SetDynamic(bool inIsDynamic)
+{
+ if (m_IsDynamic != inIsDynamic) {
+ m_IsDynamic = inIsDynamic;
+ // Invalidate( );
+ }
+}
+
+//=============================================================================
+/**
+ * @return true if dynamic
+ */
+bool CTimelineKeyframe::IsDynamic()
+{
+ return m_IsDynamic;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.h
new file mode 100644
index 00000000..a08f553c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_TIMELINE_KEYFRAME
+#define INCLUDED_TIMELINE_KEYFRAME 1
+
+#pragma once
+class CRenderer;
+
+class CTimelineKeyframe
+{
+public:
+ CTimelineKeyframe();
+ ~CTimelineKeyframe();
+ virtual void Draw(CRenderer *inRenderer) = 0;
+
+ virtual void SetTime(long inTime);
+ virtual long GetTime();
+
+ void SetDynamic(bool inIsDynamic);
+ bool IsDynamic();
+
+ static const long DRAGBUFFER =
+ 3; // Specifies how many pixels a keframe should be dragged before it actually moves
+
+protected:
+ long m_Time;
+ bool m_IsDynamic;
+};
+
+#endif // INCLUDED_TIMELINE_KEYFRAME \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineRow.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineRow.cpp
new file mode 100644
index 00000000..c465575c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineRow.cpp
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "TimelineRow.h"
+#include "StudioPreferences.h"
+#include "StudioObjectTypes.h"
+#include "BaseStateRow.h"
+
+const long CTimelineRow::TREE_INDENT = CStudioPreferences::GetRowSize();
+
+CTimelineRow::CTimelineRow()
+ : m_ParentRow(nullptr)
+ , m_IsViewable(false)
+ , m_Indent(0)
+{
+}
+
+CTimelineRow::~CTimelineRow()
+{
+}
+void CTimelineRow::SetIndent(long inIndent)
+{
+ m_Indent = inIndent;
+}
+
+long CTimelineRow::GetIndent()
+{
+ return m_Indent;
+}
+
+void CTimelineRow::SetParent(CBaseStateRow *inParent)
+{
+ m_ParentRow = inParent;
+}
+
+//=============================================================================
+/**
+ * Gets the Parent Row
+ */
+CBaseStateRow *CTimelineRow::GetParentRow() const
+{
+ return m_ParentRow;
+}
+
+void CTimelineRow::SetTimeRatio(double inTimeRatio)
+{
+ Q_UNUSED(inTimeRatio);
+}
+
+void CTimelineRow::OnChildVisibilityChanged()
+{
+}
+
+bool CTimelineRow::IsViewable() const
+{
+ return m_IsViewable;
+}
+
+void CTimelineRow::PopulateSnappingList(CSnapper *inSnapper)
+{
+ Q_UNUSED(inSnapper);
+}
+
+//=============================================================================
+/**
+ * By default, this will recurse up its parent, for an answer.
+ * If this proves to a performance hit, we can cache a ITimelineControl pointer at EVERY row.
+ */
+ITimelineControl *CTimelineRow::GetTopControl() const
+{
+ ITimelineControl *theControl = (m_ParentRow) ? m_ParentRow->GetTopControl() : nullptr;
+ ASSERT(theControl);
+ return theControl;
+}
+
+//=============================================================================
+/**
+ * Retrieves the background color for the row based upon the type of asset
+ * passed in.
+ * @param inType specifies which asset type you want the color for
+ * @return background color to use for this row
+ */
+::CColor CTimelineRow::GetTimebarBackgroundColor(EStudioObjectType inType)
+{
+ ::CColor theColor;
+
+ switch (inType) {
+ case OBJTYPE_LAYER:
+ theColor = CStudioPreferences::GetLayerBackgroundColor();
+ break;
+
+ case OBJTYPE_GROUP:
+ case OBJTYPE_COMPONENT:
+ theColor = CStudioPreferences::GetGroupBackgroundColor();
+ break;
+
+ default:
+ theColor = CStudioPreferences::GetObjectBackgroundColor();
+ break;
+ }
+
+ return theColor;
+}
+
+//=============================================================================
+/**
+ * Retrieves the background color for the row when the mouse is over the row,
+ * based upon the type of asset passed in.
+ * @param inType specifies which asset type you want the color for
+ * @return background color to use for this row when the mouse is over the row
+ */
+::CColor CTimelineRow::GetTimebarHighlightBackgroundColor(EStudioObjectType inType)
+{
+ ::CColor theColor;
+
+ switch (inType) {
+ case OBJTYPE_LAYER:
+ theColor = CStudioPreferences::GetMouseOverHighlightColor();
+ break;
+
+ case OBJTYPE_GROUP:
+ case OBJTYPE_COMPONENT:
+ theColor = CStudioPreferences::GetMouseOverHighlightColor();
+ break;
+
+ default:
+ theColor = CStudioPreferences::GetMouseOverHighlightColor();
+ break;
+ }
+
+ return theColor;
+}
+
+long CTimelineRow::GetLatestEndTime()
+{
+ return 0;
+}
+
+void CTimelineRow::Dispose()
+{
+ delete this;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineRow.h b/src/Authoring/Studio/Palettes/Timeline/TimelineRow.h
new file mode 100644
index 00000000..c18d438b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineRow.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_TIMELINE_ROW_H
+#define INCLUDED_TIMELINE_ROW_H 1
+
+#pragma once
+
+#include "TimelineFilter.h"
+#include "CColor.h"
+#include "StudioObjectTypes.h"
+
+#include <vector>
+
+class CSnapper;
+class CControl;
+class CBaseStateRow;
+class ISnappingListProvider;
+class ITimelineControl;
+
+class CTimelineRow
+{
+public:
+ static const long TREE_INDENT;
+
+ CTimelineRow();
+ virtual ~CTimelineRow();
+
+ virtual CControl *GetColorControl() = 0;
+ virtual CControl *GetTreeControl() = 0;
+ virtual CControl *GetToggleControl() = 0;
+ virtual CControl *GetTimebarControl() = 0;
+
+ virtual void SetIndent(long inIndent);
+ long GetIndent();
+
+ virtual void Filter(const CFilter &inFilter, bool inFilterChildren = true) = 0;
+
+ void SetParent(CBaseStateRow *inParent);
+ CBaseStateRow *GetParentRow() const;
+ virtual void SetTimeRatio(double inTimeRatio);
+ virtual void OnChildVisibilityChanged();
+ virtual bool IsViewable() const;
+ virtual void PopulateSnappingList(CSnapper *inSnappingList);
+ virtual ISnappingListProvider *GetSnappingListProvider() const = 0;
+ virtual void SetSnappingListProvider(ISnappingListProvider *inProvider) = 0;
+ virtual ITimelineControl *GetTopControl() const;
+
+ virtual ::CColor GetTimebarBackgroundColor(EStudioObjectType inType);
+ virtual ::CColor GetTimebarHighlightBackgroundColor(EStudioObjectType inType);
+
+ virtual long GetLatestEndTime();
+
+ virtual void Dispose();
+
+protected:
+ CBaseStateRow *m_ParentRow;
+ bool m_IsViewable;
+ long m_Indent;
+};
+#endif // INCLUDED_TIMELINE_ROW_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.cpp
new file mode 100644
index 00000000..fe072db6
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//=============================================================================
+// Prefix
+//=============================================================================
+#include "stdafx.h"
+
+//=============================================================================
+// Includes
+//=============================================================================
+#include "TimelineSplitter.h"
+#include "StudioPreferences.h"
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CTimelineSplitter::CTimelineSplitter()
+{
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CTimelineSplitter::~CTimelineSplitter()
+{
+}
+
+//=============================================================================
+/**
+ * Set the location of the splitter bar. Overridden so that this location can
+ * be stored in the user's preferences.
+ * @param inSplitLocation the location of the splitter bar, in pixels from the right/top.
+ */
+void CTimelineSplitter::SetSplitLocation(long inPixels)
+{
+ CSplitter::SetSplitLocation(inPixels);
+ CStudioPreferences::SetTimelineSplitterLocation(inPixels);
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.h b/src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.h
new file mode 100644
index 00000000..f9ba681a
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//=============================================================================
+// Prefix
+//=============================================================================
+#ifndef TIMELINE_SPLITTER_INCLUDED
+#define TIMELINE_SPLITTER_INCLUDED 1
+
+#pragma once
+
+//=============================================================================
+// Includes
+//=============================================================================
+#include "Splitter.h"
+
+//=============================================================================
+/**
+ * Overridden splitter, specific to the timeline, which stores the split location
+ * so that it can be retrieved between program sessions.
+ */
+class CTimelineSplitter : public CSplitter
+{
+public:
+ CTimelineSplitter();
+ virtual ~CTimelineSplitter();
+ void SetSplitLocation(long inPixels) override;
+};
+
+#endif
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp
new file mode 100644
index 00000000..ead5251d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp
@@ -0,0 +1,713 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//=============================================================================
+// Prefix
+//=============================================================================
+#include "stdafx.h"
+
+//=============================================================================
+// Includes
+//=============================================================================
+#include "TimelineTimelineLayout.h"
+#include "TimeMeasure.h"
+#include "ScalableScroller.h"
+#include "StudioUtils.h"
+#include "TimelineRow.h"
+#include "TimelineControl.h"
+#include "StateRow.h"
+#include "Snapper.h"
+#include "Bindings/TimelineTranslationManager.h"
+#include "ControlData.h"
+#include "HotKeys.h"
+#include "foundation/Qt3DSLogging.h"
+
+//=============================================================================
+// Defines
+//=============================================================================
+// For Win the modifier key for keyframe multi selection is the control key.
+#define MODIFIER_KEY CHotKeys::MODIFIER_CONTROL
+
+//=============================================================================
+// Class constants
+//=============================================================================
+const double DEFAULT_TIME_RATIO = .05;
+const double CTimelineTimelineLayout::SCALING_PERCENTAGE_INC = 1.1;
+const double CTimelineTimelineLayout::SCALING_PERCENTAGE_DEC = 0.9;
+const double CTimelineTimelineLayout::MAX_ZOOM_OUT = 7e-005;
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CTimelineTimelineLayout::CTimelineTimelineLayout(CTimelineControl *inTimelineControl, IDoc *inDoc)
+ : m_Playhead(this, inDoc)
+ , m_IsLayoutChanged(false)
+ , m_IsMouseDown(false)
+{
+ m_ControlData->SetMouseWheelEnabled(true);
+ m_TimelineControl = inTimelineControl;
+
+ m_TimeRatio = DEFAULT_TIME_RATIO + .01;
+ m_TimeMeasure = new CTimeMeasure(this, m_TimeRatio);
+ m_Scroller = new CScalableScroller();
+
+ m_Scroller->SetVerticalScrollMode(CScroller::ALWAYS);
+ m_Scroller->SetHorizontalScrollMode(CScroller::ALWAYS);
+ m_Scroller->AddScrollListener(this);
+ m_BoundingRect = new CAreaBoundingRect();
+ m_BoundingRect->SetName("TimelineAreaBoundingRect");
+ m_BoundingRect->SetVisible(false);
+ m_BoundingRect->SetAlpha(128);
+
+ AddChild(m_TimeMeasure);
+ AddChild(m_Scroller);
+ AddChild(&m_Playhead);
+ AddChild(m_BoundingRect);
+
+ // Blank control filling in the bottom of the timeline, under the rows
+ CBlankControl *theTimelineBlankControl = new CBlankControl();
+ m_TimebarList = new CFlowLayout(theTimelineBlankControl);
+
+ m_Scroller->AddChild(m_TimebarList);
+ m_Scroller->SetScalingListener(this);
+ m_TimebarList->SetName("TimelineTimelineLayoutList");
+
+ // Initializing flags for keyframe multi select to work.
+ m_CommitKeyframeSelection = false;
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CTimelineTimelineLayout::~CTimelineTimelineLayout()
+{
+ delete m_TimeMeasure;
+ delete m_Scroller;
+ delete m_TimebarList;
+ delete m_BoundingRect;
+}
+
+//=============================================================================
+/**
+ * Clear all the StateRows out of the top-level list.
+ * This is used when the current presentation is being cleared out.
+ */
+void CTimelineTimelineLayout::ClearRows()
+{
+ TTimelineRowList::iterator thePos = m_Rows.begin();
+ for (; thePos != m_Rows.end(); ++thePos) {
+ CTimelineRow *theRow = (*thePos);
+ m_TimebarList->RemoveChild(theRow->GetTimebarControl());
+ }
+
+ m_Rows.clear();
+}
+
+//=============================================================================
+/**
+ * Set the size of this control.
+ * Overrrides CControl::SetSize so that this can redo the layout of all inner
+ * controls.
+ * @param inSize the new size of this control.
+ */
+void CTimelineTimelineLayout::SetSize(CPt inSize)
+{
+ CControl::SetSize(inSize);
+
+ RecalcLayout();
+}
+
+//=============================================================================
+/**
+ * Recalculate the positioning of all the child components.
+ */
+void CTimelineTimelineLayout::RecalcLayout()
+{
+ CPt mySize = GetSize();
+ // Put the time measure on top taking 21 pixels high.
+ m_TimeMeasure->SetSize(CPt(mySize.x, 21));
+ m_TimeMeasure->SetPosition(CPt(0, 0));
+
+ // Make the scroller take up the rest of the space.
+ m_Scroller->SetSize(CPt(mySize.x, mySize.y - 42));
+ m_Scroller->SetPosition(CPt(0, 21));
+
+ // Make it the full length of the view, minus the bottom scroll bar.
+ m_Playhead.SetSize(CPt(13, GetSize().y - m_Scroller->GetHorizontalBar()->GetSize().y - 21));
+
+ long theMinTime = -(m_Playhead.GetCenterOffset());
+
+ if (!m_Rows.empty()) {
+ long theLatestTime = 0;
+ TTimelineRowList::iterator thePos = m_Rows.begin();
+ for (; thePos != m_Rows.end(); ++thePos) {
+ CTimelineRow *theRow = (*thePos);
+ long theRowLatestTime = theRow->GetLatestEndTime();
+ if (theRowLatestTime > theLatestTime)
+ theLatestTime = theRowLatestTime;
+ }
+
+ long theMinWidth = ::TimeToPos(theLatestTime, m_TimeRatio) + END_BUFFER_SIZE;
+ long theMinHeight = m_TimebarList->GetMinimumSize().y;
+
+ CPt theVisSize = m_Scroller->GetVisibleSize();
+
+ if (theMinHeight < theVisSize.y)
+ theMinHeight = theVisSize.y;
+ if (theMinWidth < theVisSize.x)
+ theMinWidth = theVisSize.x;
+
+ m_TimebarList->ResetMinMaxPref();
+ m_TimebarList->SetAbsoluteSize(CPt(theMinWidth, theMinHeight));
+ }
+
+ // Set up the limits.
+ m_Playhead.SetMinMaxPosition(theMinTime, mySize.x - m_Scroller->GetVerticalBar()->GetSize().x);
+
+ // Set playhead to time 0.
+ SetTime(m_TimelineControl->GetTranslationManager()->GetCurrentViewTime(), true);
+
+ // Reset! so that this isn't unnecessarily run
+ m_IsLayoutChanged = false;
+}
+
+//=============================================================================
+/**
+ * Add a timeline row to this object.
+ * This will add the row as a top level object.
+ * @param inRow the row to be added.
+ */
+void CTimelineTimelineLayout::AddRow(CTimelineRow *inRow)
+{
+ m_Rows.push_back(inRow);
+
+ m_TimebarList->AddChild(inRow->GetTimebarControl());
+
+ inRow->SetTimeRatio(m_TimeRatio);
+ // For keyframe/timebar snapping.
+ inRow->SetSnappingListProvider(this);
+}
+
+//=============================================================================
+/**
+ * Call from the ScalableScroller that it is scaling the right side of the timebar.
+ * @param inLength the length that the thumb wants to be.
+ * @param inTotalLength the maximum length that the thumb can be.
+ * @param inOffset the offset of the thumb position.
+ */
+void CTimelineTimelineLayout::OnScalingRight(long inLength, long inTotalLength, long inOffset)
+{
+ double theViewSize = m_Scroller->GetVisibleSize().x;
+ double theClientSize = m_Scroller->GetContaineeSize().x;
+ double theLength = inLength;
+ double theTotalLength = inTotalLength;
+
+ double theTimeRatio =
+ (theViewSize * theTotalLength) / (theClientSize * theLength) * m_TimeRatio;
+
+ // This means the bar was dragged to the far end, just prevent it for getting wacky.
+ if (theTimeRatio > 0) {
+ // This will set the time ratio, but will cap it at 1 or MAX_ZOOM_OUT so if the Time ratio
+ // less than max, don't need to move the timeline
+ SetTimeRatio(theTimeRatio);
+ if (theTimeRatio < 1) {
+ double theMaxVisPos = m_Scroller->GetMaxVisiblePosition().x;
+ long theVisiblePosition = ::dtol(theMaxVisPos * inOffset / (inTotalLength - inLength));
+ m_Scroller->SetVisiblePosition(
+ CPt(theVisiblePosition, m_Scroller->GetVisiblePosition().y));
+ }
+ }
+}
+
+//=============================================================================
+/**
+ * Under construction.
+ */
+void CTimelineTimelineLayout::OnScalingLeft(long inLength, long inTotalLength, long inOffset)
+{
+ // Hey- look at that, doesn't matter which side you're scaling.
+ // Hey, nice comment especially the function header
+ OnScalingRight(inLength, inTotalLength, inOffset);
+}
+
+void CTimelineTimelineLayout::OnScalingReset()
+{
+ SetTimeRatio(DEFAULT_TIME_RATIO);
+}
+
+//=============================================================================
+/**
+ * Set the TimeRatio to be used.
+ * This will propagate the time ratio down to all the child items.
+ * @param inTimeRatio the time ratio to be set.
+ */
+void CTimelineTimelineLayout::SetTimeRatio(double inTimeRatio)
+{
+ if (inTimeRatio != m_TimeRatio) {
+ if (inTimeRatio > 1)
+ inTimeRatio = 1;
+ // if ( inTimeRatio < MAX_ZOOM_OUT )
+ // inTimeRatio = MAX_ZOOM_OUT;
+
+ m_TimeRatio = inTimeRatio;
+ m_TimeMeasure->SetTimeRatio(inTimeRatio);
+
+ TTimelineRowList::iterator thePos = m_Rows.begin();
+ for (; thePos != m_Rows.end(); ++thePos) {
+ CTimelineRow *theRow = (*thePos);
+ theRow->SetTimeRatio(inTimeRatio);
+ }
+
+ RecalcLayout();
+
+ // store the timeline ratio
+ SetTimelineRatio(m_TimelineControl->GetActiveSlide(), m_TimeRatio);
+ qCInfo(qt3ds::TRACE_INFO) << "Set time ratio: " << inTimeRatio;
+ }
+}
+
+//==============================================================================
+/**
+ * When timeline layout has changed. RecalcLayout should be called to adjust the scrollbars if
+ * a asset is expanded/collapsed in the timeline.
+ */
+void CTimelineTimelineLayout::OnTimelineLayoutChanged()
+{
+ RecalcLayout();
+
+ // In addition, this has to be 'marked' for if SetScrollerPositionY is called due to
+ // new assets being added, RecalcLayout has to be called again.
+ m_IsLayoutChanged = true;
+}
+
+/**
+ * Deletes the time zoom ratio for a particular slide.
+ * @param inContext the time context of that slide to delete
+ */
+void CTimelineTimelineLayout::DeleteTimelineRatio(UICDM::CUICDMSlideHandle inSlide)
+{
+ m_TimelineRatio.erase(inSlide);
+}
+
+/**
+ * Clear all entries
+ */
+void CTimelineTimelineLayout::ClearAllTimeRatios()
+{
+ m_TimelineRatio.clear();
+}
+
+/**
+ * Retrieves the time zoom ratio for a particular slide
+ * @param inContext the time context of that slide to retrieve zoom ratio
+ * @return the zoom ratio, or -1 if it's not found
+ */
+double CTimelineTimelineLayout::GetTimelineRatio(UICDM::CUICDMSlideHandle inSlide)
+{
+ TSlideRatioMap::iterator theResult = m_TimelineRatio.find(inSlide);
+ if (theResult != m_TimelineRatio.end())
+ return theResult->second;
+ else
+ return -1;
+}
+
+/**
+ * Sets the time zoom ratio for a particular slide
+ * @param inContext the time context of that slide
+ * @param inRatio the zoom factor
+ */
+void CTimelineTimelineLayout::SetTimelineRatio(UICDM::CUICDMSlideHandle inSlide, double inRatio)
+{
+ m_TimelineRatio[inSlide] = inRatio;
+}
+
+//=============================================================================
+/**
+ * For testing purposes.
+ */
+long CTimelineTimelineLayout::GetMaximumTimebarTime()
+{
+ return 30000;
+}
+
+//=============================================================================
+/**
+ * Call from the TimelineView to notifiy this that some of its objects got filtered.
+ * This was used for redoing the layout but is no longer necessary.
+ */
+void CTimelineTimelineLayout::Filter()
+{
+}
+
+//=============================================================================
+/**
+ * Notification from the CScroller that it is scrolling.
+ * This will update the other views with the verticall scrolling and update
+ * the TimeMeasure with the horizontal scroll amount.
+ * @param inScrollAmount the amount that was scrolled by.
+ */
+void CTimelineTimelineLayout::OnScroll(CScroller *inSource, CPt inScrollAmount)
+{
+ Q_UNUSED(inSource);
+
+ m_TimelineControl->SetScrollPositionY(m_Scroller, m_Scroller->GetVisiblePosition().y);
+
+ long theTimeOffset = GetViewTimeOffset();
+ m_TimeMeasure->SetTimeOffset(theTimeOffset);
+
+ long thePlayheadPos =
+ ::TimeToPos(m_TimelineControl->GetTranslationManager()->GetCurrentViewTime()
+ - theTimeOffset,
+ m_TimeRatio)
+ - m_Playhead.GetCenterOffset();
+
+ m_Playhead.SetPosition(CPt(thePlayheadPos, 0));
+
+ m_DragBeginPoint += inScrollAmount;
+}
+
+void CTimelineTimelineLayout::SetScrollPositionY(CScroller *inSource, long inPositionY,
+ bool inAbsolute)
+{
+ Q_UNUSED(inSource);
+
+ CPt theVisPos = m_Scroller->GetVisiblePosition();
+
+ if (!inAbsolute) {
+ CPt theMaxSize = m_Scroller->GetMaxVisiblePosition();
+
+ CRct theVisibleRect(CPt(theVisPos.x, theMaxSize.y - theVisPos.y),
+ m_Scroller->GetVisibleSize());
+ CPt thePoint(theVisPos.x, inPositionY);
+ if (!theVisibleRect.IsInRect(thePoint))
+ m_Scroller->SetVisiblePosition(CPt(theVisPos.x, inPositionY));
+ } else {
+ // For new assets added, RecalcLayout needs be called here if there was a layout changed
+ // because
+ // m_TimebarList->GetMinimumSize( ).y is only updated at this point, otherwise the tree and
+ // layout will
+ // go out of sync.
+ if (m_IsLayoutChanged)
+ RecalcLayout();
+
+ m_Scroller->SetVisiblePosition(CPt(theVisPos.x, inPositionY));
+ }
+}
+
+//=============================================================================
+/**
+ * Get the scroller control this is using.
+ * Meant for testing purposes.
+ * @return the scroller this is using.
+ */
+CScalableScroller *CTimelineTimelineLayout::GetScroller()
+{
+ return m_Scroller;
+}
+
+//=============================================================================
+/**
+ * Get the playhead control this is using.
+ * Meant for testing purposes.
+ * @return the playhead this is using.
+ */
+CPlayhead *CTimelineTimelineLayout::GetPlayhead()
+{
+ return &m_Playhead;
+}
+
+//=============================================================================
+/**
+ * Scroll the contents of the timeline horizontally.
+ * This is used mainly by the playhead to scroll the view when it gets to the
+ * edge.
+ * @param inAmount the amount to scroll the view by.
+ * @return the amount actually scrolled, limited by min/max values.
+ */
+long CTimelineTimelineLayout::ScrollLayout(long inAmount)
+{
+ // Log the current position for returning
+ CPt thePosition = m_Scroller->GetVisiblePosition();
+
+ m_Scroller->SetVisiblePosition(CPt(thePosition.x + inAmount, thePosition.y));
+
+ // Return how much was actually scrolled, let the scroller handle min/max scroll amounts.
+ return m_Scroller->GetVisiblePosition().x - thePosition.x;
+}
+
+//=============================================================================
+/**
+ * Recalculate what the time is based on the location of the playhead.
+ * This will call SetTime on the TimelineView with the new time.
+ * @param inUpdateClient true if the client time should be updated.
+ */
+void CTimelineTimelineLayout::RecalcTime(bool inUpdateClient, long inFlags)
+{
+ long theOffset = m_Playhead.GetPosition().x + m_Playhead.GetCenterOffset()
+ + m_Scroller->GetVisiblePosition().x;
+
+ long theTime = ::PosToTime(theOffset, m_TimeRatio);
+ m_Snapper.InterpretTimeEx(theTime, inFlags);
+
+ // Update the time
+ m_Playhead.UpdateTime(theTime, inUpdateClient);
+}
+
+//=============================================================================
+/**
+ * Call from the timeline view that the time is changing.
+ * @param inNewTime the new time.
+ * @param inIsSecondary lame flag to prevent infinite recursion.
+ */
+void CTimelineTimelineLayout::SetTime(long inNewTime, bool inIsSecondary)
+{
+ long theOffset = ::TimeToPos(inNewTime, m_TimeRatio);
+ theOffset -= m_Scroller->GetVisiblePosition().x + m_Playhead.GetCenterOffset();
+
+ long theViewSize = m_Scroller->GetVisibleSize().x;
+
+ if (!inIsSecondary) {
+ if (theOffset < -m_Playhead.GetCenterOffset()) {
+ long thePos = ::TimeToPos(inNewTime, m_TimeRatio) - m_Playhead.GetCenterOffset();
+ m_Scroller->SetVisiblePosition(CPt(thePos, m_Scroller->GetVisiblePosition().y));
+ } else if (theOffset > (theViewSize - (m_Playhead.GetCenterOffset() + 20))) {
+ long thePos = ::TimeToPos(inNewTime, m_TimeRatio) + 20;
+ thePos -= theViewSize;
+ m_Scroller->SetVisiblePosition(CPt(thePos, m_Scroller->GetVisiblePosition().y));
+ }
+ SetTime(inNewTime, true);
+ } else {
+ m_Playhead.SetPosition(CPt(theOffset, m_Playhead.GetPosition().y));
+ }
+}
+
+//=============================================================================
+/**
+ * Notification that the TimeMeasure was clicked on.
+ * This is used to reposition the playhead wherever the mouse was clicked.
+ * @param inPoint the location of the mouse local to the time measure.
+ */
+void CTimelineTimelineLayout::OnTimeMeasureMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ Q_UNUSED(inFlags);
+
+ m_Snapper.Clear();
+ m_Snapper.SetSource(&m_Playhead);
+ PopulateSnappingList(&m_Snapper);
+ m_Snapper.SetSnappingKeyframes(true);
+
+ m_Playhead.SetPosition(
+ CPt(inPoint.x - m_Playhead.GetCenterOffset(), m_Playhead.GetPosition().y));
+ RecalcTime(true, inFlags);
+}
+
+//=============================================================================
+/**
+ * Handles left-clicks. Starts a drag operation if a child does not handle the
+ * message.
+ * @param inPoint location of the mouse when event occurred
+ * @param inFlags state of modifier keys when event occurred
+ */
+bool CTimelineTimelineLayout::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ if (!CControl::OnMouseDown(inPoint, inFlags)) {
+ m_BoundingRect->SetSize(CPt(0, 0));
+ m_BoundingRect->SetVisible(true);
+
+ // Do not deselect all keyframes as the user intends to select more keyframes,
+ // when the modifier key is pressed.
+ if (!(inFlags & MODIFIER_KEY))
+ m_TimelineControl->GetTranslationManager()->ClearKeyframeSelection();
+
+ m_IsMouseDown = true;
+ m_DragBeginPoint = inPoint;
+ }
+ return true;
+}
+
+void CTimelineTimelineLayout::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseMove(inPoint, inFlags);
+
+ if (m_IsMouseDown) {
+ CPt theSize;
+ CRct theRect;
+
+ // Tests if the user has pressed the modifier key, while moving the mouse.
+ bool theModifierKeyDown;
+ if (inFlags & MODIFIER_KEY)
+ theModifierKeyDown = true;
+ else
+ theModifierKeyDown = false;
+
+ // Calculate the rect for the bounding box
+ theSize = CPt(inPoint.x - m_DragBeginPoint.x, inPoint.y - m_DragBeginPoint.y);
+ theRect = CRct(m_DragBeginPoint, theSize);
+ theRect.Normalize();
+ m_BoundingRect->SetPosition(theRect.position);
+ m_BoundingRect->SetSize(theRect.size);
+ theRect.Offset(-m_Scroller->GetPosition());
+ theRect.Offset(m_Scroller->GetVisiblePosition());
+
+ // Select all keys inside the rect
+
+ TTimelineRowList::iterator thePos = m_Rows.begin();
+
+ for (; thePos != m_Rows.end(); ++thePos) {
+ CStateRow *theRow = reinterpret_cast<CStateRow *>(*thePos);
+ theRow->SelectKeysInRect(theRect, theModifierKeyDown, m_CommitKeyframeSelection);
+ }
+ m_CommitKeyframeSelection = false;
+ }
+}
+
+void CTimelineTimelineLayout::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ // try to prevent stuck mousetips on exceptions
+ try {
+ CControl::OnMouseUp(inPoint, inFlags);
+ m_BoundingRect->SetVisible(false);
+ } catch (...) {
+ }
+
+ m_IsMouseDown = false;
+
+ // Commits the key frame selection. This finalises the keyframes selection
+ // in the rect. When the mouse is down again, we would be able to append
+ // the commited keyframes with the new batch of keyframes.
+ m_CommitKeyframeSelection = true;
+}
+
+void CTimelineTimelineLayout::PopulateSnappingList(CSnapper *inSnappingList)
+{
+ CRct theArea(m_Scroller->GetVisibleSize());
+ theArea.Offset(-m_Scroller->GetPosition());
+ theArea.Offset(m_Scroller->GetVisiblePosition());
+
+ inSnappingList->SetVisibleArea(theArea.position.y, theArea.size.y);
+
+ inSnappingList->SetTimeRatio(m_TimeRatio);
+ if (inSnappingList->GetSource() != &m_Playhead)
+ inSnappingList->AddTime(m_Playhead.GetCurrentTime());
+
+ m_TimeMeasure->PopulateSnappingList(inSnappingList);
+
+ TTimelineRowList::iterator theRowIter = m_Rows.begin();
+ for (; theRowIter != m_Rows.end(); ++theRowIter) {
+ (*theRowIter)->PopulateSnappingList(inSnappingList);
+ }
+}
+
+long CTimelineTimelineLayout::GetViewTimeOffset()
+{
+ return ::dtol(m_Scroller->GetVisiblePosition().x / m_TimeRatio);
+}
+
+CTimeMeasure *CTimelineTimelineLayout::GetTimeMeasure()
+{
+ return m_TimeMeasure;
+}
+
+//=============================================================================
+/**
+ * Register all the events for hotkeys that are active for the entire application.
+ * Hotkeys for the entire application are ones that are not view specific in
+ * scope.
+ * @param inShortcutHandler the global shortcut handler.
+ */
+void CTimelineTimelineLayout::RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler)
+{
+ inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer<CTimelineTimelineLayout>(
+ this, &CTimelineTimelineLayout::OnScalingZoomIn),
+ 0, Qt::Key_Plus);
+ inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer<CTimelineTimelineLayout>(
+ this, &CTimelineTimelineLayout::OnScalingZoomOut),
+ 0, Qt::Key_Minus);
+ inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer<CTimelineTimelineLayout>(
+ this, &CTimelineTimelineLayout::OnScalingZoomIn),
+ Qt::KeypadModifier, Qt::Key_Plus);
+ inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer<CTimelineTimelineLayout>(
+ this, &CTimelineTimelineLayout::OnScalingZoomOut),
+ Qt::KeypadModifier, Qt::Key_Minus);
+}
+
+//=============================================================================
+/**
+ * Call from the Hotkey that it is zooming in the timebar.
+ */
+
+void CTimelineTimelineLayout::OnScalingZoomIn()
+{
+ double theTimeRatio = m_TimeRatio * SCALING_PERCENTAGE_INC;
+
+ SetTimeRatio(theTimeRatio);
+ CenterToPlayhead();
+}
+
+//=============================================================================
+/**
+ * Call from the Hotkey that it is zooming out of the timebar.
+ */
+
+void CTimelineTimelineLayout::OnScalingZoomOut()
+{
+ double theTimeRatio = m_TimeRatio * SCALING_PERCENTAGE_DEC;
+
+ SetTimeRatio(theTimeRatio);
+ CenterToPlayhead();
+}
+
+void CTimelineTimelineLayout::CenterToPlayhead()
+{
+ long theTime = m_Playhead.GetCurrentTime();
+ long thePos = ::TimeToPos(theTime, m_TimeRatio);
+ long theNewPosX = thePos - (m_Scroller->GetSize().x / 2);
+
+ m_Scroller->SetVisiblePosition(CPt(theNewPosX, m_Scroller->GetVisiblePosition().y));
+}
+
+//==============================================================================
+/**
+ * Handle mouse wheel messages to allow zooming
+ */
+bool CTimelineTimelineLayout::OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags)
+{
+ bool theRetVal = false;
+ if (inFlags & CHotKeys::MODIFIER_CONTROL) {
+ if (inAmount > 0)
+ OnScalingZoomIn();
+ else
+ OnScalingZoomOut();
+ theRetVal = true;
+ } else
+ theRetVal = CControl::OnMouseWheel(inPoint, inAmount, inFlags);
+ return theRetVal;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.h b/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.h
new file mode 100644
index 00000000..35524d5b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//=============================================================================
+// Prefix
+//=============================================================================
+#ifndef INCLUDED_TIMELINE_TIMELINE_LAYOUT_H
+#define INCLUDED_TIMELINE_TIMELINE_LAYOUT_H 1
+
+#pragma once
+
+//=============================================================================
+// Includes
+//=============================================================================
+#include "Control.h"
+#include <vector>
+#include "ScalableScrollerBar.h"
+#include "Scroller.h"
+#include "Pt.h"
+#include "Snapper.h"
+#include "AreaBoundingRect.h"
+#include "Playhead.h"
+#include "UICDMHandles.h"
+
+//=============================================================================
+// Forwards
+//=============================================================================
+class CScalableScroller;
+class CTimelineRow;
+class CFlowLayout;
+class CTimelineControl;
+class CSnapper;
+class IDoc;
+class CHotKeys;
+class CTimeMeasure;
+class CPlayhead;
+
+//=============================================================================
+/**
+ * Right-hand pane of the Timeline containing timebars, keyframes, etc.
+ */
+class CTimelineTimelineLayout : public CControl,
+ public CScalingListener,
+ public CScrollListener,
+ public ISnappingListProvider
+{
+ typedef std::vector<CTimelineRow *> TTimelineRowList;
+ typedef std::map<UICDM::CUICDMSlideHandle, double> TSlideRatioMap;
+
+public:
+ static const long END_BUFFER_SIZE = 20;
+ static const double SCALING_PERCENTAGE_INC;
+ static const double SCALING_PERCENTAGE_DEC;
+ static const double MAX_ZOOM_OUT;
+
+ CTimelineTimelineLayout(CTimelineControl *inView, IDoc *inDoc);
+ virtual ~CTimelineTimelineLayout();
+
+ void SetSize(CPt inSize) override;
+
+ void AddRow(CTimelineRow *inRow);
+
+ void OnScalingRight(long inLength, long inTotalLength, long inOffset) override;
+ void OnScalingLeft(long inLength, long inTotalLength, long inOffset) override;
+ void OnScalingReset() override;
+
+ long ScrollLayout(long inAmount);
+
+ void Filter();
+
+ void OnScroll(CScroller *inScroller, CPt inScrollAmount) override;
+ void SetScrollPositionY(CScroller *inSource, long inPositionY, bool inAbsolute = true);
+
+ void ClearRows();
+
+ bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ bool OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags) override;
+
+ CScalableScroller *GetScroller();
+ CPlayhead *GetPlayhead();
+ CTimeMeasure *GetTimeMeasure();
+ void RecalcTime(bool inUpdateClient, long inFlags);
+ void SetTime(long inTime, bool inIsSecondary = false);
+ void OnTimeMeasureMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags);
+ long GetViewTimeOffset();
+ void RecalcLayout();
+ void RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler);
+ void SetTimeRatio(double inTimeRatio);
+ void OnTimelineLayoutChanged();
+
+ void DeleteTimelineRatio(UICDM::CUICDMSlideHandle inSlide);
+ void ClearAllTimeRatios();
+ double GetTimelineRatio(UICDM::CUICDMSlideHandle inSlide);
+
+ // ISnappingListProvider
+ void PopulateSnappingList(CSnapper *inSnappingList) override;
+
+protected:
+ void SetTimelineRatio(UICDM::CUICDMSlideHandle inSlide, double inRatio);
+
+ long GetMaximumTimebarTime();
+ void OnScalingZoomIn();
+ void OnScalingZoomOut();
+ void CenterToPlayhead();
+
+ bool m_CommitKeyframeSelection; ///< flag for saving previous keyframe selection when the mouse
+ ///is released.
+ CTimelineControl *m_TimelineControl;
+ CTimeMeasure *m_TimeMeasure;
+ CScalableScroller *m_Scroller;
+ CFlowLayout *m_TimebarList;
+ double m_TimeRatio;
+
+ TTimelineRowList m_Rows;
+ CPlayhead m_Playhead;
+ CSnapper m_Snapper;
+ bool m_IsLayoutChanged; ///< flag to keep track of a need for a delayed RecalcLayout
+
+ bool m_IsMouseDown;
+ CPt m_DragBeginPoint;
+ CAreaBoundingRect *m_BoundingRect;
+
+ TSlideRatioMap m_TimelineRatio; ///< stores the time zooming ratios for each slide
+};
+#endif // INCLUDED_TIMELINE_TIMELINE_LAYOUT_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.cpp
new file mode 100644
index 00000000..1229b88b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.cpp
@@ -0,0 +1,360 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//=============================================================================
+// Prefix
+//=============================================================================
+#include "stdafx.h"
+
+//=============================================================================
+// Includes
+//=============================================================================
+#include "TimelineTreeLayout.h"
+#include "FlowLayout.h"
+#include "Scroller.h"
+#include "StateRow.h"
+#include "FilterToolbar.h"
+#include "ToggleToolbar.h"
+#include "TimeToolbar.h"
+#include "StudioPreferences.h"
+#include "TimelineControl.h"
+#include "Renderer.h"
+#include "ToggleBlankControl.h"
+#include "ColorBlankControl.h"
+#include "TreeBlankControl.h"
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CTimelineTreeLayout::CTimelineTreeLayout(CTimelineControl *inTimelineControl, IDoc *inDoc)
+ : m_IsScrolling(false)
+{
+ m_TimelineControl = inTimelineControl;
+
+ m_ColorScroller = new CScroller();
+ m_ColorScroller->SetHorizontalScrollMode(CScroller::NEVER);
+ m_ColorScroller->SetVerticalScrollMode(CScroller::NEVER);
+ m_ColorScroller->AddScrollListener(this);
+
+ m_ColorBlankControl = new CColorBlankControl();
+ m_ColorList = new CFlowLayout(m_ColorBlankControl);
+ m_ColorScroller->AddChild(m_ColorList);
+
+ m_ToggleScroller = new CScroller();
+ m_ToggleScroller->SetHorizontalScrollMode(CScroller::NEVER);
+ m_ToggleScroller->SetVerticalScrollMode(CScroller::NEVER);
+
+ m_ToggleBlankControl = new CToggleBlankControl();
+ m_ToggleList = new CFlowLayout(m_ToggleBlankControl);
+ m_ToggleScroller->AddChild(m_ToggleList);
+ m_ToggleScroller->AddScrollListener(this);
+
+ m_TreeScroller = new CScroller();
+ m_TreeScroller->SetVerticalScrollMode(CScroller::NEVER);
+ m_TreeScroller->SetHorizontalScrollMode(CScroller::ALWAYS);
+ m_TreeScroller->AddScrollListener(this);
+
+ m_TreeBlankControl = new CTreeBlankControl();
+ m_TreeList = new CFlowLayout(m_TreeBlankControl);
+ m_TreeScroller->AddChild(m_TreeList);
+
+ m_FilterToolbar = new CFilterToolbar(this);
+ m_TimeToolbar = new CTimeToolbar(inDoc);
+ m_ToggleToolbar = new CToggleToolbar(this);
+
+ AddChild(m_TreeScroller);
+ AddChild(m_ToggleScroller);
+ AddChild(m_TimeToolbar);
+ AddChild(m_ToggleToolbar);
+ AddChild(m_ColorScroller);
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CTimelineTreeLayout::~CTimelineTreeLayout()
+{
+ m_ColorScroller->RemoveChild(m_ColorList);
+ m_ToggleScroller->RemoveChild(m_ToggleList);
+ m_TreeScroller->RemoveChild(m_TreeList);
+
+ RemoveChild(m_TreeScroller);
+ RemoveChild(m_ToggleScroller);
+ RemoveChild(m_TimeToolbar);
+ RemoveChild(m_FilterToolbar);
+ RemoveChild(m_ToggleToolbar);
+ RemoveChild(m_ColorScroller);
+ // RemoveChild( m_BreadCrumbToolbar );
+
+ delete m_FilterToolbar;
+ delete m_TimeToolbar;
+ delete m_ToggleToolbar;
+ delete m_ColorScroller;
+ delete m_ColorList;
+ delete m_ToggleScroller;
+ delete m_ToggleList;
+ delete m_TreeList;
+ delete m_TreeScroller;
+ // delete m_BreadCrumbToolbar;
+
+ // Delete all the rows, this control is responsible for the rows, maybe it should not
+ // be but currently it is.
+ TTimelineRowList::iterator thePos = m_Rows.begin();
+ for (; thePos != m_Rows.end(); ++thePos) {
+ CTimelineRow *theRow = (*thePos);
+ theRow->Dispose(); // Dispose will delete the row as well
+ }
+}
+
+//=============================================================================
+/**
+ * Clear out all the contents of this tree layout.
+ * This will also delete all the rows, so make sure it is called after the
+ * TimelineTimelineLayout::ClearRows is called.
+ */
+void CTimelineTreeLayout::ClearRows()
+{
+ TTimelineRowList::iterator thePos = m_Rows.begin();
+ for (; thePos != m_Rows.end(); ++thePos) {
+ CTimelineRow *theRow = (*thePos);
+ m_ColorList->RemoveChild(theRow->GetColorControl());
+ m_TreeList->RemoveChild(theRow->GetTreeControl());
+ m_ToggleList->RemoveChild(theRow->GetToggleControl());
+
+ theRow->Dispose();
+ }
+
+ m_Rows.clear();
+}
+
+//=============================================================================
+/**
+ * Set the filter back to it's default state.
+ */
+void CTimelineTreeLayout::ResetFilter()
+{
+ m_FilterToolbar->FilterBehaviors(false);
+ m_FilterToolbar->FilterProperties(false);
+ m_FilterToolbar->FilterMaterials(false);
+ m_FilterToolbar->FilterShy(false);
+}
+
+//=============================================================================
+/**
+ * Set the size of this control.
+ * Overrides CControl::SetSize so that RecalcLayout can be called.
+ */
+void CTimelineTreeLayout::SetSize(CPt inSize)
+{
+ if (inSize != GetSize()) {
+ CControl::SetSize(inSize);
+
+ RecalcLayout();
+ }
+}
+
+//=============================================================================
+/**
+ * Recalculate the layout of all the child components.
+ * Called when this changes size and all the children need to be repositioned.
+ */
+void CTimelineTreeLayout::RecalcLayout()
+{
+ CPt mySize = GetSize();
+ long theHeaderHeight = CStudioPreferences::GetHeaderHeight();
+
+ m_FilterToolbar->SetSize(CPt(120, theHeaderHeight));
+ m_FilterToolbar->SetPosition(0, 0);
+
+ m_ToggleToolbar->SetSize(CPt(61, theHeaderHeight));
+ m_ToggleToolbar->SetPosition(mySize.x - m_ToggleToolbar->GetSize().x, 0);
+
+ m_TimeToolbar->SetSize(CPt(mySize.x - m_ToggleToolbar->GetSize().x, theHeaderHeight));
+ m_TimeToolbar->SetPosition(0, 0);
+
+ m_ColorScroller->SetSize(CPt(CStudioPreferences::GetRowSize(), mySize.y - theHeaderHeight
+ - m_TreeScroller->GetHorizontalBar()->GetMinimumSize().y
+ - theHeaderHeight));
+ m_ColorScroller->SetPosition(0, theHeaderHeight);
+
+ m_ToggleScroller->SetSize(CPt(m_ToggleToolbar->GetSize().x, mySize.y - theHeaderHeight
+ - m_TreeScroller->GetHorizontalBar()->GetMinimumSize().y
+ - theHeaderHeight));
+ m_ToggleScroller->SetPosition(mySize.x - m_ToggleScroller->GetSize().x, theHeaderHeight);
+
+ m_TreeScroller->SetSize(
+ CPt(mySize.x, mySize.y - m_FilterToolbar->GetSize().y - theHeaderHeight));
+ m_TreeScroller->SetPosition(0, theHeaderHeight);
+
+ m_TreeScroller->SetAdditionalClippingRect(
+ CRct(m_ColorScroller->GetSize().x, 0,
+ m_ToggleScroller->GetPosition().x - m_ColorScroller->GetSize().x,
+ m_TreeScroller->GetSize().y));
+}
+
+//=============================================================================
+/**
+ * Add another top level item to the left side of the timeline.
+ * If there is already a top level item then this one will be appended to the
+ * list.
+ * @param inRow the row to be added.
+ */
+void CTimelineTreeLayout::AddRow(CTimelineRow *inRow)
+{
+ m_ColorList->AddChild(inRow->GetColorControl());
+ m_TreeList->AddChild(inRow->GetTreeControl());
+ m_ToggleList->AddChild(inRow->GetToggleControl());
+
+ m_Rows.push_back(inRow);
+
+ inRow->SetIndent(20);
+
+ inRow->Filter(m_Filter);
+}
+
+//=============================================================================
+/**
+ * Applies the current filter settings to the timeline. Although the filter
+ * preferences can be set independently, they are not actually applied until
+ * this function is called.
+ */
+void CTimelineTreeLayout::Filter()
+{
+ for (TTimelineRowList::iterator thePos = m_Rows.begin(); thePos != m_Rows.end(); ++thePos) {
+ CTimelineRow *theRow = *thePos;
+ theRow->Filter(m_Filter);
+ }
+
+ // TODO: sk - it is unclear to me what this is trying to do.. I am leavint this here till it
+ // becomes obvious it is totally redundant OR someone finds a related bug
+ /*
+ // Call OnSelect( ) on the selected object (if there is one) to get the timeline to scroll down.
+ CAsset* theSelectedObject = dynamic_cast<CAsset*>( m_Doc->GetSelectedObject( ) );
+ if ( theSelectedObject )
+ theSelectedObject->OnSelect( );
+
+ m_TimelineControl->GetTimelineLayout( )->RecalcLayout( );
+ */
+}
+
+void CTimelineTreeLayout::OnScroll(CScroller *inSource, CPt inScrollAmount)
+{
+ Q_UNUSED(inScrollAmount);
+
+ // SetScrollPositionY triggers another onScroll event and potentially causes the position
+ // to be set incorrectly.
+ if (!m_IsScrolling) {
+ m_IsScrolling = true;
+ m_TreeBlankControl->SetVisiblePositionX(inSource->GetVisiblePosition().x);
+ m_TimelineControl->SetScrollPositionY(inSource, inSource->GetVisiblePosition().y);
+ m_IsScrolling = false;
+ }
+}
+
+//=============================================================================
+/**
+ * Set the vertical position of all the scrollers in this view.
+ * This is used to sync up the positions with the timebar scroller view.
+ * @param inScrollPositionY the position of the scroller.
+ */
+void CTimelineTreeLayout::SetScrollPositionY(CScroller *inSource, long inScrollPositionY,
+ bool inAbsolute)
+{
+ Q_UNUSED(inSource);
+
+ if (!inAbsolute) {
+ CRct theVisibleRect(m_ColorScroller->GetVisiblePosition(),
+ m_ColorScroller->GetVisibleSize());
+ CPt thePoint(m_ColorScroller->GetVisiblePosition().x, inScrollPositionY);
+ if (!theVisibleRect.IsInRect(thePoint)) {
+ m_ColorScroller->SetVisiblePosition(
+ CPt(m_ColorScroller->GetVisiblePosition().x, inScrollPositionY));
+ m_TreeScroller->SetVisiblePosition(
+ CPt(m_TreeScroller->GetVisiblePosition().x, inScrollPositionY));
+ m_ToggleScroller->SetVisiblePosition(
+ CPt(m_ToggleScroller->GetVisiblePosition().x, inScrollPositionY));
+ }
+ } else {
+ m_ColorScroller->SetVisiblePosition(
+ CPt(m_ColorScroller->GetVisiblePosition().x, inScrollPositionY));
+ m_TreeScroller->SetVisiblePosition(
+ CPt(m_TreeScroller->GetVisiblePosition().x, inScrollPositionY));
+ m_ToggleScroller->SetVisiblePosition(
+ CPt(m_ToggleScroller->GetVisiblePosition().x, inScrollPositionY));
+ }
+}
+
+//=============================================================================
+/**
+ * Sets the time on the Time header display time.
+ * @param inTime the new time.
+ */
+void CTimelineTreeLayout::SetTime(long inTime)
+{
+ m_TimeToolbar->SetTime(inTime);
+}
+
+//=============================================================================
+/**
+ * This is overridden so the Gesture can Notify Drop Listeners that its time to Drop.
+ * If the gesture is dragging something then wee will drop.
+ */
+void CTimelineTreeLayout::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
+{
+ CControl::OnMouseUp(inPoint, inFlags);
+}
+
+//=============================================================================
+/**
+ * Returns the playhead time
+ */
+long CTimelineTreeLayout::GetTime()
+{
+ return m_TimeToolbar->GetTime();
+}
+
+//=============================================================================
+/**
+ * @return rectangle describing the visible area of the tree control
+ */
+CRct CTimelineTreeLayout::GetVisibleArea()
+{
+ CPt theUpperLeftCorner;
+ CPt theSize;
+
+ theUpperLeftCorner.x = m_ColorScroller->GetSize().x;
+ theUpperLeftCorner.y = CStudioPreferences::GetHeaderHeight();
+ theSize.x = m_ToggleScroller->GetPosition().x - theUpperLeftCorner.x;
+ theSize.y = ::abs(m_ToggleScroller->GetPosition().y - m_ToggleScroller->GetSize().y)
+ - theUpperLeftCorner.y;
+
+ return CRct(theUpperLeftCorner, theSize);
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.h b/src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.h
new file mode 100644
index 00000000..004bf3b7
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//=============================================================================
+// Prefix
+//=============================================================================
+#ifndef INCLUDED_TIMELINE_TREE_LAYOUT_H
+#define INCLUDED_TIMELINE_TREE_LAYOUT_H 1
+
+#pragma once
+
+//=============================================================================
+// Includes
+//=============================================================================
+#include "Control.h"
+#include "TimelineFilter.h"
+#include "Scroller.h"
+#include <vector>
+
+//=============================================================================
+// Forwards
+//=============================================================================
+class CFlowLayout;
+class CScroller;
+class CFilterToolbar;
+class CTimelineRow;
+class CToggleToolbar;
+class CTimeToolbar;
+class CTimelineControl;
+class IDoc;
+class CRenderer;
+class CToggleBlankControl;
+class CColorBlankControl;
+class CTreeBlankControl;
+
+//=============================================================================
+/**
+ * Class for tree control on the timeline palette.
+ */
+class CTimelineTreeLayout : public CControl, public CScrollListener
+{
+ typedef std::vector<CTimelineRow *> TTimelineRowList;
+
+public:
+ CTimelineTreeLayout(CTimelineControl *inTimelineControl, IDoc *inDoc);
+ virtual ~CTimelineTreeLayout();
+
+ // CControl
+ void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
+ void SetSize(CPt inSize) override;
+
+ virtual void AddRow(CTimelineRow *inRow);
+
+ /// Returns a filter object so that filter preferences can be set. You must call Filter() in
+ /// order to apply the filters once you make your changes.
+ CFilter *GetFilter() { return &m_Filter; }
+ void Filter();
+
+ void OnScroll(CScroller *inScroller, CPt inScrollAmount) override;
+ void SetScrollPositionY(CScroller *inSource, long inPositionY, bool inAbsolute = true);
+
+ void ClearRows();
+
+ void SetTime(long inTime);
+ long GetTime();
+ void ResetFilter();
+ CRct GetVisibleArea();
+ void RecalcLayout();
+
+protected:
+ CFilter m_Filter;
+ CFilterToolbar
+ *m_FilterToolbar; ///< Control at the top of the timeline containing filter buttons.
+ CTimeToolbar *m_TimeToolbar; ///< Control at the top containing the time display
+ CToggleToolbar
+ *m_ToggleToolbar; ///< Control at the top containing a header for the toggle column.
+
+ CScroller *m_ColorScroller;
+ CFlowLayout *m_ColorList;
+ CColorBlankControl *m_ColorBlankControl;
+
+ CScroller *m_ToggleScroller;
+ CFlowLayout *m_ToggleList;
+ CToggleBlankControl *m_ToggleBlankControl;
+
+ CScroller *m_TreeScroller;
+ CFlowLayout *m_TreeList;
+ CTreeBlankControl *m_TreeBlankControl;
+
+ TTimelineRowList m_Rows;
+ CTimelineControl *m_TimelineControl; ///< Parent control of this control
+
+ bool
+ m_IsScrolling; ///< Flag to not process onScroll that was triggered from a previous onScroll
+};
+#endif // INCLUDED_TIMELINE_TREE_LAYOUT_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.cpp b/src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.cpp
new file mode 100644
index 00000000..c9ffff8e
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "ToggleBlankControl.h"
+#include "Renderer.h"
+#include "StudioPreferences.h"
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CToggleBlankControl::CToggleBlankControl(CColor inColor)
+ : CBlankControl(inColor)
+{
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CToggleBlankControl::~CToggleBlankControl()
+{
+}
+
+//=============================================================================
+/**
+ * Handles custom drawing of the blank control underneath the tree control
+ * on the timeline palette.
+ */
+void CToggleBlankControl::Draw(CRenderer *inRenderer)
+{
+ CBlankControl::Draw(inRenderer);
+
+ // Draw the line on the right side of this control
+ CPt theSize = GetSize();
+ inRenderer->PushPen(CStudioPreferences::GetButtonShadowColor());
+ inRenderer->MoveTo(theSize.x - 1, 0);
+ inRenderer->LineTo(theSize.x - 1, theSize.y - 1);
+ inRenderer->PopPen();
+
+ // Draw the line on the left side of this control
+ inRenderer->PushPen(CStudioPreferences::GetPropertyFloorColor());
+ inRenderer->MoveTo(CPt(0, 0));
+ inRenderer->LineTo(CPt(0, theSize.y - 1));
+ inRenderer->PopPen();
+
+ // Draw the highlight
+ inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor());
+ inRenderer->MoveTo(CPt(1, 0));
+ inRenderer->LineTo(CPt(1, theSize.y - 1));
+ inRenderer->PopPen();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.h b/src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.h
new file mode 100644
index 00000000..ac07f7db
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_TOGGLE_BLANK_CONTROL_H
+#define INCLUDED_TOGGLE_BLANK_CONTROL_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "BlankControl.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CRenderer;
+
+//=============================================================================
+/**
+ * Extends the blank control to draw items specific to the tree view side of the
+ * timeline palette.
+ */
+class CToggleBlankControl : public CBlankControl
+{
+public:
+ CToggleBlankControl(CColor inColor = CStudioPreferences::GetBaseColor());
+ virtual ~CToggleBlankControl();
+ void Draw(CRenderer *inRenderer) override;
+
+protected:
+};
+
+#endif // INCLUDED_TOGGLE_BLANK_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/ToggleControl.cpp b/src/Authoring/Studio/Palettes/Timeline/ToggleControl.cpp
new file mode 100644
index 00000000..7abc00d4
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ToggleControl.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "stdafx.h"
+
+#include "ToggleControl.h"
+#include "Renderer.h"
+#include "StateRow.h"
+#include "BlankControl.h"
+#include "HotKeys.h"
+#include "Bindings/ITimelineItemBinding.h"
+
+CToggleControl::CToggleControl(CStateRow *inStateRow, ITimelineItemBinding *inTimelineItemBinding)
+ : CBlankToggleControl(inStateRow)
+ , m_TimelineItemBinding(inTimelineItemBinding)
+{
+ m_StateRow = inStateRow;
+ long theLeftOffset = 4;
+
+ m_Shy = new CToggleButton();
+ m_Shy->SetName("ShyToggle");
+ m_Shy->SetUpImage("Toggle-Empty.png");
+ m_Shy->SetDownImage("Toggle-Shy.png");
+ m_Shy->SetPosition(CPt(theLeftOffset, 0));
+ CPt theShySize = m_Shy->GetSize();
+
+ m_Visible = new CToggleButton();
+ m_Visible->SetName("VisibilityToggle");
+ m_Visible->SetUpImage("Toggle-Empty.png");
+ m_Visible->SetDownImage("Toggle-HideShow.png");
+ m_Visible->SetUpDisabledImage("Toggle-Empty.png"); // show empty if disabled
+ m_Visible->SetDisabledImage("Toggle-HideShow-disabled.png");
+ m_Visible->SetPosition(CPt(theShySize.x + 7, 0));
+ CPt theVisibleSize = m_Visible->GetSize();
+
+ m_Locked = new CToggleButton();
+ m_Locked->SetName("LockToggle");
+ m_Locked->SetUpImage("Toggle-Empty.png");
+ m_Locked->SetDownImage("Toggle-Lock.png");
+ m_Locked->SetPosition(CPt(theVisibleSize.x + theShySize.x + 10, 0));
+ CPt theLockedSize = m_Locked->GetSize();
+
+ AddChild(m_Shy);
+ AddChild(m_Visible);
+ AddChild(m_Locked);
+
+ SetAbsoluteSize(CPt(theShySize.x + theVisibleSize.x + theLockedSize.x + 1, theShySize.y));
+
+ // Button down listeners
+ m_Shy->SigToggle.connect(std::bind(&CToggleControl::OnShyClicked, this,
+ std::placeholders::_1, std::placeholders::_2));
+ m_Visible->SigToggle.connect(std::bind(&CToggleControl::OnVisibleClicked, this,
+ std::placeholders::_1, std::placeholders::_2));
+ m_Locked->SigToggle.connect(std::bind(&CToggleControl::OnLockClicked, this,
+ std::placeholders::_1, std::placeholders::_2));
+
+ ITimelineItem *theTimelineItem = m_TimelineItemBinding->GetTimelineItem();
+ // Initial toggle state of the eye visibility button
+ // Note GetViewToggleOff==FALSE means visible
+ m_Visible->SetToggleState(theTimelineItem->IsVisible());
+
+ // Initial toggle state of the button
+ m_Locked->SetToggleState(theTimelineItem->IsLocked());
+
+ // Initial toggle state of the button
+ m_Shy->SetToggleState(theTimelineItem->IsShy());
+
+ // sk - if anything, this should be checked in the data model level, not here.
+ // The tri-state (on, off, dim) of visibility depends on two bools:
+ // GetViewToggleOff and IsEnabled. Ensure that any bogus 4th permutation
+ // is detected ASAP
+ // ASSERT( !inStateRow->GetState( )->GetViewToggleOff( ) ||
+ // !inStateRow->GetState( )->IsEnabled( ) );
+}
+
+CToggleControl::~CToggleControl()
+{
+ delete m_Shy;
+ delete m_Visible;
+ delete m_Locked;
+}
+
+//==============================================================================
+/**
+ * Handles clicking on the Shy button. Toggles the shy state on the asset. Shy
+ * objects can be filtered out of the timeline.
+ */
+void CToggleControl::OnShyClicked(CToggleButton *, CToggleButton::EButtonState inButtonState)
+{
+ m_TimelineItemBinding->GetTimelineItem()->SetShy(inButtonState
+ == CToggleButton::EBUTTONSTATE_DOWN);
+
+ m_StateRow->Filter(*m_StateRow->GetFilter());
+ CBaseStateRow *theParentRow = m_StateRow->GetParentRow();
+ if (theParentRow != nullptr)
+ theParentRow->OnChildVisibilityChanged();
+}
+
+//==============================================================================
+/**
+ * Handles clicking on the Visible button. Toggles the Visible state on the asset.
+ */
+void CToggleControl::OnVisibleClicked(CToggleButton *inButton,
+ CToggleButton::EButtonState inButtonState)
+{
+ Q_UNUSED(inButton);
+
+ m_TimelineItemBinding->GetTimelineItem()->SetVisible(inButtonState
+ == CToggleButton::EBUTTONSTATE_DOWN);
+ m_StateRow->Filter(*m_StateRow->GetFilter());
+}
+
+//==============================================================================
+/**
+ * Handles clicking on the Lock button. Toggles the Lock state on the asset.
+ */
+void CToggleControl::OnLockClicked(CToggleButton *inButton,
+ CToggleButton::EButtonState inButtonState)
+{
+ Q_UNUSED(inButton);
+
+ m_TimelineItemBinding->GetTimelineItem()->SetLocked(inButtonState
+ == CToggleButton::EBUTTONSTATE_DOWN);
+ m_StateRow->Filter(*m_StateRow->GetFilter());
+}
+
+//==============================================================================
+/**
+ * Refreshes the state of this control accd to the asset state
+ */
+void CToggleControl::Refresh()
+{
+ CBlankToggleControl::Refresh();
+
+ ITimelineItem *theTimelineItem = m_TimelineItemBinding->GetTimelineItem();
+ m_Shy->SetToggleState(theTimelineItem->IsShy());
+ m_Locked->SetToggleState(theTimelineItem->IsLocked());
+
+ bool theEnabled = m_TimelineItemBinding->IsVisibleEnabled();
+ m_Visible->SetEnabled(theEnabled);
+ if (theEnabled) // only valid to update this if the enabled flag is true.
+ m_Visible->SetToggleState(theTimelineItem->IsVisible());
+
+ this->Invalidate();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/ToggleControl.h b/src/Authoring/Studio/Palettes/Timeline/ToggleControl.h
new file mode 100644
index 00000000..49caaff8
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ToggleControl.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_TOGGLE_CONTROL_H
+#define INCLUDED_TOGGLE_CONTROL_H 1
+
+#pragma once
+
+#include "BlankToggleControl.h"
+#include "ToggleButton.h"
+
+class CStateRow;
+class CBlankControl;
+class ITimelineItemBinding;
+
+class CToggleControl : public CBlankToggleControl
+{
+public:
+ CToggleControl(CStateRow *inStateRow, ITimelineItemBinding *inTimelineItemBinding);
+ virtual ~CToggleControl();
+
+ void OnShyClicked(CToggleButton *inButton, CToggleButton::EButtonState inState);
+ void OnVisibleClicked(CToggleButton *inButton, CToggleButton::EButtonState inState);
+ void OnLockClicked(CToggleButton *inButton, CToggleButton::EButtonState inState);
+
+ void Refresh() override;
+
+protected:
+ CStateRow *m_StateRow;
+
+ CToggleButton *m_Shy;
+ CToggleButton *m_Visible;
+ CToggleButton *m_Locked;
+
+ ITimelineItemBinding *m_TimelineItemBinding;
+};
+#endif // INCLUDED_TOGGLE_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.cpp b/src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.cpp
new file mode 100644
index 00000000..7dadde19
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.cpp
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+
+#include "stdafx.h"
+#include "Strings.h"
+#include "StringLoader.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+
+#include "ToggleToolbar.h"
+#include "SIcon.h"
+#include "Renderer.h"
+#include "StudioPreferences.h"
+#include "TimelineTreeLayout.h"
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CToggleToolbar::CToggleToolbar(CTimelineTreeLayout *inTreeLayout)
+ : CFlowLayout(new CBlankControl(CStudioPreferences::GetTopRowColor()))
+{
+ m_TreeLayout = inTreeLayout;
+
+ m_Color = CStudioPreferences::GetBaseColor();
+
+ SetFlowDirection(FLOW_HORIZONTAL);
+ SetAlignment(ALIGN_TOP, ALIGN_LEFT);
+ SetLeftMargin(1);
+
+ CProceduralButton<CToggleButton>::SBorderOptions theBorderOptions(false, true, true, true);
+
+ m_FltrShyBtn = new CProceduralButton<CToggleButton>();
+ m_FltrShyBtn->SetUpImage("Toggle-Shy.png");
+ m_FltrShyBtn->SetDownImage("Toggle-Shy.png");
+ m_FltrShyBtn->SetBorderVisibilityAll(theBorderOptions);
+ m_FltrShyBtn->SetAbsoluteSize(m_FltrShyBtn->GetSize());
+ m_FltrShyBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_SHY2));
+ m_FltrShyBtn->SigToggle.connect(std::bind(&CToggleToolbar::OnButtonToggled, this,
+ std::placeholders::_1, std::placeholders::_2));
+ AddChild(m_FltrShyBtn);
+ m_FltrShyBtn->SetToggleState(false);
+
+ m_FltrVisibleBtn = new CProceduralButton<CToggleButton>();
+ m_FltrVisibleBtn->SetUpImage("filter-toggle-eye-up.png");
+ m_FltrVisibleBtn->SetDownImage("filter-toggle-eye-down.png");
+ m_FltrVisibleBtn->SetBorderVisibilityAll(theBorderOptions);
+ m_FltrVisibleBtn->SetAbsoluteSize(m_FltrVisibleBtn->GetSize());
+ m_FltrVisibleBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_VISIBLE2));
+ m_FltrVisibleBtn->SigToggle.connect(std::bind(&CToggleToolbar::OnButtonToggled, this,
+ std::placeholders::_1, std::placeholders::_2));
+ AddChild(m_FltrVisibleBtn);
+ m_FltrVisibleBtn->SetToggleState(false);
+
+ m_FltrLockBtn = new CProceduralButton<CToggleButton>();
+ m_FltrLockBtn->SetUpImage("Toggle-Lock.png");
+ m_FltrLockBtn->SetDownImage("Toggle-Lock.png");
+ m_FltrLockBtn->SetBorderVisibilityAll(theBorderOptions);
+ m_FltrLockBtn->SetAbsoluteSize(m_FltrLockBtn->GetSize());
+ m_FltrLockBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_LOCK2));
+ m_FltrLockBtn->SigToggle.connect(std::bind(&CToggleToolbar::OnButtonToggled, this,
+ std::placeholders::_1, std::placeholders::_2));
+ AddChild(m_FltrLockBtn);
+ m_FltrLockBtn->SetToggleState(false);
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CToggleToolbar::~CToggleToolbar()
+{
+ delete m_FltrShyBtn;
+ delete m_FltrVisibleBtn;
+ delete m_FltrLockBtn;
+}
+
+//=============================================================================
+/**
+ * Fills in the background color and highlighting for this control.
+ */
+void CToggleToolbar::Draw(CRenderer *inRenderer)
+{
+ CRct theRect(0, 0, GetSize().x, GetSize().y - 1);
+ inRenderer->FillSolidRect(theRect, m_Color);
+ CFlowLayout::Draw(inRenderer);
+ inRenderer->Draw3dRect(theRect, CStudioPreferences::GetButtonShadowColor(),
+ CStudioPreferences::GetButtonShadowColor());
+
+ // Draw the highlight at the bottom
+ inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor());
+ inRenderer->MoveTo(CPt(0, theRect.size.y));
+ inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y));
+ inRenderer->PopPen();
+
+ // Draw the one pixel on the end of the highlight that has to be dark
+ // Apparently there's some problems trying to draw one pixel, so clip the excess
+ inRenderer->PushClippingRect(QRect(0, 0, GetSize().x, GetSize().y));
+ inRenderer->PushPen(CStudioPreferences::GetButtonShadowColor());
+ inRenderer->MoveTo(CPt(theRect.size.x, theRect.size.y));
+ inRenderer->LineTo(CPt(theRect.size.x - 1, theRect.size.y));
+ inRenderer->PopPen();
+ inRenderer->PopClippingRect();
+}
+
+//=============================================================================
+/**
+ * Handles turning a filter on or off in response to a button being pressed.
+ * @param inButton button that generated the event
+ * @param inState new state of the button after being toggled
+ */
+void CToggleToolbar::OnButtonToggled(CToggleButton *inButton, CButtonControl::EButtonState inState)
+{
+ bool theFilterNeedsApplied = (inState == CButtonControl::EBUTTONSTATE_UP);
+
+ if (inButton == m_FltrShyBtn)
+ FilterShy(theFilterNeedsApplied);
+ else if (inButton == m_FltrVisibleBtn)
+ FilterVisible(theFilterNeedsApplied);
+ else if (inButton == m_FltrLockBtn)
+ FilterLocked(theFilterNeedsApplied);
+}
+
+//=============================================================================
+/**
+ * Turns filtering on and off for shy objects.
+ * @param inFilter true to filter shy objects out of the timeline, false to show
+ * shy objects in the timeline.
+ */
+void CToggleToolbar::FilterShy(bool inFilter)
+{
+ if (inFilter)
+ m_FltrShyBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_SHY2));
+ else
+ m_FltrShyBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_SHY1));
+
+ m_TreeLayout->GetFilter()->SetShy(inFilter);
+ m_TreeLayout->Filter();
+}
+
+//=============================================================================
+/**
+ * Turns filtering on and off for visible objects.
+ * @param inFilter true to filter visible objects out of the timeline, false to show
+ * visible objects in the timeline.
+ */
+void CToggleToolbar::FilterVisible(bool inFilter)
+{
+ if (inFilter)
+ m_FltrVisibleBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_VISIBLE2));
+ else
+ m_FltrVisibleBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_VISIBLE1));
+
+ m_TreeLayout->GetFilter()->SetVisible(inFilter);
+ m_TreeLayout->Filter();
+}
+
+//=============================================================================
+/**
+ * Turns filtering on and off for locked objects.
+ * @param inFilter true to filter locked objects out of the timeline, false to show
+ * locked objects in the timeline.
+ */
+void CToggleToolbar::FilterLocked(bool inFilter)
+{
+ if (inFilter)
+ m_FltrLockBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_LOCK2));
+ else
+ m_FltrLockBtn->SetTooltipText(::LoadResourceString(IDS_FLTR_TOOLTIP_LOCK1));
+
+ m_TreeLayout->GetFilter()->SetLocked(inFilter);
+ m_TreeLayout->Filter();
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.h b/src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.h
new file mode 100644
index 00000000..a0f95e62
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+
+#ifndef INCLUDED_TOGGLE_TOOLBAR_H
+#define INCLUDED_TOGGLE_TOOLBAR_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+
+#include "FlowLayout.h"
+#include "ProceduralButton.h"
+#include "ToggleButton.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+
+class CRenderer;
+class CTimelineTreeLayout;
+// class CSIcon;
+
+//=============================================================================
+/**
+ * Control at the top of the time display and a header for the toggle column.
+ */
+class CToggleToolbar : public CFlowLayout
+{
+public:
+ CToggleToolbar(CTimelineTreeLayout *inTreeLayout);
+ virtual ~CToggleToolbar();
+ void Draw(CRenderer *inRenderer) override;
+
+ void FilterShy(bool inFilter);
+ void FilterVisible(bool inFilter);
+ void FilterLocked(bool inFilter);
+ void OnButtonToggled(CToggleButton *inButton, CToggleButton::EButtonState inState);
+
+protected:
+ // CSIcon* m_ShyIcon;
+ // CSIcon* m_VisibilityIcon;
+ // CSIcon* m_LockIcon;
+ CProceduralButton<CToggleButton> *m_FltrShyBtn;
+ CProceduralButton<CToggleButton> *m_FltrVisibleBtn;
+ CProceduralButton<CToggleButton> *m_FltrLockBtn;
+ CTimelineTreeLayout *m_TreeLayout;
+ CColor m_Color;
+};
+
+#endif // INCLUDED_TOGGLE_TOOLBAR_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.cpp b/src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.cpp
new file mode 100644
index 00000000..b49eabb5
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//==============================================================================
+// Prefix
+//==============================================================================
+#include "stdafx.h"
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "TreeBlankControl.h"
+#include "Renderer.h"
+
+//=============================================================================
+/**
+ * Constructor
+ */
+CTreeBlankControl::CTreeBlankControl(CColor inColor)
+ : CBlankControl(inColor)
+ , m_LeftEdgeOffset(0)
+{
+}
+
+//=============================================================================
+/**
+ * Destructor
+ */
+CTreeBlankControl::~CTreeBlankControl()
+{
+}
+
+//=============================================================================
+/**
+ * Handles custom drawing of the blank control underneath the tree control
+ * on the timeline palette.
+ */
+void CTreeBlankControl::Draw(CRenderer *inRenderer)
+{
+ CBlankControl::Draw(inRenderer);
+
+ // Draw the highlight on the left side of this control
+ CPt theSize = GetSize();
+ inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor());
+ inRenderer->MoveTo(CStudioPreferences::GetRowSize() + m_LeftEdgeOffset, 0);
+ inRenderer->LineTo(CStudioPreferences::GetRowSize() + m_LeftEdgeOffset, theSize.y - 1);
+ inRenderer->PopPen();
+}
+
+//=============================================================================
+/**
+ * xxx
+ */
+void CTreeBlankControl::SetVisiblePositionX(long inPosition)
+{
+ m_LeftEdgeOffset = inPosition;
+} \ No newline at end of file
diff --git a/src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.h b/src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.h
new file mode 100644
index 00000000..0d0df3ab
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2002 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDED_TREE_BLANK_CONTROL_H
+#define INCLUDED_TREE_BLANK_CONTROL_H 1
+
+#pragma once
+
+//==============================================================================
+// Includes
+//==============================================================================
+#include "BlankControl.h"
+
+//==============================================================================
+// Forwards
+//==============================================================================
+class CRenderer;
+
+//=============================================================================
+/**
+ * Extends the blank control to draw items specific to the tree view side of the
+ * timeline palette.
+ */
+class CTreeBlankControl : public CBlankControl
+{
+public:
+ CTreeBlankControl(CColor inColor = CStudioPreferences::GetBaseColor());
+ virtual ~CTreeBlankControl();
+ void Draw(CRenderer *inRenderer) override;
+ void SetVisiblePositionX(long inPosition);
+
+protected:
+ long m_LeftEdgeOffset; ///< Visibility offset of the left edge in case timeline is scrolled
+ ///horizontally
+};
+
+#endif // INCLUDED_TREE_BLANK_CONTROL_H
diff --git a/src/Authoring/Studio/Palettes/controls/BrowserCombo.qml b/src/Authoring/Studio/Palettes/controls/BrowserCombo.qml
new file mode 100644
index 00000000..0e8bcb55
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/controls/BrowserCombo.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.8
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+
+MouseArea {
+ id: root
+
+ property alias value: value.text
+ property var activeBrowser
+ property bool blockShow: false
+
+ signal showBrowser
+
+ Layout.minimumHeight: _controlBaseHeight
+ Layout.preferredWidth: _valueWidth
+
+ onPressed: {
+ // Block showBrowser event on the mouse press that makes the browser lose focus
+ if (activeBrowser && activeBrowser.visible) {
+ activeBrowser = null;
+ blockShow = true
+ } else {
+ blockShow = false
+ }
+ }
+
+ onClicked: {
+ if (!blockShow)
+ root.showBrowser()
+ }
+
+ Rectangle {
+ anchors.fill: parent
+
+ color: _studioColor2
+
+ StyledLabel {
+ id: value
+ anchors.fill: parent
+ horizontalAlignment: Text.AlignLeft
+ rightPadding: 6 + img.width
+ leftPadding: 6
+ }
+ Image {
+ id: img
+ x: parent.width - sourceSize.width - 2
+ y: (parent.height - sourceSize.height) / 2
+ source: _resDir + "arrow_down.png"
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/controls/FloatTextField.qml b/src/Authoring/Studio/Palettes/controls/FloatTextField.qml
new file mode 100644
index 00000000..bea65443
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/controls/FloatTextField.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+
+/* Use for: Position, Rotation, Scale, Pivot ... */
+
+TextField {
+ id: floatTextFieldId
+ property alias decimalValue: validator.decimals
+
+ signal wheelEventFinished
+
+ selectByMouse: true
+ text: "0.000"
+ Layout.preferredWidth: _valueWidth / 2
+ Layout.preferredHeight: _controlBaseHeight
+
+ topPadding: 0
+ bottomPadding: 0
+ rightPadding: 6
+
+ horizontalAlignment: TextInput.AlignRight
+ verticalAlignment: TextInput.AlignVCenter
+ validator: DoubleValidator {
+ id: validator
+ decimals: 3
+ locale: "C"
+ }
+
+ selectionColor: _selectionColor
+ selectedTextColor: _textColor
+ font.pixelSize: _fontSize
+ color: _textColor
+ background: Rectangle {
+ color: floatTextFieldId.enabled ? _studioColor2 : "transparent"
+ border.width: floatTextFieldId.activeFocus ? 1 : 0
+ border.color: floatTextFieldId.activeFocus ? _selectionColor : _disabledColor
+ }
+
+ MouseArea {
+ property int _clickedPos
+ id: mouseAreaBaseId
+
+ anchors.fill: parent
+ onPressed: {
+ parent.forceActiveFocus()
+ _clickedPos = parent.positionAt(mouse.x, mouse.y)
+ parent.cursorPosition = _clickedPos
+ }
+ onDoubleClicked: parent.selectAll()
+ onPositionChanged: {
+ parent.cursorPosition = parent.positionAt(mouse.x, mouse.y)
+ parent.select(_clickedPos, parent.cursorPosition)
+ }
+
+ onWheel: {
+ if (!floatTextFieldId.activeFocus) {
+ wheel.accepted = false
+ return
+ }
+ if (wheel.angleDelta.y > 0) {
+ floatTextFieldId.text++
+ } else {
+ floatTextFieldId.text--
+ }
+ wheel.accepted=true
+ floatTextFieldId.wheelEventFinished();
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/controls/StyledComboBox.qml b/src/Authoring/Studio/Palettes/controls/StyledComboBox.qml
new file mode 100644
index 00000000..ff079f41
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/controls/StyledComboBox.qml
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.2
+import QtQuick.Layouts 1.3
+import QtQuick.Window 2.2
+
+ComboBox {
+ id: control
+ Layout.preferredHeight: _controlBaseHeight
+ Layout.preferredWidth: _valueWidth
+ topPadding: 0
+ bottomPadding: 0
+
+ delegate: ItemDelegate {
+ id: itemDelegate
+
+ property bool hasSeparator: itemDelegate.text.endsWith("|separator")
+
+ width: parent.width
+ height: hasSeparator ? _controlBaseHeight + 6 : _controlBaseHeight
+ padding: 0
+ spacing: 0
+ text: {
+ control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole]
+ : model[control.textRole])
+ : modelData
+ }
+ highlighted: control.highlightedIndex === index
+ hoverEnabled: control.hoverEnabled
+ contentItem: ColumnLayout {
+ anchors.fill: itemDelegate
+ spacing: 0
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 1
+ color: _studioColor3
+ visible: itemDelegate.hasSeparator
+ }
+ StyledLabel {
+ Layout.fillWidth: true
+ rightPadding: control.indicator.width + 6
+ leftPadding: 6
+ text: {
+ hasSeparator ? itemDelegate.text.replace("|separator", "")
+ : itemDelegate.text
+ }
+ visible: itemDelegate.text
+ horizontalAlignment: Text.AlignLeft
+ }
+ }
+ background: Rectangle {
+ anchors.fill: itemDelegate
+ color: hovered ? _selectionColor : _studioColor2
+ }
+ }
+
+ indicator: Image {
+ x: control.width - width - 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ source: _resDir + "arrow_down.png"
+ sourceSize.width: width
+ sourceSize.height: height
+ }
+
+ contentItem: StyledTextField {
+ text: {
+ var newText = control.editable ? control.editText : control.displayText;
+ var hasSeparator = newText.endsWith("|separator");
+ hasSeparator ? newText.replace("|separator", "") : newText;
+ }
+
+ enabled: control.editable
+ autoScroll: control.editable
+ readOnly: control.popup.visible
+ inputMethodHints: control.inputMethodHints
+ validator: control.validator
+ opacity: 1
+ leftPadding: 6
+ horizontalAlignment: Text.AlignLeft
+ }
+
+ background: Rectangle {
+ color: control.enabled ? _studioColor2 : "transparent"
+ border.width: 0
+ }
+
+ popup: Popup {
+ y: control.height
+ width: control.width
+ height: Math.min(contentItem.implicitHeight,
+ control.Window.height - topMargin - bottomMargin)
+ topMargin: 6
+ bottomMargin: 6
+ padding: 0
+
+ contentItem: ListView {
+ clip: true
+ implicitHeight: contentHeight
+ model: control.popup.visible ? control.delegateModel : null
+ currentIndex: control.highlightedIndex
+ highlightRangeMode: ListView.ApplyRange
+ highlightMoveDuration: 0
+ ScrollIndicator.vertical: ScrollIndicator {
+ id: scrollIndicator
+ contentItem: Rectangle {
+ id: indicator
+
+ implicitWidth: 2
+ implicitHeight: 2
+
+ color: _studioColor3
+ visible: scrollIndicator.size < 1.0
+ opacity: 0.75
+ }
+ }
+ Rectangle {
+ z: 10
+ anchors.fill: parent
+ color: "transparent"
+ border.color: _studioColor3
+ }
+ }
+
+ background: Rectangle {
+ color: _studioColor2
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/controls/StyledLabel.qml b/src/Authoring/Studio/Palettes/controls/StyledLabel.qml
new file mode 100644
index 00000000..02016069
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/controls/StyledLabel.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+
+Label {
+ id: styledLabelId
+ font.pixelSize: _fontSize
+ color: _textColor
+ Layout.preferredHeight: _controlBaseHeight
+ Layout.preferredWidth: _idWidth
+ verticalAlignment: Text.AlignVCenter
+ clip: true
+}
diff --git a/src/Authoring/Studio/Palettes/controls/StyledMenuItem.qml b/src/Authoring/Studio/Palettes/controls/StyledMenuItem.qml
new file mode 100644
index 00000000..361d5876
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/controls/StyledMenuItem.qml
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+
+MenuItem {
+ id: control
+ hoverEnabled: true
+
+ contentItem: StyledLabel {
+ text: control.text
+ visible: control.text
+ horizontalAlignment: Text.AlignLeft
+ color: control.enabled ? _textColor : _disabledColor
+ }
+ background: Rectangle {
+ implicitWidth: _valueWidth
+ implicitHeight: _controlBaseHeight
+ color: control.hovered ? _selectionColor : _studioColor1
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/controls/StyledMenuSeparator.qml b/src/Authoring/Studio/Palettes/controls/StyledMenuSeparator.qml
new file mode 100644
index 00000000..532fee2c
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/controls/StyledMenuSeparator.qml
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+
+MenuSeparator {
+ id: control
+ padding: 0
+ topPadding: 4
+ bottomPadding: 4
+ leftPadding: 0
+ rightPadding: 0
+ contentItem: Rectangle {
+ width: control.width
+ implicitWidth: control.parent.width - control.leftPadding - control.rightPadding
+ implicitHeight: 1
+ color: _studioColor3
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/controls/StyledTextField.qml b/src/Authoring/Studio/Palettes/controls/StyledTextField.qml
new file mode 100644
index 00000000..da621314
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/controls/StyledTextField.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+import QtQuick.Layouts 1.3
+
+TextField {
+ id: styledTextFieldId
+
+ property alias backgroundColor: textBackground.color
+
+ Layout.preferredWidth: _valueWidth
+ Layout.preferredHeight: _controlBaseHeight
+ horizontalAlignment: TextInput.AlignRight
+ verticalAlignment: TextInput.AlignVCenter
+
+ topPadding: 0
+ bottomPadding: 0
+ rightPadding: 6
+
+ selectByMouse: true
+ selectionColor: _selectionColor
+ selectedTextColor: _textColor
+
+ font.pixelSize: _fontSize
+ color: _textColor
+ background: Rectangle {
+ id: textBackground
+ color: styledTextFieldId.enabled ? _studioColor2 : "transparent"
+ border.width: styledTextFieldId.activeFocus ? 1 : 0
+ border.color: styledTextFieldId.activeFocus ? _selectionColor : _disabledColor
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/controls/StyledToolButton.qml b/src/Authoring/Studio/Palettes/controls/StyledToolButton.qml
new file mode 100644
index 00000000..51654331
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/controls/StyledToolButton.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+
+ToolButton {
+ id: control
+
+ property string enabledImage
+ property string disabledImage
+ property alias toolTipText: toolTip.text
+
+ hoverEnabled: true
+
+ StyledTooltip {
+ id: toolTip
+ visible: control.hovered
+ }
+
+ background: Rectangle {
+ color: control.pressed ? _selectionColor : (hovered ? _studioColor1 : "transparent")
+ border.color: _studioColor1
+ }
+
+ contentItem: Image {
+ source: control.enabled ? _resDir + enabledImage : _resDir + disabledImage
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/controls/StyledTooltip.qml b/src/Authoring/Studio/Palettes/controls/StyledTooltip.qml
new file mode 100644
index 00000000..cae9c59f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/controls/StyledTooltip.qml
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import QtQuick.Controls 2.1
+
+ToolTip {
+ id: control
+ delay: 500
+ contentItem: StyledLabel {
+ text: control.text
+ }
+
+ background: Rectangle {
+ border.color: _studioColor3
+ color: _studioColor2
+ radius: 2
+ }
+}