From 07840524085bd1785b8f9142b03d942f678c5c51 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 6 Oct 2017 11:49:09 +0000 Subject: Initial import --- src/Authoring/Studio/Application/MsgRouter.h | 125 + src/Authoring/Studio/Application/StudioConst.h | 158 + src/Authoring/Studio/Application/StudioDefs.h | 44 + .../Studio/Application/StudioInstance.cpp | 86 + src/Authoring/Studio/Application/StudioInstance.h | 49 + .../Studio/Application/StudioTutorialWidget.cpp | 236 ++ .../Studio/Application/StudioTutorialWidget.h | 94 + .../Studio/Application/StudioTutorialWidget.ui | 184 + src/Authoring/Studio/Controls/BaseMeasure.cpp | 206 ++ src/Authoring/Studio/Controls/BaseMeasure.h | 81 + src/Authoring/Studio/Controls/BlankControl.cpp | 118 + src/Authoring/Studio/Controls/BlankControl.h | 57 + .../Studio/Controls/BreadCrumbControl.cpp | 326 ++ src/Authoring/Studio/Controls/BreadCrumbControl.h | 94 + src/Authoring/Studio/Controls/ButtonControl.cpp | 425 +++ src/Authoring/Studio/Controls/ButtonControl.h | 124 + src/Authoring/Studio/Controls/ClickableLabel.cpp | 51 + src/Authoring/Studio/Controls/ClickableLabel.h | 48 + src/Authoring/Studio/Controls/ComboTextBox.h | 65 + src/Authoring/Studio/Controls/Control.cpp | 1806 +++++++++ src/Authoring/Studio/Controls/Control.h | 263 ++ src/Authoring/Studio/Controls/ControlData.cpp | 763 ++++ src/Authoring/Studio/Controls/ControlData.h | 276 ++ src/Authoring/Studio/Controls/ControlGraph.cpp | 188 + src/Authoring/Studio/Controls/ControlGraph.h | 68 + .../Studio/Controls/ControlGraphIterators.h | 156 + src/Authoring/Studio/Controls/EditInPlace.h | 280 ++ src/Authoring/Studio/Controls/FloatEdit.cpp | 524 +++ src/Authoring/Studio/Controls/FloatEdit.h | 115 + src/Authoring/Studio/Controls/FlowLayout.cpp | 1009 ++++++ src/Authoring/Studio/Controls/FlowLayout.h | 140 + .../Studio/Controls/GenericComboDropDown.h | 99 + src/Authoring/Studio/Controls/GenericEdit.h | 94 + src/Authoring/Studio/Controls/InsertionLine.cpp | 142 + src/Authoring/Studio/Controls/InsertionLine.h | 76 + src/Authoring/Studio/Controls/InsertionOverlay.cpp | 112 + src/Authoring/Studio/Controls/InsertionOverlay.h | 74 + src/Authoring/Studio/Controls/LazyFlow.cpp | 318 ++ src/Authoring/Studio/Controls/LazyFlow.h | 267 ++ src/Authoring/Studio/Controls/ListBoxItem.cpp | 277 ++ src/Authoring/Studio/Controls/ListBoxItem.h | 101 + .../Studio/Controls/ListBoxStringItem.cpp | 108 + src/Authoring/Studio/Controls/ListBoxStringItem.h | 72 + src/Authoring/Studio/Controls/ListLayout.cpp | 185 + src/Authoring/Studio/Controls/ListLayout.h | 60 + src/Authoring/Studio/Controls/NameEdit.cpp | 138 + src/Authoring/Studio/Controls/NameEdit.h | 70 + src/Authoring/Studio/Controls/OverlayControl.cpp | 240 ++ src/Authoring/Studio/Controls/OverlayControl.h | 83 + src/Authoring/Studio/Controls/ProceduralButton.h | 569 +++ src/Authoring/Studio/Controls/Renderer.cpp | 74 + src/Authoring/Studio/Controls/Renderer.h | 105 + src/Authoring/Studio/Controls/SIcon.cpp | 165 + src/Authoring/Studio/Controls/SIcon.h | 74 + src/Authoring/Studio/Controls/ScrollController.cpp | 211 ++ src/Authoring/Studio/Controls/ScrollController.h | 82 + src/Authoring/Studio/Controls/Scroller.cpp | 829 +++++ src/Authoring/Studio/Controls/Scroller.h | 171 + .../Studio/Controls/ScrollerBackground.cpp | 202 ++ src/Authoring/Studio/Controls/ScrollerBackground.h | 69 + src/Authoring/Studio/Controls/ScrollerBar.cpp | 333 ++ src/Authoring/Studio/Controls/ScrollerBar.h | 120 + .../Studio/Controls/ScrollerButtonControl.cpp | 97 + .../Studio/Controls/ScrollerButtonControl.h | 76 + src/Authoring/Studio/Controls/ScrollerThumb.cpp | 197 + src/Authoring/Studio/Controls/ScrollerThumb.h | 76 + src/Authoring/Studio/Controls/SplashControl.cpp | 107 + src/Authoring/Studio/Controls/SplashControl.h | 70 + src/Authoring/Studio/Controls/SplitBar.cpp | 205 ++ src/Authoring/Studio/Controls/SplitBar.h | 97 + src/Authoring/Studio/Controls/Splitter.cpp | 419 +++ src/Authoring/Studio/Controls/Splitter.h | 74 + src/Authoring/Studio/Controls/StringEdit.cpp | 246 ++ src/Authoring/Studio/Controls/StringEdit.h | 73 + src/Authoring/Studio/Controls/TextButton.h | 350 ++ src/Authoring/Studio/Controls/TextEdit.cpp | 1478 ++++++++ src/Authoring/Studio/Controls/TextEdit.h | 215 ++ .../Studio/Controls/TextEditContextMenu.cpp | 135 + .../Studio/Controls/TextEditContextMenu.h | 77 + src/Authoring/Studio/Controls/TextEditInPlace.cpp | 324 ++ src/Authoring/Studio/Controls/TextEditInPlace.h | 92 + src/Authoring/Studio/Controls/TimeEdit.cpp | 195 + src/Authoring/Studio/Controls/TimeEdit.h | 81 + src/Authoring/Studio/Controls/ToggleButton.cpp | 140 + src/Authoring/Studio/Controls/ToggleButton.h | 89 + src/Authoring/Studio/Controls/TreeControl.cpp | 749 ++++ src/Authoring/Studio/Controls/TreeControl.h | 140 + src/Authoring/Studio/Controls/TreeItem.cpp | 939 +++++ src/Authoring/Studio/Controls/TreeItem.h | 158 + src/Authoring/Studio/Controls/WidgetControl.cpp | 439 +++ src/Authoring/Studio/Controls/WidgetControl.h | 110 + src/Authoring/Studio/Docs/CmdLineOptions.txt | 27 + .../Studio/DragAndDrop/BasicObjectDropSource.cpp | 266 ++ .../Studio/DragAndDrop/BasicObjectDropSource.h | 64 + src/Authoring/Studio/DragAndDrop/DropContainer.cpp | 96 + src/Authoring/Studio/DragAndDrop/DropContainer.h | 81 + src/Authoring/Studio/DragAndDrop/DropSource.cpp | 131 + src/Authoring/Studio/DragAndDrop/DropSource.h | 100 + src/Authoring/Studio/DragAndDrop/DropTarget.cpp | 57 + src/Authoring/Studio/DragAndDrop/DropTarget.h | 67 + .../Studio/DragAndDrop/ExplorerFileDropSource.cpp | 123 + .../Studio/DragAndDrop/ExplorerFileDropSource.h | 70 + .../Studio/DragAndDrop/FileDropSource.cpp | 199 + src/Authoring/Studio/DragAndDrop/FileDropSource.h | 74 + .../Studio/DragAndDrop/ListBoxDropSource.cpp | 83 + .../Studio/DragAndDrop/ListBoxDropSource.h | 60 + .../Studio/DragAndDrop/ListBoxDropTarget.cpp | 116 + .../Studio/DragAndDrop/ListBoxDropTarget.h | 65 + .../Studio/DragAndDrop/ProjectDropTarget.cpp | 229 ++ .../Studio/DragAndDrop/ProjectDropTarget.h | 62 + .../Studio/DragAndDrop/SceneDropTarget.cpp | 242 ++ src/Authoring/Studio/DragAndDrop/SceneDropTarget.h | 67 + .../Studio/DragAndDrop/TimelineDropSource.cpp | 167 + .../Studio/DragAndDrop/TimelineDropSource.h | 66 + .../Studio/DragAndDrop/TimelineDropTarget.cpp | 230 ++ .../Studio/DragAndDrop/TimelineDropTarget.h | 88 + .../Studio/English.lproj/Strings/Static.stri | Bin 0 -> 50010 bytes .../Studio/English.lproj/Strings/Static.stro | Bin 0 -> 48720 bytes .../Studio/English.lproj/Strings/Strings.h | 301 ++ .../Studio/English.lproj/Strings/StringsReadme.htm | 124 + .../Studio/English.lproj/Strings/compile.py | 245 ++ .../Studio/English.lproj/Strings/compile32.py | 272 ++ src/Authoring/Studio/MainFrm.cpp | 2049 +++++++++++ src/Authoring/Studio/MainFrm.h | 249 ++ src/Authoring/Studio/MainFrm.qrc | 83 + src/Authoring/Studio/MainFrm.ui | 799 ++++ .../Studio/Palettes/Action/ActionContextMenu.cpp | 76 + .../Studio/Palettes/Action/ActionContextMenu.h | 58 + .../Studio/Palettes/Action/ActionModel.cpp | 225 ++ src/Authoring/Studio/Palettes/Action/ActionModel.h | 77 + .../Studio/Palettes/Action/ActionView.cpp | 848 +++++ src/Authoring/Studio/Palettes/Action/ActionView.h | 201 + .../Studio/Palettes/Action/ActionView.qml | 426 +++ .../Studio/Palettes/Action/EventsBrowser.qml | 163 + .../Studio/Palettes/Action/EventsBrowserView.cpp | 99 + .../Studio/Palettes/Action/EventsBrowserView.h | 70 + .../Studio/Palettes/Action/EventsModel.cpp | 262 ++ src/Authoring/Studio/Palettes/Action/EventsModel.h | 96 + .../Studio/Palettes/Action/HandlerEmitSignal.qml | 51 + .../Studio/Palettes/Action/HandlerFireEvent.qml | 55 + .../Palettes/Action/HandlerGenericBaseColor.qml | 80 + .../Palettes/Action/HandlerGenericCheckbox.qml | 59 + .../Studio/Palettes/Action/HandlerGenericColor.qml | 53 + .../Studio/Palettes/Action/HandlerGenericText.qml | 53 + .../Studio/Palettes/Action/HandlerGoToSlide.qml | 62 + .../Palettes/Action/HandlerMultilineText.qml | 84 + .../Studio/Palettes/Action/HandlerProperty.qml | 255 ++ .../Palettes/Action/HandlerPropertyBaseSlider.qml | 164 + .../Palettes/Action/HandlerPropertyBaseXYZ.qml | 91 + .../Palettes/Action/HandlerPropertyCombo.qml | 55 + .../Palettes/Action/HandlerPropertySlider.qml | 64 + .../Studio/Palettes/Action/HandlerPropertyXYZ.qml | 63 + .../Studio/Palettes/Action/PropertyModel.cpp | 219 ++ .../Studio/Palettes/Action/PropertyModel.h | 80 + .../Palettes/BasicObjects/BasicObjectsModel.cpp | 119 + .../Palettes/BasicObjects/BasicObjectsModel.h | 99 + .../Palettes/BasicObjects/BasicObjectsView.cpp | 74 + .../Palettes/BasicObjects/BasicObjectsView.h | 52 + .../Palettes/BasicObjects/BasicObjectsView.qml | 88 + .../Studio/Palettes/Inspector/ChooserDelegate.qml | 81 + .../Studio/Palettes/Inspector/ChooserModelBase.cpp | 592 +++ .../Studio/Palettes/Inspector/ChooserModelBase.h | 119 + .../Palettes/Inspector/EasyInspectorGroup.cpp | 56 + .../Studio/Palettes/Inspector/EasyInspectorGroup.h | 58 + .../Studio/Palettes/Inspector/FileChooser.qml | 65 + .../Studio/Palettes/Inspector/FileChooserModel.cpp | 50 + .../Studio/Palettes/Inspector/FileChooserModel.h | 46 + .../Studio/Palettes/Inspector/FileChooserView.cpp | 108 + .../Studio/Palettes/Inspector/FileChooserView.h | 67 + .../Studio/Palettes/Inspector/GuideInspectable.cpp | 322 ++ .../Studio/Palettes/Inspector/GuideInspectable.h | 86 + .../Palettes/Inspector/HandlerFilesChooser.qml | 48 + .../Palettes/Inspector/HandlerGenericChooser.qml | 47 + .../Palettes/Inspector/IEasyInspectorRowListener.h | 48 + .../Studio/Palettes/Inspector/IInspectableItem.h | 211 ++ .../Studio/Palettes/Inspector/ImageChooser.qml | 65 + .../Palettes/Inspector/ImageChooserModel.cpp | 49 + .../Studio/Palettes/Inspector/ImageChooserModel.h | 47 + .../Studio/Palettes/Inspector/ImageChooserView.cpp | 117 + .../Studio/Palettes/Inspector/ImageChooserView.h | 67 + .../Studio/Palettes/Inspector/InspectableBase.cpp | 38 + .../Studio/Palettes/Inspector/InspectableBase.h | 67 + .../Palettes/Inspector/InspectorControlModel.cpp | 862 +++++ .../Palettes/Inspector/InspectorControlModel.h | 180 + .../Palettes/Inspector/InspectorControlView.cpp | 429 +++ .../Palettes/Inspector/InspectorControlView.h | 125 + .../Palettes/Inspector/InspectorControlView.qml | 771 ++++ .../Studio/Palettes/Inspector/InspectorGroup.cpp | 61 + .../Studio/Palettes/Inspector/InspectorGroup.h | 67 + .../Studio/Palettes/Inspector/MeshChooser.qml | 63 + .../Studio/Palettes/Inspector/MeshChooserModel.cpp | 64 + .../Studio/Palettes/Inspector/MeshChooserModel.h | 47 + .../Studio/Palettes/Inspector/MeshChooserView.cpp | 131 + .../Studio/Palettes/Inspector/MeshChooserView.h | 68 + .../Studio/Palettes/Inspector/ObjectBrowser.qml | 175 + .../Palettes/Inspector/ObjectBrowserView.cpp | 117 + .../Studio/Palettes/Inspector/ObjectBrowserView.h | 94 + .../Studio/Palettes/Inspector/ObjectListModel.cpp | 336 ++ .../Studio/Palettes/Inspector/ObjectListModel.h | 120 + .../Studio/Palettes/Inspector/ObjectReference.qml | 41 + .../Palettes/Inspector/ObjectReferenceModel.cpp | 53 + .../Palettes/Inspector/ObjectReferenceModel.h | 45 + .../Palettes/Inspector/ObjectReferenceView.cpp | 101 + .../Palettes/Inspector/ObjectReferenceView.h | 65 + .../Studio/Palettes/Inspector/TabOrderHandler.cpp | 120 + .../Studio/Palettes/Inspector/TabOrderHandler.h | 65 + .../Studio/Palettes/Inspector/TextureChooser.qml | 70 + .../Palettes/Inspector/TextureChooserView.cpp | 107 + .../Studio/Palettes/Inspector/TextureChooserView.h | 67 + .../Studio/Palettes/Inspector/UICDMInspectable.cpp | 325 ++ .../Studio/Palettes/Inspector/UICDMInspectable.h | 77 + .../Palettes/Inspector/UICDMInspectorGroup.cpp | 83 + .../Palettes/Inspector/UICDMInspectorGroup.h | 78 + .../Palettes/Inspector/UICDMInspectorRow.cpp | 75 + .../Studio/Palettes/Inspector/UICDMInspectorRow.h | 92 + .../Inspector/UICDMMaterialInspectable.cpp | 226 ++ .../Palettes/Inspector/UICDMMaterialInspectable.h | 60 + .../Palettes/Inspector/UICDMSceneInspectable.cpp | 77 + .../Palettes/Inspector/UICDMSceneInspectable.h | 66 + .../Studio/Palettes/Master/MasterControl.cpp | 295 ++ .../Studio/Palettes/Master/MasterControl.h | 114 + .../Studio/Palettes/Master/MasterView.cpp | 154 + src/Authoring/Studio/Palettes/Master/MasterView.h | 78 + .../Studio/Palettes/Progress/ProgressCallback.h | 57 + .../Studio/Palettes/Progress/ProgressControl.cpp | 133 + .../Studio/Palettes/Progress/ProgressControl.h | 72 + .../Studio/Palettes/Project/ProjectContextMenu.cpp | 81 + .../Studio/Palettes/Project/ProjectContextMenu.h | 53 + .../Palettes/Project/ProjectFileSystemModel.cpp | 587 +++ .../Palettes/Project/ProjectFileSystemModel.h | 107 + .../Studio/Palettes/Project/ProjectView.cpp | 250 ++ .../Studio/Palettes/Project/ProjectView.h | 102 + .../Studio/Palettes/Project/ProjectView.qml | 231 ++ .../Studio/Palettes/Slide/SlideContextMenu.cpp | 71 + .../Studio/Palettes/Slide/SlideContextMenu.h | 53 + src/Authoring/Studio/Palettes/Slide/SlideModel.cpp | 273 ++ src/Authoring/Studio/Palettes/Slide/SlideModel.h | 81 + src/Authoring/Studio/Palettes/Slide/SlideView.cpp | 315 ++ src/Authoring/Studio/Palettes/Slide/SlideView.h | 113 + src/Authoring/Studio/Palettes/Slide/SlideView.qml | 249 ++ .../Studio/Palettes/Timeline/AreaBoundingRect.cpp | 64 + .../Studio/Palettes/Timeline/AreaBoundingRect.h | 53 + .../Palettes/Timeline/AssetTimelineKeyframe.cpp | 440 +++ .../Palettes/Timeline/AssetTimelineKeyframe.h | 110 + .../Studio/Palettes/Timeline/BaseStateRow.cpp | 1139 ++++++ .../Studio/Palettes/Timeline/BaseStateRow.h | 205 ++ .../Palettes/Timeline/BaseTimebarlessRow.cpp | 186 + .../Studio/Palettes/Timeline/BaseTimebarlessRow.h | 80 + .../Palettes/Timeline/BaseTimelineTreeControl.cpp | 685 ++++ .../Palettes/Timeline/BaseTimelineTreeControl.h | 125 + .../Bindings/BehaviorTimelineItemBinding.cpp | 65 + .../Bindings/BehaviorTimelineItemBinding.h | 61 + .../Timeline/Bindings/EmptyTimelineTimebar.cpp | 115 + .../Timeline/Bindings/EmptyTimelineTimebar.h | 66 + .../Timeline/Bindings/GroupTimelineItemBinding.cpp | 115 + .../Timeline/Bindings/GroupTimelineItemBinding.h | 63 + .../Palettes/Timeline/Bindings/IKeyframeSelector.h | 52 + .../Palettes/Timeline/Bindings/ITimelineItem.h | 73 + .../Timeline/Bindings/ITimelineItemBinding.h | 190 + .../Timeline/Bindings/ITimelineItemProperty.h | 81 + .../Timeline/Bindings/ITimelineKeyframesManager.h | 55 + .../Palettes/Timeline/Bindings/ITimelineTimebar.h | 74 + .../Timeline/Bindings/ImageTimelineItemBinding.cpp | 97 + .../Timeline/Bindings/ImageTimelineItemBinding.h | 78 + .../Timeline/Bindings/KeyframesManager.cpp | 506 +++ .../Palettes/Timeline/Bindings/KeyframesManager.h | 108 + .../Timeline/Bindings/LayerTimelineItemBinding.cpp | 317 ++ .../Timeline/Bindings/LayerTimelineItemBinding.h | 77 + .../Bindings/MaterialTimelineItemBinding.cpp | 336 ++ .../Bindings/MaterialTimelineItemBinding.h | 83 + .../Bindings/OffsetKeyframesCommandHelper.cpp | 73 + .../Bindings/OffsetKeyframesCommandHelper.h | 65 + .../Bindings/PasteKeyframesCommandHelper.h | 118 + .../PathAnchorPointTimelineItemBinding.cpp | 44 + .../Bindings/PathAnchorPointTimelineItemBinding.h | 69 + .../Timeline/Bindings/PathTimelineItemBinding.cpp | 58 + .../Timeline/Bindings/PathTimelineItemBinding.h | 65 + .../Timeline/Bindings/SlideTimelineItemBinding.cpp | 104 + .../Timeline/Bindings/SlideTimelineItemBinding.h | 121 + .../Bindings/TimelineBreadCrumbProvider.cpp | 239 ++ .../Timeline/Bindings/TimelineBreadCrumbProvider.h | 74 + .../Bindings/TimelineTranslationManager.cpp | 599 +++ .../Timeline/Bindings/TimelineTranslationManager.h | 160 + .../Bindings/UICDMAssetTimelineKeyframe.cpp | 80 + .../Timeline/Bindings/UICDMAssetTimelineKeyframe.h | 69 + .../Palettes/Timeline/Bindings/UICDMTimeline.h | 42 + .../Timeline/Bindings/UICDMTimelineItemBinding.cpp | 1260 +++++++ .../Timeline/Bindings/UICDMTimelineItemBinding.h | 225 ++ .../Bindings/UICDMTimelineItemProperty.cpp | 579 +++ .../Timeline/Bindings/UICDMTimelineItemProperty.h | 119 + .../Timeline/Bindings/UICDMTimelineKeyframe.cpp | 213 ++ .../Timeline/Bindings/UICDMTimelineKeyframe.h | 84 + .../Timeline/Bindings/UICDMTimelineTimebar.cpp | 263 ++ .../Timeline/Bindings/UICDMTimelineTimebar.h | 90 + .../Palettes/Timeline/BlankToggleControl.cpp | 169 + .../Studio/Palettes/Timeline/BlankToggleControl.h | 65 + .../Studio/Palettes/Timeline/ColorBlankControl.cpp | 86 + .../Studio/Palettes/Timeline/ColorBlankControl.h | 60 + .../Studio/Palettes/Timeline/ColorControl.cpp | 307 ++ .../Studio/Palettes/Timeline/ColorControl.h | 98 + .../Studio/Palettes/Timeline/CommentEdit.cpp | 231 ++ .../Studio/Palettes/Timeline/CommentEdit.h | 77 + .../Palettes/Timeline/ComponentContextMenu.cpp | 309 ++ .../Palettes/Timeline/ComponentContextMenu.h | 107 + .../Studio/Palettes/Timeline/FilterToolbar.cpp | 271 ++ .../Studio/Palettes/Timeline/FilterToolbar.h | 80 + .../Studio/Palettes/Timeline/IBreadCrumbProvider.h | 72 + .../Studio/Palettes/Timeline/ITimelineControl.h | 53 + .../Palettes/Timeline/KeyframeContextMenu.cpp | 405 +++ .../Studio/Palettes/Timeline/KeyframeContextMenu.h | 154 + .../Studio/Palettes/Timeline/MultiSelectAspect.cpp | 30 + .../Studio/Palettes/Timeline/MultiSelectAspect.h | 149 + .../Studio/Palettes/Timeline/Playhead.cpp | 266 ++ src/Authoring/Studio/Palettes/Timeline/Playhead.h | 82 + .../Palettes/Timeline/PropertyColorControl.cpp | 89 + .../Palettes/Timeline/PropertyColorControl.h | 55 + .../Palettes/Timeline/PropertyGraphKeyframe.cpp | 152 + .../Palettes/Timeline/PropertyGraphKeyframe.h | 73 + .../Studio/Palettes/Timeline/PropertyRow.cpp | 377 ++ .../Studio/Palettes/Timeline/PropertyRow.h | 102 + .../Palettes/Timeline/PropertyTimebarGraph.cpp | 234 ++ .../Palettes/Timeline/PropertyTimebarGraph.h | 70 + .../Palettes/Timeline/PropertyTimebarRow.cpp | 508 +++ .../Studio/Palettes/Timeline/PropertyTimebarRow.h | 103 + .../Palettes/Timeline/PropertyTimelineKeyframe.cpp | 374 ++ .../Palettes/Timeline/PropertyTimelineKeyframe.h | 95 + .../Palettes/Timeline/PropertyToggleControl.cpp | 110 + .../Palettes/Timeline/PropertyToggleControl.h | 58 + .../Palettes/Timeline/PropertyTreeControl.cpp | 190 + .../Studio/Palettes/Timeline/PropertyTreeControl.h | 68 + .../Studio/Palettes/Timeline/ScalableScroller.cpp | 78 + .../Studio/Palettes/Timeline/ScalableScroller.h | 57 + .../Palettes/Timeline/ScalableScrollerBar.cpp | 359 ++ .../Studio/Palettes/Timeline/ScalableScrollerBar.h | 112 + .../Studio/Palettes/Timeline/SlideRow.cpp | 124 + src/Authoring/Studio/Palettes/Timeline/SlideRow.h | 63 + .../Studio/Palettes/Timeline/SlideTimebarRow.cpp | 78 + .../Studio/Palettes/Timeline/SlideTimebarRow.h | 60 + src/Authoring/Studio/Palettes/Timeline/Snapper.cpp | 455 +++ src/Authoring/Studio/Palettes/Timeline/Snapper.h | 118 + .../Studio/Palettes/Timeline/StateRow.cpp | 311 ++ src/Authoring/Studio/Palettes/Timeline/StateRow.h | 90 + .../Studio/Palettes/Timeline/StateRowFactory.cpp | 60 + .../Studio/Palettes/Timeline/StateRowFactory.h | 50 + .../Studio/Palettes/Timeline/StateTimebarRow.cpp | 156 + .../Studio/Palettes/Timeline/StateTimebarRow.h | 67 + .../Palettes/Timeline/StateTimebarlessRow.cpp | 364 ++ .../Studio/Palettes/Timeline/StateTimebarlessRow.h | 87 + .../Studio/Palettes/Timeline/TimeEditAspect.cpp | 49 + .../Studio/Palettes/Timeline/TimeEditAspect.h | 51 + .../Studio/Palettes/Timeline/TimeMeasure.cpp | 340 ++ .../Studio/Palettes/Timeline/TimeMeasure.h | 74 + .../Studio/Palettes/Timeline/TimeToolbar.cpp | 135 + .../Studio/Palettes/Timeline/TimeToolbar.h | 75 + .../Studio/Palettes/Timeline/TimebarControl.cpp | 690 ++++ .../Studio/Palettes/Timeline/TimebarControl.h | 144 + .../Studio/Palettes/Timeline/TimebarTip.cpp | 235 ++ .../Studio/Palettes/Timeline/TimebarTip.h | 84 + .../Studio/Palettes/Timeline/TimelineControl.cpp | 587 +++ .../Studio/Palettes/Timeline/TimelineControl.h | 158 + .../Studio/Palettes/Timeline/TimelineFilter.cpp | 246 ++ .../Studio/Palettes/Timeline/TimelineFilter.h | 84 + .../Studio/Palettes/Timeline/TimelineKeyframe.cpp | 75 + .../Studio/Palettes/Timeline/TimelineKeyframe.h | 57 + .../Studio/Palettes/Timeline/TimelineRow.cpp | 170 + .../Studio/Palettes/Timeline/TimelineRow.h | 87 + .../Studio/Palettes/Timeline/TimelineSplitter.cpp | 67 + .../Studio/Palettes/Timeline/TimelineSplitter.h | 56 + .../Palettes/Timeline/TimelineTimelineLayout.cpp | 713 ++++ .../Palettes/Timeline/TimelineTimelineLayout.h | 153 + .../Palettes/Timeline/TimelineTreeLayout.cpp | 360 ++ .../Studio/Palettes/Timeline/TimelineTreeLayout.h | 122 + .../Palettes/Timeline/ToggleBlankControl.cpp | 86 + .../Studio/Palettes/Timeline/ToggleBlankControl.h | 60 + .../Studio/Palettes/Timeline/ToggleControl.cpp | 171 + .../Studio/Palettes/Timeline/ToggleControl.h | 63 + .../Studio/Palettes/Timeline/ToggleToolbar.cpp | 205 ++ .../Studio/Palettes/Timeline/ToggleToolbar.h | 82 + .../Studio/Palettes/Timeline/TreeBlankControl.cpp | 83 + .../Studio/Palettes/Timeline/TreeBlankControl.h | 63 + .../Studio/Palettes/controls/BrowserCombo.qml | 79 + .../Studio/Palettes/controls/FloatTextField.qml | 98 + .../Studio/Palettes/controls/StyledComboBox.qml | 155 + .../Studio/Palettes/controls/StyledLabel.qml | 41 + .../Studio/Palettes/controls/StyledMenuItem.qml | 48 + .../Palettes/controls/StyledMenuSeparator.qml | 45 + .../Studio/Palettes/controls/StyledTextField.qml | 59 + .../Studio/Palettes/controls/StyledToolButton.qml | 54 + .../Studio/Palettes/controls/StyledTooltip.qml | 44 + src/Authoring/Studio/PreviewHelper.cpp | 291 ++ src/Authoring/Studio/PreviewHelper.h | 85 + src/Authoring/Studio/Render/IStudioRenderer.h | 88 + src/Authoring/Studio/Render/PathWidget.cpp | 512 +++ src/Authoring/Studio/Render/PathWidget.h | 49 + src/Authoring/Studio/Render/StudioPickValues.h | 217 ++ src/Authoring/Studio/Render/StudioRenderer.cpp | 883 +++++ src/Authoring/Studio/Render/StudioRendererImpl.h | 134 + .../Studio/Render/StudioRendererTranslation.cpp | 3827 ++++++++++++++++++++ .../Studio/Render/StudioRendererTranslation.h | 691 ++++ .../Studio/Render/StudioRotationWidget.cpp | 437 +++ src/Authoring/Studio/Render/StudioScaleWidget.cpp | 261 ++ .../Studio/Render/StudioTranslationWidget.cpp | 172 + src/Authoring/Studio/Render/StudioWidget.cpp | 315 ++ src/Authoring/Studio/Render/StudioWidget.h | 140 + src/Authoring/Studio/Render/StudioWidgetImpl.h | 346 ++ src/Authoring/Studio/Render/WGLRenderContext.cpp | 213 ++ src/Authoring/Studio/Render/WGLRenderContext.h | 107 + src/Authoring/Studio/UI/ContextMenu.h | 150 + src/Authoring/Studio/UI/CustomReBar.cpp | 54 + src/Authoring/Studio/UI/CustomReBar.h | 56 + src/Authoring/Studio/UI/PaletteState.cpp | 160 + src/Authoring/Studio/UI/PaletteState.h | 69 + src/Authoring/Studio/Utils/CmdLineParser.cpp | 193 + src/Authoring/Studio/Utils/CmdLineParser.h | 64 + src/Authoring/Studio/Utils/ITickTock.h | 86 + src/Authoring/Studio/Utils/ImportUtils.cpp | 90 + src/Authoring/Studio/Utils/ImportUtils.h | 72 + src/Authoring/Studio/Utils/MouseCursor.h | 91 + src/Authoring/Studio/Utils/ResourceCache.cpp | 144 + src/Authoring/Studio/Utils/ResourceCache.h | 64 + src/Authoring/Studio/Utils/StringLoader.cpp | 151 + src/Authoring/Studio/Utils/StringLoader.h | 59 + src/Authoring/Studio/Utils/StudioUtils.cpp | 229 ++ src/Authoring/Studio/Utils/StudioUtils.h | 69 + src/Authoring/Studio/Utils/SystemPreferences.cpp | 105 + src/Authoring/Studio/Utils/SystemPreferences.h | 49 + src/Authoring/Studio/Utils/TickTock.cpp | 312 ++ src/Authoring/Studio/Workspace/Dialogs.h | 188 + src/Authoring/Studio/Workspace/Views/Views.h | 91 + src/Authoring/Studio/_Win/Application/AboutDlg.cpp | 314 ++ src/Authoring/Studio/_Win/Application/AboutDlg.h | 95 + src/Authoring/Studio/_Win/Application/AboutDlg.ui | 180 + src/Authoring/Studio/_Win/Application/BaseLink.cpp | 252 ++ src/Authoring/Studio/_Win/Application/BaseLink.h | 76 + .../Studio/_Win/Application/MsgRouter.cpp | 131 + .../Studio/_Win/Application/StudioApp.cpp | 1835 ++++++++++ src/Authoring/Studio/_Win/Application/StudioApp.h | 255 ++ .../Studio/_Win/Application/StudioColors.h | 137 + .../_Win/Application/SubPresentationsDlg.cpp | 172 + .../Studio/_Win/Application/SubPresentationsDlg.h | 82 + .../Studio/_Win/Application/SubPresentationsDlg.ui | 152 + src/Authoring/Studio/_Win/Application/TextLink.cpp | 100 + src/Authoring/Studio/_Win/Application/TextLink.h | 73 + src/Authoring/Studio/_Win/Application/WebLink.cpp | 440 +++ src/Authoring/Studio/_Win/Application/WebLink.h | 100 + src/Authoring/Studio/_Win/Controls/AppFonts.cpp | 89 + src/Authoring/Studio/_Win/Controls/AppFonts.h | 61 + .../Studio/_Win/Controls/BufferedRenderer.cpp | 214 ++ .../Studio/_Win/Controls/BufferedRenderer.h | 60 + .../Studio/_Win/Controls/MFCEditControl.cpp | 278 ++ .../Studio/_Win/Controls/MFCEditControl.h | 85 + .../Studio/_Win/Controls/OffscreenRenderer.cpp | 66 + .../Studio/_Win/Controls/OffscreenRenderer.h | 61 + .../Studio/_Win/Controls/PlatformEditControl.cpp | 144 + .../Studio/_Win/Controls/PlatformEditControl.h | 85 + .../Studio/_Win/Controls/PlatformStaticControl.cpp | 68 + .../Studio/_Win/Controls/PlatformStaticControl.h | 66 + .../Studio/_Win/Controls/PlatformWindowControl.cpp | 96 + .../Studio/_Win/Controls/PlatformWindowControl.h | 69 + src/Authoring/Studio/_Win/Controls/WinRenderer.cpp | 525 +++ src/Authoring/Studio/_Win/Controls/WinRenderer.h | 130 + src/Authoring/Studio/_Win/Controls/WndControl.cpp | 1006 +++++ src/Authoring/Studio/_Win/Controls/WndControl.h | 148 + src/Authoring/Studio/_Win/DragNDrop/DropProxy.cpp | 341 ++ src/Authoring/Studio/_Win/DragNDrop/DropProxy.h | 82 + src/Authoring/Studio/_Win/DragNDrop/WinDnd.cpp | 119 + src/Authoring/Studio/_Win/DragNDrop/WinDnd.h | 64 + .../Studio/_Win/Include/StudioPrefixWin32.h | 39 + .../Studio/_Win/Palettes/PaletteManager.cpp | 902 +++++ .../Studio/_Win/Palettes/PaletteManager.h | 153 + .../_Win/Palettes/Progress/ProgressPalette.cpp | 127 + .../_Win/Palettes/Progress/ProgressPalette.h | 58 + .../Studio/_Win/Palettes/Progress/ProgressView.cpp | 178 + .../Studio/_Win/Palettes/Progress/ProgressView.h | 80 + .../Studio/_Win/Palettes/Splash/SplashPalette.cpp | 94 + .../Studio/_Win/Palettes/Splash/SplashPalette.h | 54 + .../Studio/_Win/Palettes/Splash/SplashView.cpp | 92 + .../Studio/_Win/Palettes/Splash/SplashView.h | 71 + src/Authoring/Studio/_Win/Studio/stdafx.cpp | 33 + src/Authoring/Studio/_Win/Studio/stdafx.h | 221 ++ src/Authoring/Studio/_Win/UI/ContextMenu.cpp | 292 ++ src/Authoring/Studio/_Win/UI/ControlButton.cpp | 471 +++ src/Authoring/Studio/_Win/UI/ControlButton.h | 119 + src/Authoring/Studio/_Win/UI/CrashDlg.cpp | 212 ++ src/Authoring/Studio/_Win/UI/CrashDlg.h | 96 + src/Authoring/Studio/_Win/UI/EditCameraBar.cpp | 226 ++ src/Authoring/Studio/_Win/UI/EditCameraBar.h | 99 + src/Authoring/Studio/_Win/UI/EditorPane.cpp | 90 + src/Authoring/Studio/_Win/UI/EditorPane.h | 65 + src/Authoring/Studio/_Win/UI/FileDialogEX.cpp | 451 +++ src/Authoring/Studio/_Win/UI/FileDialogEX.h | 111 + src/Authoring/Studio/_Win/UI/GLVersionDlg.cpp | 91 + src/Authoring/Studio/_Win/UI/GLVersionDlg.h | 75 + src/Authoring/Studio/_Win/UI/InterpolationDlg.cpp | 78 + src/Authoring/Studio/_Win/UI/InterpolationDlg.h | 66 + src/Authoring/Studio/_Win/UI/InterpolationDlg.ui | 305 ++ src/Authoring/Studio/_Win/UI/MemoryDC.cpp | 258 ++ src/Authoring/Studio/_Win/UI/MemoryDC.h | 91 + src/Authoring/Studio/_Win/UI/MenuEdit.cpp | 169 + src/Authoring/Studio/_Win/UI/MenuEdit.h | 72 + src/Authoring/Studio/_Win/UI/MenuItem.cpp | 58 + src/Authoring/Studio/_Win/UI/MenuItem.h | 60 + src/Authoring/Studio/_Win/UI/NumericEdit.cpp | 347 ++ src/Authoring/Studio/_Win/UI/NumericEdit.h | 101 + .../Studio/_Win/UI/PlayerContainerWnd.cpp | 510 +++ src/Authoring/Studio/_Win/UI/PlayerContainerWnd.h | 106 + src/Authoring/Studio/_Win/UI/PlayerWnd.cpp | 278 ++ src/Authoring/Studio/_Win/UI/PlayerWnd.h | 99 + src/Authoring/Studio/_Win/UI/PopupWnd.cpp | 248 ++ src/Authoring/Studio/_Win/UI/PopupWnd.h | 104 + src/Authoring/Studio/_Win/UI/PreviewOutputDlg.cpp | 366 ++ src/Authoring/Studio/_Win/UI/PreviewOutputDlg.h | 92 + src/Authoring/Studio/_Win/UI/RecentItems.cpp | 145 + src/Authoring/Studio/_Win/UI/RecentItems.h | 88 + src/Authoring/Studio/_Win/UI/ReportDlg.cpp | 198 + src/Authoring/Studio/_Win/UI/ReportDlg.h | 100 + .../Studio/_Win/UI/ResetKeyframeValuesDlg.cpp | 66 + .../Studio/_Win/UI/ResetKeyframeValuesDlg.h | 57 + src/Authoring/Studio/_Win/UI/SceneView.cpp | 861 +++++ src/Authoring/Studio/_Win/UI/SceneView.h | 174 + src/Authoring/Studio/_Win/UI/StartupDlg.cpp | 174 + src/Authoring/Studio/_Win/UI/StartupDlg.h | 114 + src/Authoring/Studio/_Win/UI/StartupDlg.ui | 171 + .../Studio/_Win/UI/StudioAppPrefsPage.cpp | 590 +++ src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.h | 121 + src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.ui | 183 + src/Authoring/Studio/_Win/UI/StudioPaletteBar.cpp | 260 ++ src/Authoring/Studio/_Win/UI/StudioPaletteBar.h | 88 + .../Studio/_Win/UI/StudioPreferencesPropSheet.cpp | 155 + .../Studio/_Win/UI/StudioPreferencesPropSheet.h | 105 + .../Studio/_Win/UI/StudioPreferencesPropSheet.ui | 102 + .../Studio/_Win/UI/StudioProjectSettingsPage.cpp | 385 ++ .../Studio/_Win/UI/StudioProjectSettingsPage.h | 103 + .../Studio/_Win/UI/StudioProjectSettingsPage.ui | 125 + src/Authoring/Studio/_Win/UI/TimeEditDlg.cpp | 524 +++ src/Authoring/Studio/_Win/UI/TimeEditDlg.h | 190 + src/Authoring/Studio/_Win/UI/timeeditdlg.ui | 364 ++ src/Authoring/Studio/_Win/Utils/MouseCursor.cpp | 199 + src/Authoring/Studio/_Win/Utils/WinUtils.cpp | 600 +++ src/Authoring/Studio/_Win/Utils/WinUtils.h | 65 + src/Authoring/Studio/_Win/Workspace/Dialogs.cpp | 1332 +++++++ src/Authoring/Studio/_Win/Workspace/Views.cpp | 195 + src/Authoring/Studio/images.qrc | 179 + src/Authoring/Studio/images/Action-Action.png | Bin 0 -> 2927 bytes src/Authoring/Studio/images/Action-ChildAction.png | Bin 0 -> 2836 bytes .../Studio/images/Action-ChildMasterAction.png | Bin 0 -> 2840 bytes .../Studio/images/Action-ComponentAction.png | Bin 0 -> 2836 bytes .../Studio/images/Action-ComponentMasterAction.png | Bin 0 -> 2844 bytes .../Studio/images/Action-MasterAction.png | Bin 0 -> 2911 bytes .../Studio/images/Action-Trash-Disabled.png | Bin 0 -> 533 bytes .../Studio/images/Action-Trash-Disabled@2x.png | Bin 0 -> 656 bytes .../Studio/images/Action-Trash-Normal.png | Bin 0 -> 534 bytes .../Studio/images/Action-Trash-Normal@2x.png | Bin 0 -> 656 bytes src/Authoring/Studio/images/Asset-Alias-Normal.png | Bin 0 -> 284 bytes .../Studio/images/Asset-Alias-Normal@2x.png | Bin 0 -> 545 bytes .../Studio/images/Asset-Camera-Normal.png | Bin 0 -> 347 bytes .../Studio/images/Asset-Camera-Normal@2x.png | Bin 0 -> 547 bytes .../Studio/images/Asset-Component-Normal.png | Bin 0 -> 402 bytes .../Studio/images/Asset-Component-Normal@2x.png | Bin 0 -> 797 bytes src/Authoring/Studio/images/Asset-Cone-Normal.png | Bin 0 -> 517 bytes .../Studio/images/Asset-Cone-Normal@2x.png | Bin 0 -> 1001 bytes src/Authoring/Studio/images/Asset-Cube-Normal.png | Bin 0 -> 550 bytes .../Studio/images/Asset-Cube-Normal@2x.png | Bin 0 -> 885 bytes .../Studio/images/Asset-Cylinder-Normal.png | Bin 0 -> 508 bytes .../Studio/images/Asset-Cylinder-Normal@2x.png | Bin 0 -> 938 bytes src/Authoring/Studio/images/Asset-Group-Normal.png | Bin 0 -> 606 bytes .../Studio/images/Asset-Group-Normal@2x.png | Bin 0 -> 1206 bytes src/Authoring/Studio/images/Asset-Layer-Normal.png | Bin 0 -> 181 bytes .../Studio/images/Asset-Layer-Normal@2x.png | Bin 0 -> 280 bytes src/Authoring/Studio/images/Asset-Light-Normal.png | Bin 0 -> 517 bytes .../Studio/images/Asset-Light-Normal@2x.png | Bin 0 -> 923 bytes .../Studio/images/Asset-Rectangle-Normal.png | Bin 0 -> 248 bytes .../Studio/images/Asset-Rectangle-Normal@2x.png | Bin 0 -> 345 bytes .../Studio/images/Asset-Sphere-Normal.png | Bin 0 -> 421 bytes .../Studio/images/Asset-Sphere-Normal@2x.png | Bin 0 -> 672 bytes src/Authoring/Studio/images/Asset-Text-Normal.png | Bin 0 -> 151 bytes .../Studio/images/Asset-Text-Normal@2x.png | Bin 0 -> 188 bytes src/Authoring/Studio/images/Insert-Left.png | Bin 0 -> 273 bytes .../Studio/images/Insert-Rearrange-Left.png | Bin 0 -> 196 bytes .../Studio/images/Insert-Rearrange-Right.png | Bin 0 -> 196 bytes src/Authoring/Studio/images/Insert-Right.png | Bin 0 -> 275 bytes .../images/Inspector-AnimateToggle-Active.png | Bin 0 -> 641 bytes .../images/Inspector-AnimateToggle-Active@2x.png | Bin 0 -> 972 bytes .../images/Inspector-AnimateToggle-Normal.png | Bin 0 -> 637 bytes .../images/Inspector-AnimateToggle-Normal@2x.png | Bin 0 -> 978 bytes .../Studio/images/Keyframe-Master-Disabled.png | Bin 0 -> 3009 bytes .../Studio/images/Keyframe-Master-Normal.png | Bin 0 -> 2924 bytes .../Studio/images/Keyframe-Master-Selected.png | Bin 0 -> 2985 bytes .../images/Keyframe-MasterDynamic-Normal.png | Bin 0 -> 3010 bytes .../images/Keyframe-MasterDynamic-Selected.png | Bin 0 -> 2981 bytes .../Studio/images/Keyframe-MasterLeft-Normal.png | Bin 0 -> 2890 bytes .../Studio/images/Keyframe-MasterLeft-Selected.png | Bin 0 -> 2939 bytes .../Studio/images/Keyframe-MasterLeft-disabled.png | Bin 0 -> 2935 bytes .../images/Keyframe-MasterLeftDynamic-Normal.png | Bin 0 -> 2957 bytes .../images/Keyframe-MasterLeftDynamic-Selected.png | Bin 0 -> 2934 bytes .../Studio/images/Keyframe-MasterRight-Normal.png | Bin 0 -> 2879 bytes .../images/Keyframe-MasterRight-Selected.png | Bin 0 -> 2904 bytes .../images/Keyframe-MasterRight-disabled.png | Bin 0 -> 2918 bytes .../images/Keyframe-MasterRightDynamic-Normal.png | Bin 0 -> 2912 bytes .../Keyframe-MasterRightDynamic-Selected.png | Bin 0 -> 2904 bytes .../Studio/images/Keyframe-Property-Disabled.png | Bin 0 -> 2989 bytes .../Studio/images/Keyframe-Property-Normal.png | Bin 0 -> 2924 bytes .../Studio/images/Keyframe-Property-Selected.png | Bin 0 -> 2981 bytes .../images/Keyframe-PropertyDynamic-Normal.png | Bin 0 -> 2971 bytes .../images/Keyframe-PropertyDynamic-Selected.png | Bin 0 -> 2973 bytes .../Studio/images/Objects-Alias-Disabled.png | Bin 0 -> 555 bytes .../Studio/images/Objects-Alias-Disabled@2x.png | Bin 0 -> 621 bytes .../Studio/images/Objects-Alias-Normal.png | Bin 0 -> 241 bytes .../Studio/images/Objects-Alias-Normal@2x.png | Bin 0 -> 391 bytes .../Studio/images/Objects-Behavior-Disabled.png | Bin 0 -> 466 bytes .../Studio/images/Objects-Behavior-Disabled@2x.png | Bin 0 -> 507 bytes .../Studio/images/Objects-Behavior-Normal.png | Bin 0 -> 152 bytes .../Studio/images/Objects-Behavior-Normal@2x.png | Bin 0 -> 179 bytes .../Studio/images/Objects-Camera-Disabled.png | Bin 0 -> 542 bytes .../Studio/images/Objects-Camera-Disabled@2x.png | Bin 0 -> 653 bytes .../Studio/images/Objects-Camera-Normal.png | Bin 0 -> 259 bytes .../Studio/images/Objects-Camera-Normal@2x.png | Bin 0 -> 418 bytes .../Studio/images/Objects-Component-Disabled.png | Bin 0 -> 583 bytes .../images/Objects-Component-Disabled@2x.png | Bin 0 -> 726 bytes .../Studio/images/Objects-Component-Normal.png | Bin 0 -> 266 bytes .../Studio/images/Objects-Component-Normal@2x.png | Bin 0 -> 460 bytes .../Studio/images/Objects-Effect-Disabled.png | Bin 0 -> 631 bytes .../Studio/images/Objects-Effect-Disabled@2x.png | Bin 0 -> 869 bytes .../Studio/images/Objects-Effect-Normal.png | Bin 0 -> 381 bytes .../Studio/images/Objects-Effect-Normal@2x.png | Bin 0 -> 709 bytes .../Studio/images/Objects-Folder-Disabled.png | Bin 0 -> 468 bytes .../Studio/images/Objects-Folder-Disabled@2x.png | Bin 0 -> 499 bytes .../Studio/images/Objects-Folder-Normal.png | Bin 0 -> 469 bytes .../Studio/images/Objects-Folder-Normal@2x.png | Bin 0 -> 498 bytes .../Studio/images/Objects-Group-Disabled.png | Bin 0 -> 569 bytes .../Studio/images/Objects-Group-Disabled@2x.png | Bin 0 -> 836 bytes .../Studio/images/Objects-Group-Normal.png | Bin 0 -> 288 bytes .../Studio/images/Objects-Group-Normal@2x.png | Bin 0 -> 595 bytes .../Studio/images/Objects-Image-Disabled.png | Bin 0 -> 589 bytes .../Studio/images/Objects-Image-Disabled@2x.png | Bin 0 -> 704 bytes .../Studio/images/Objects-Image-Normal.png | Bin 0 -> 281 bytes .../Studio/images/Objects-Image-Normal@2.png | Bin 0 -> 457 bytes .../Studio/images/Objects-Layer-Disabled.png | Bin 0 -> 507 bytes .../Studio/images/Objects-Layer-Disabled@2x.png | Bin 0 -> 541 bytes .../Studio/images/Objects-Layer-Normal.png | Bin 0 -> 151 bytes .../Studio/images/Objects-Layer-Normal@2x.png | Bin 0 -> 203 bytes .../Studio/images/Objects-Light-Disabled.png | Bin 0 -> 606 bytes .../Studio/images/Objects-Light-Disabled@2x.png | Bin 0 -> 803 bytes .../Studio/images/Objects-Light-Normal.png | Bin 0 -> 325 bytes .../Studio/images/Objects-Light-Normal@2x.png | Bin 0 -> 640 bytes .../Studio/images/Objects-Material-Disabled.png | Bin 0 -> 610 bytes .../Studio/images/Objects-Material-Disabled@2x.png | Bin 0 -> 768 bytes .../Studio/images/Objects-Material-Normal.png | Bin 0 -> 287 bytes .../Studio/images/Objects-Material-Normal@2x.png | Bin 0 -> 511 bytes .../Studio/images/Objects-Model-Disabled.png | Bin 0 -> 636 bytes .../Studio/images/Objects-Model-Disabled@2x.png | Bin 0 -> 832 bytes .../Studio/images/Objects-Model-Normal.png | Bin 0 -> 336 bytes .../Studio/images/Objects-Model-Normal@2x.png | Bin 0 -> 545 bytes .../Studio/images/Objects-Property-Disabled.png | Bin 0 -> 480 bytes .../Studio/images/Objects-Property-Disabled@2x.png | Bin 0 -> 518 bytes .../Studio/images/Objects-Property-Normal.png | Bin 0 -> 481 bytes .../Studio/images/Objects-Property-Normal@2x.png | Bin 0 -> 515 bytes .../Studio/images/Objects-Scene-Disabled.png | Bin 0 -> 489 bytes .../Studio/images/Objects-Scene-Disabled@2x.png | Bin 0 -> 533 bytes .../Studio/images/Objects-Scene-Normal.png | Bin 0 -> 199 bytes .../Studio/images/Objects-Scene-Normal@2x.png | Bin 0 -> 282 bytes .../Studio/images/Objects-Text-Disabled.png | Bin 0 -> 470 bytes .../Studio/images/Objects-Text-Disabled@2x.png | Bin 0 -> 495 bytes .../Studio/images/Objects-Text-Normal.png | Bin 0 -> 151 bytes .../Studio/images/Objects-Text-Normal@2x.png | Bin 0 -> 188 bytes src/Authoring/Studio/images/PlaybackHead.png | Bin 0 -> 233 bytes src/Authoring/Studio/images/PlaybackHead@2x.png | Bin 0 -> 318 bytes src/Authoring/Studio/images/Slide-Active.png | Bin 0 -> 1562 bytes src/Authoring/Studio/images/Slide-Active@2x.png | Bin 0 -> 2663 bytes .../Studio/images/Slide-Master-Active.png | Bin 0 -> 1471 bytes .../Studio/images/Slide-Master-Active@2x.png | Bin 0 -> 4190 bytes src/Authoring/Studio/images/Slide-Normal.png | Bin 0 -> 1461 bytes src/Authoring/Studio/images/Slide-Normal@2x.png | Bin 0 -> 2534 bytes src/Authoring/Studio/images/Toggle-Empty.png | Bin 0 -> 2855 bytes .../Studio/images/Toggle-HideShow-disabled.png | Bin 0 -> 238 bytes .../Studio/images/Toggle-HideShow-disabled@2x.png | Bin 0 -> 371 bytes src/Authoring/Studio/images/Toggle-HideShow.png | Bin 0 -> 248 bytes src/Authoring/Studio/images/Toggle-HideShow@2x.png | Bin 0 -> 454 bytes src/Authoring/Studio/images/Toggle-Lock.png | Bin 0 -> 224 bytes src/Authoring/Studio/images/Toggle-Lock@2x.png | Bin 0 -> 356 bytes src/Authoring/Studio/images/Toggle-Shy.png | Bin 0 -> 289 bytes src/Authoring/Studio/images/Toggle-Shy@2x.png | Bin 0 -> 485 bytes src/Authoring/Studio/images/add.png | Bin 0 -> 454 bytes src/Authoring/Studio/images/add@2x.png | Bin 0 -> 515 bytes src/Authoring/Studio/images/arrow.png | Bin 0 -> 523 bytes src/Authoring/Studio/images/arrow@2x.png | Bin 0 -> 600 bytes src/Authoring/Studio/images/arrow_down.png | Bin 0 -> 533 bytes src/Authoring/Studio/images/arrow_down@2x.png | Bin 0 -> 610 bytes .../Studio/images/breadcrumb_component_button.png | Bin 0 -> 3402 bytes .../images/breadcrumb_component_colon_button.png | Bin 0 -> 262 bytes .../images/breadcrumb_component_grey_button.png | Bin 0 -> 3374 bytes .../Studio/images/breadcrumb_component_scene.png | Bin 0 -> 3506 bytes src/Authoring/Studio/images/checkbox-checked.png | Bin 0 -> 3196 bytes src/Authoring/Studio/images/checkbox-unchecked.png | Bin 0 -> 2946 bytes src/Authoring/Studio/images/empty-pixel.png | Bin 0 -> 154 bytes src/Authoring/Studio/images/filter-shy-down.png | Bin 0 -> 289 bytes src/Authoring/Studio/images/filter-shy-down@2x.png | Bin 0 -> 485 bytes .../Studio/images/filter-toggle-eye-down.png | Bin 0 -> 238 bytes .../Studio/images/filter-toggle-eye-down@2x.png | Bin 0 -> 371 bytes .../Studio/images/filter-toggle-eye-up.png | Bin 0 -> 248 bytes .../Studio/images/filter-toggle-eye-up@2x.png | Bin 0 -> 454 bytes .../Studio/images/obsolete_placeholder.png | Bin 0 -> 158 bytes .../images/scrollbar-arrows-down-depressed.png | Bin 0 -> 2918 bytes .../images/scrollbar-arrows-down-disabled.png | Bin 0 -> 2889 bytes .../Studio/images/scrollbar-arrows-down-normal.png | Bin 0 -> 2893 bytes .../images/scrollbar-arrows-left-depressed.png | Bin 0 -> 2914 bytes .../images/scrollbar-arrows-left-disabled.png | Bin 0 -> 2886 bytes .../Studio/images/scrollbar-arrows-left-normal.png | Bin 0 -> 2887 bytes .../images/scrollbar-arrows-right-depressed.png | Bin 0 -> 2916 bytes .../images/scrollbar-arrows-right-disabled.png | Bin 0 -> 2884 bytes .../images/scrollbar-arrows-right-normal.png | Bin 0 -> 2885 bytes .../images/scrollbar-arrows-up-depressed.png | Bin 0 -> 2917 bytes .../Studio/images/scrollbar-arrows-up-disabled.png | Bin 0 -> 2881 bytes .../Studio/images/scrollbar-arrows-up-normal.png | Bin 0 -> 2879 bytes .../Studio/images/timebarhandle-disabled-left.png | Bin 0 -> 276 bytes .../Studio/images/timebarhandle-disabled-right.png | Bin 0 -> 283 bytes src/Authoring/Studio/images/timebarhandle-left.png | Bin 0 -> 298 bytes .../Studio/images/timebarhandle-right.png | Bin 0 -> 297 bytes src/Authoring/Studio/qt3dstudio.qrc | 16 + src/Authoring/Studio/remoteproject.cpp | 202 ++ src/Authoring/Studio/remoteproject.h | 61 + src/Authoring/Studio/res/About Icon.bmp | Bin 0 -> 297132 bytes src/Authoring/Studio/res/Flippy-Right.bmp | Bin 0 -> 824 bytes src/Authoring/Studio/res/Flippy-down.bmp | Bin 0 -> 824 bytes src/Authoring/Studio/res/Studio.ico | Bin 0 -> 370070 bytes src/Authoring/Studio/res/Studio.manifest | 22 + src/Authoring/Studio/res/Studio.png | Bin 0 -> 16918 bytes src/Authoring/Studio/res/StudioDoc.ico | Bin 0 -> 370070 bytes src/Authoring/Studio/res/Toolbar-00.png | Bin 0 -> 229 bytes src/Authoring/Studio/res/Toolbar-01.png | Bin 0 -> 190 bytes src/Authoring/Studio/res/Toolbar-02.png | Bin 0 -> 180 bytes src/Authoring/Studio/res/Toolbar-03.png | Bin 0 -> 169 bytes src/Authoring/Studio/res/Toolbar-04.png | Bin 0 -> 209 bytes src/Authoring/Studio/res/Toolbar-05.png | Bin 0 -> 230 bytes src/Authoring/Studio/res/Toolbar-06.png | Bin 0 -> 150 bytes src/Authoring/Studio/res/Toolbar-07.png | Bin 0 -> 155 bytes src/Authoring/Studio/res/Toolbar.bmp | Bin 0 -> 1078 bytes src/Authoring/Studio/res/Tutorial/button_back.png | Bin 0 -> 807 bytes .../Studio/res/Tutorial/button_back@2x.png | Bin 0 -> 1510 bytes src/Authoring/Studio/res/Tutorial/button_next.png | Bin 0 -> 782 bytes .../Studio/res/Tutorial/button_next@2x.png | Bin 0 -> 1499 bytes src/Authoring/Studio/res/Tutorial/screens/1.png | Bin 0 -> 79204 bytes src/Authoring/Studio/res/Tutorial/screens/2.png | Bin 0 -> 128317 bytes src/Authoring/Studio/res/Tutorial/screens/3.png | Bin 0 -> 113936 bytes src/Authoring/Studio/res/Tutorial/screens/4.png | Bin 0 -> 108052 bytes src/Authoring/Studio/res/Tutorial/screens/5.png | Bin 0 -> 100198 bytes src/Authoring/Studio/res/Tutorial/screens/6.png | Bin 0 -> 98135 bytes src/Authoring/Studio/res/Tutorial/screens/7.png | Bin 0 -> 99190 bytes src/Authoring/Studio/res/arrow_down.png | Bin 0 -> 213 bytes src/Authoring/Studio/res/arrow_down@2x.png | Bin 0 -> 273 bytes .../Studio/res/client_tools_grayed_out.bmp | Bin 0 -> 5432 bytes .../Studio/res/client_tools_hi_color-00.png | Bin 0 -> 302 bytes .../Studio/res/client_tools_hi_color-00@2x.png | Bin 0 -> 465 bytes .../Studio/res/client_tools_hi_color-01.png | Bin 0 -> 231 bytes .../Studio/res/client_tools_hi_color-01@2x.png | Bin 0 -> 324 bytes .../Studio/res/client_tools_hi_color-02.png | Bin 0 -> 311 bytes .../Studio/res/client_tools_hi_color-02@2x.png | Bin 0 -> 554 bytes .../Studio/res/client_tools_hi_color-03.png | Bin 0 -> 149 bytes .../Studio/res/client_tools_hi_color-03@2x.png | Bin 0 -> 190 bytes .../Studio/res/client_tools_hi_color-04.png | Bin 0 -> 349 bytes .../Studio/res/client_tools_hi_color-04@2x.png | Bin 0 -> 848 bytes .../Studio/res/client_tools_hi_color-05.png | Bin 0 -> 359 bytes .../Studio/res/client_tools_hi_color-05@2x.png | Bin 0 -> 671 bytes .../Studio/res/client_tools_hi_color-06.png | Bin 0 -> 162 bytes .../Studio/res/client_tools_hi_color-06@2x.png | Bin 0 -> 230 bytes src/Authoring/Studio/res/client_tools_hi_color.bmp | Bin 0 -> 5432 bytes .../Studio/res/client_tools_low_color.bmp | Bin 0 -> 1014 bytes src/Authoring/Studio/res/cursors.bmp | Bin 0 -> 3190 bytes src/Authoring/Studio/res/edit_camera_pan.png | Bin 0 -> 556 bytes src/Authoring/Studio/res/edit_camera_rot.png | Bin 0 -> 567 bytes src/Authoring/Studio/res/edit_camera_zoom.png | Bin 0 -> 567 bytes .../Studio/res/editcamera_tools_disabled.bmp | Bin 0 -> 4664 bytes .../Studio/res/editcamera_tools_hi-00.png | Bin 0 -> 324 bytes .../Studio/res/editcamera_tools_hi-00@2x.png | Bin 0 -> 623 bytes .../Studio/res/editcamera_tools_hi-00_disabled.png | Bin 0 -> 339 bytes .../res/editcamera_tools_hi-00_disabled@2x.png | Bin 0 -> 487 bytes .../Studio/res/editcamera_tools_hi-01.png | Bin 0 -> 395 bytes .../Studio/res/editcamera_tools_hi-01@2x.png | Bin 0 -> 730 bytes .../Studio/res/editcamera_tools_hi-01_disabled.png | Bin 0 -> 298 bytes .../res/editcamera_tools_hi-01_disabled@2x.png | Bin 0 -> 468 bytes .../Studio/res/editcamera_tools_hi-02.png | Bin 0 -> 670 bytes .../Studio/res/editcamera_tools_hi-02@2x.png | Bin 0 -> 972 bytes .../Studio/res/editcamera_tools_hi-02_disabled.png | Bin 0 -> 672 bytes .../res/editcamera_tools_hi-02_disabled@2x.png | Bin 0 -> 979 bytes .../Studio/res/editcamera_tools_hi-03.png | Bin 0 -> 494 bytes .../Studio/res/editcamera_tools_hi-03@2x.png | Bin 0 -> 966 bytes .../Studio/res/editcamera_tools_hi-03_disabled.png | Bin 0 -> 361 bytes .../res/editcamera_tools_hi-03_disabled@2x.png | Bin 0 -> 624 bytes .../Studio/res/editcamera_tools_hi-04.png | Bin 0 -> 341 bytes .../Studio/res/editcamera_tools_hi-04@2x.png | Bin 0 -> 774 bytes .../Studio/res/editcamera_tools_hi-04_disabled.png | Bin 0 -> 353 bytes .../res/editcamera_tools_hi-04_disabled@2x.png | Bin 0 -> 605 bytes .../Studio/res/editcamera_tools_hi-05.png | Bin 0 -> 328 bytes .../Studio/res/editcamera_tools_hi-05@2x.png | Bin 0 -> 720 bytes .../Studio/res/editcamera_tools_hi-05_disabled.png | Bin 0 -> 367 bytes .../res/editcamera_tools_hi-05_disabled@2x.png | Bin 0 -> 582 bytes src/Authoring/Studio/res/editcamera_tools_hi.bmp | Bin 0 -> 4664 bytes src/Authoring/Studio/res/editcamera_tools_low.bmp | Bin 0 -> 2614 bytes src/Authoring/Studio/res/group_move.png | Bin 0 -> 560 bytes src/Authoring/Studio/res/group_rotate.png | Bin 0 -> 570 bytes src/Authoring/Studio/res/group_scale.png | Bin 0 -> 540 bytes src/Authoring/Studio/res/item_move.png | Bin 0 -> 562 bytes src/Authoring/Studio/res/item_rotate.png | Bin 0 -> 573 bytes src/Authoring/Studio/res/item_scale.png | Bin 0 -> 536 bytes src/Authoring/Studio/res/keyframe.bmp | Bin 0 -> 978 bytes .../Studio/res/library_buttons_hi_color.bmp | Bin 0 -> 10040 bytes .../Studio/res/library_buttons_low_color.bmp | Bin 0 -> 1294 bytes src/Authoring/Studio/res/libtoolb.bmp | Bin 0 -> 1590 bytes src/Authoring/Studio/res/menubtn_down.bmp | Bin 0 -> 230 bytes src/Authoring/Studio/res/menubtn_normal.bmp | Bin 0 -> 180 bytes src/Authoring/Studio/res/menubtn_selected.bmp | Bin 0 -> 180 bytes src/Authoring/Studio/res/menuedit.bmp | Bin 0 -> 3894 bytes src/Authoring/Studio/res/menutool.bmp | Bin 0 -> 20790 bytes src/Authoring/Studio/res/open_dialog.png | Bin 0 -> 42144 bytes src/Authoring/Studio/res/playback_tools_grayed.bmp | Bin 0 -> 3128 bytes src/Authoring/Studio/res/playback_tools_hi.bmp | Bin 0 -> 3128 bytes src/Authoring/Studio/res/playback_tools_low-00.png | Bin 0 -> 547 bytes .../Studio/res/playback_tools_low-00@2x.png | Bin 0 -> 651 bytes src/Authoring/Studio/res/playback_tools_low-01.png | Bin 0 -> 437 bytes .../Studio/res/playback_tools_low-01@2x.png | Bin 0 -> 457 bytes src/Authoring/Studio/res/playback_tools_low-02.png | Bin 0 -> 519 bytes .../Studio/res/playback_tools_low-02@2x.png | Bin 0 -> 567 bytes src/Authoring/Studio/res/playback_tools_low-03.png | Bin 0 -> 578 bytes .../Studio/res/playback_tools_low-03@2x.png | Bin 0 -> 693 bytes src/Authoring/Studio/res/playback_tools_low.bmp | Bin 0 -> 630 bytes src/Authoring/Studio/res/prefstab-00.png | Bin 0 -> 519 bytes src/Authoring/Studio/res/prefstab-00@2x.png | Bin 0 -> 1037 bytes src/Authoring/Studio/res/prefstab-01.png | Bin 0 -> 597 bytes src/Authoring/Studio/res/prefstab-01@2x.png | Bin 0 -> 832 bytes src/Authoring/Studio/res/prefstab.bmp | Bin 0 -> 2102 bytes src/Authoring/Studio/res/preview_tools.bmp | Bin 0 -> 246 bytes src/Authoring/Studio/res/project-icon-new.bmp | Bin 0 -> 3128 bytes src/Authoring/Studio/res/project-icon-open.bmp | Bin 0 -> 3128 bytes src/Authoring/Studio/res/qt3ds_header.bmp | Bin 0 -> 192080 bytes src/Authoring/Studio/res/separator.png | Bin 0 -> 522 bytes src/Authoring/Studio/res/separator@2x.png | Bin 0 -> 526 bytes src/Authoring/Studio/res/stmtool.bmp | Bin 0 -> 3894 bytes src/Authoring/Studio/res/storagep.bmp | Bin 0 -> 1494 bytes src/Authoring/Studio/res/tmchmenu.bmp | Bin 0 -> 5094 bytes src/Authoring/Studio/res/tmlntool.bmp | Bin 0 -> 3126 bytes src/Authoring/Studio/res/tmtbmenu.bmp | Bin 0 -> 5094 bytes src/Authoring/Studio/res/weblinkc.bmp | Bin 0 -> 1494 bytes src/Authoring/Studio/res/winxp1.bin | 22 + src/Authoring/Studio/style.qss | 219 ++ src/Authoring/Studio/version.h | 35 + 845 files changed, 105367 insertions(+) create mode 100644 src/Authoring/Studio/Application/MsgRouter.h create mode 100644 src/Authoring/Studio/Application/StudioConst.h create mode 100644 src/Authoring/Studio/Application/StudioDefs.h create mode 100644 src/Authoring/Studio/Application/StudioInstance.cpp create mode 100644 src/Authoring/Studio/Application/StudioInstance.h create mode 100644 src/Authoring/Studio/Application/StudioTutorialWidget.cpp create mode 100644 src/Authoring/Studio/Application/StudioTutorialWidget.h create mode 100644 src/Authoring/Studio/Application/StudioTutorialWidget.ui create mode 100644 src/Authoring/Studio/Controls/BaseMeasure.cpp create mode 100644 src/Authoring/Studio/Controls/BaseMeasure.h create mode 100644 src/Authoring/Studio/Controls/BlankControl.cpp create mode 100644 src/Authoring/Studio/Controls/BlankControl.h create mode 100644 src/Authoring/Studio/Controls/BreadCrumbControl.cpp create mode 100644 src/Authoring/Studio/Controls/BreadCrumbControl.h create mode 100644 src/Authoring/Studio/Controls/ButtonControl.cpp create mode 100644 src/Authoring/Studio/Controls/ButtonControl.h create mode 100644 src/Authoring/Studio/Controls/ClickableLabel.cpp create mode 100644 src/Authoring/Studio/Controls/ClickableLabel.h create mode 100644 src/Authoring/Studio/Controls/ComboTextBox.h create mode 100644 src/Authoring/Studio/Controls/Control.cpp create mode 100644 src/Authoring/Studio/Controls/Control.h create mode 100644 src/Authoring/Studio/Controls/ControlData.cpp create mode 100644 src/Authoring/Studio/Controls/ControlData.h create mode 100644 src/Authoring/Studio/Controls/ControlGraph.cpp create mode 100644 src/Authoring/Studio/Controls/ControlGraph.h create mode 100644 src/Authoring/Studio/Controls/ControlGraphIterators.h create mode 100644 src/Authoring/Studio/Controls/EditInPlace.h create mode 100644 src/Authoring/Studio/Controls/FloatEdit.cpp create mode 100644 src/Authoring/Studio/Controls/FloatEdit.h create mode 100644 src/Authoring/Studio/Controls/FlowLayout.cpp create mode 100644 src/Authoring/Studio/Controls/FlowLayout.h create mode 100644 src/Authoring/Studio/Controls/GenericComboDropDown.h create mode 100644 src/Authoring/Studio/Controls/GenericEdit.h create mode 100644 src/Authoring/Studio/Controls/InsertionLine.cpp create mode 100644 src/Authoring/Studio/Controls/InsertionLine.h create mode 100644 src/Authoring/Studio/Controls/InsertionOverlay.cpp create mode 100644 src/Authoring/Studio/Controls/InsertionOverlay.h create mode 100644 src/Authoring/Studio/Controls/LazyFlow.cpp create mode 100644 src/Authoring/Studio/Controls/LazyFlow.h create mode 100644 src/Authoring/Studio/Controls/ListBoxItem.cpp create mode 100644 src/Authoring/Studio/Controls/ListBoxItem.h create mode 100644 src/Authoring/Studio/Controls/ListBoxStringItem.cpp create mode 100644 src/Authoring/Studio/Controls/ListBoxStringItem.h create mode 100644 src/Authoring/Studio/Controls/ListLayout.cpp create mode 100644 src/Authoring/Studio/Controls/ListLayout.h create mode 100644 src/Authoring/Studio/Controls/NameEdit.cpp create mode 100644 src/Authoring/Studio/Controls/NameEdit.h create mode 100644 src/Authoring/Studio/Controls/OverlayControl.cpp create mode 100644 src/Authoring/Studio/Controls/OverlayControl.h create mode 100644 src/Authoring/Studio/Controls/ProceduralButton.h create mode 100644 src/Authoring/Studio/Controls/Renderer.cpp create mode 100644 src/Authoring/Studio/Controls/Renderer.h create mode 100644 src/Authoring/Studio/Controls/SIcon.cpp create mode 100644 src/Authoring/Studio/Controls/SIcon.h create mode 100644 src/Authoring/Studio/Controls/ScrollController.cpp create mode 100644 src/Authoring/Studio/Controls/ScrollController.h create mode 100644 src/Authoring/Studio/Controls/Scroller.cpp create mode 100644 src/Authoring/Studio/Controls/Scroller.h create mode 100644 src/Authoring/Studio/Controls/ScrollerBackground.cpp create mode 100644 src/Authoring/Studio/Controls/ScrollerBackground.h create mode 100644 src/Authoring/Studio/Controls/ScrollerBar.cpp create mode 100644 src/Authoring/Studio/Controls/ScrollerBar.h create mode 100644 src/Authoring/Studio/Controls/ScrollerButtonControl.cpp create mode 100644 src/Authoring/Studio/Controls/ScrollerButtonControl.h create mode 100644 src/Authoring/Studio/Controls/ScrollerThumb.cpp create mode 100644 src/Authoring/Studio/Controls/ScrollerThumb.h create mode 100644 src/Authoring/Studio/Controls/SplashControl.cpp create mode 100644 src/Authoring/Studio/Controls/SplashControl.h create mode 100644 src/Authoring/Studio/Controls/SplitBar.cpp create mode 100644 src/Authoring/Studio/Controls/SplitBar.h create mode 100644 src/Authoring/Studio/Controls/Splitter.cpp create mode 100644 src/Authoring/Studio/Controls/Splitter.h create mode 100644 src/Authoring/Studio/Controls/StringEdit.cpp create mode 100644 src/Authoring/Studio/Controls/StringEdit.h create mode 100644 src/Authoring/Studio/Controls/TextButton.h create mode 100644 src/Authoring/Studio/Controls/TextEdit.cpp create mode 100644 src/Authoring/Studio/Controls/TextEdit.h create mode 100644 src/Authoring/Studio/Controls/TextEditContextMenu.cpp create mode 100644 src/Authoring/Studio/Controls/TextEditContextMenu.h create mode 100644 src/Authoring/Studio/Controls/TextEditInPlace.cpp create mode 100644 src/Authoring/Studio/Controls/TextEditInPlace.h create mode 100644 src/Authoring/Studio/Controls/TimeEdit.cpp create mode 100644 src/Authoring/Studio/Controls/TimeEdit.h create mode 100644 src/Authoring/Studio/Controls/ToggleButton.cpp create mode 100644 src/Authoring/Studio/Controls/ToggleButton.h create mode 100644 src/Authoring/Studio/Controls/TreeControl.cpp create mode 100644 src/Authoring/Studio/Controls/TreeControl.h create mode 100644 src/Authoring/Studio/Controls/TreeItem.cpp create mode 100644 src/Authoring/Studio/Controls/TreeItem.h create mode 100644 src/Authoring/Studio/Controls/WidgetControl.cpp create mode 100644 src/Authoring/Studio/Controls/WidgetControl.h create mode 100644 src/Authoring/Studio/Docs/CmdLineOptions.txt create mode 100644 src/Authoring/Studio/DragAndDrop/BasicObjectDropSource.cpp create mode 100644 src/Authoring/Studio/DragAndDrop/BasicObjectDropSource.h create mode 100644 src/Authoring/Studio/DragAndDrop/DropContainer.cpp create mode 100644 src/Authoring/Studio/DragAndDrop/DropContainer.h create mode 100644 src/Authoring/Studio/DragAndDrop/DropSource.cpp create mode 100644 src/Authoring/Studio/DragAndDrop/DropSource.h create mode 100644 src/Authoring/Studio/DragAndDrop/DropTarget.cpp create mode 100644 src/Authoring/Studio/DragAndDrop/DropTarget.h create mode 100644 src/Authoring/Studio/DragAndDrop/ExplorerFileDropSource.cpp create mode 100644 src/Authoring/Studio/DragAndDrop/ExplorerFileDropSource.h create mode 100644 src/Authoring/Studio/DragAndDrop/FileDropSource.cpp create mode 100644 src/Authoring/Studio/DragAndDrop/FileDropSource.h create mode 100644 src/Authoring/Studio/DragAndDrop/ListBoxDropSource.cpp create mode 100644 src/Authoring/Studio/DragAndDrop/ListBoxDropSource.h create mode 100644 src/Authoring/Studio/DragAndDrop/ListBoxDropTarget.cpp create mode 100644 src/Authoring/Studio/DragAndDrop/ListBoxDropTarget.h create mode 100644 src/Authoring/Studio/DragAndDrop/ProjectDropTarget.cpp create mode 100644 src/Authoring/Studio/DragAndDrop/ProjectDropTarget.h create mode 100644 src/Authoring/Studio/DragAndDrop/SceneDropTarget.cpp create mode 100644 src/Authoring/Studio/DragAndDrop/SceneDropTarget.h create mode 100644 src/Authoring/Studio/DragAndDrop/TimelineDropSource.cpp create mode 100644 src/Authoring/Studio/DragAndDrop/TimelineDropSource.h create mode 100644 src/Authoring/Studio/DragAndDrop/TimelineDropTarget.cpp create mode 100644 src/Authoring/Studio/DragAndDrop/TimelineDropTarget.h create mode 100644 src/Authoring/Studio/English.lproj/Strings/Static.stri create mode 100644 src/Authoring/Studio/English.lproj/Strings/Static.stro create mode 100644 src/Authoring/Studio/English.lproj/Strings/Strings.h create mode 100644 src/Authoring/Studio/English.lproj/Strings/StringsReadme.htm create mode 100644 src/Authoring/Studio/English.lproj/Strings/compile.py create mode 100644 src/Authoring/Studio/English.lproj/Strings/compile32.py create mode 100644 src/Authoring/Studio/MainFrm.cpp create mode 100644 src/Authoring/Studio/MainFrm.h create mode 100644 src/Authoring/Studio/MainFrm.qrc create mode 100644 src/Authoring/Studio/MainFrm.ui create mode 100644 src/Authoring/Studio/Palettes/Action/ActionContextMenu.cpp create mode 100644 src/Authoring/Studio/Palettes/Action/ActionContextMenu.h create mode 100644 src/Authoring/Studio/Palettes/Action/ActionModel.cpp create mode 100644 src/Authoring/Studio/Palettes/Action/ActionModel.h create mode 100644 src/Authoring/Studio/Palettes/Action/ActionView.cpp create mode 100644 src/Authoring/Studio/Palettes/Action/ActionView.h create mode 100644 src/Authoring/Studio/Palettes/Action/ActionView.qml create mode 100644 src/Authoring/Studio/Palettes/Action/EventsBrowser.qml create mode 100644 src/Authoring/Studio/Palettes/Action/EventsBrowserView.cpp create mode 100644 src/Authoring/Studio/Palettes/Action/EventsBrowserView.h create mode 100644 src/Authoring/Studio/Palettes/Action/EventsModel.cpp create mode 100644 src/Authoring/Studio/Palettes/Action/EventsModel.h create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerEmitSignal.qml create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerFireEvent.qml create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerGenericBaseColor.qml create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerGenericCheckbox.qml create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerGenericColor.qml create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerGenericText.qml create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerGoToSlide.qml create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerMultilineText.qml create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerProperty.qml create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseSlider.qml create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerPropertyBaseXYZ.qml create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerPropertyCombo.qml create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerPropertySlider.qml create mode 100644 src/Authoring/Studio/Palettes/Action/HandlerPropertyXYZ.qml create mode 100644 src/Authoring/Studio/Palettes/Action/PropertyModel.cpp create mode 100644 src/Authoring/Studio/Palettes/Action/PropertyModel.h create mode 100644 src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.cpp create mode 100644 src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsModel.h create mode 100644 src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.cpp create mode 100644 src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.h create mode 100644 src/Authoring/Studio/Palettes/BasicObjects/BasicObjectsView.qml create mode 100644 src/Authoring/Studio/Palettes/Inspector/ChooserDelegate.qml create mode 100644 src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/EasyInspectorGroup.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/FileChooser.qml create mode 100644 src/Authoring/Studio/Palettes/Inspector/FileChooserModel.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/FileChooserModel.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/FileChooserView.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/FileChooserView.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/GuideInspectable.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/GuideInspectable.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/HandlerFilesChooser.qml create mode 100644 src/Authoring/Studio/Palettes/Inspector/HandlerGenericChooser.qml create mode 100644 src/Authoring/Studio/Palettes/Inspector/IEasyInspectorRowListener.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/IInspectableItem.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/ImageChooser.qml create mode 100644 src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/ImageChooserModel.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/ImageChooserView.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/ImageChooserView.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/InspectableBase.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/InspectableBase.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml create mode 100644 src/Authoring/Studio/Palettes/Inspector/InspectorGroup.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/InspectorGroup.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/MeshChooser.qml create mode 100644 src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/MeshChooserModel.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/MeshChooserView.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/MeshChooserView.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/ObjectBrowser.qml create mode 100644 src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/ObjectReference.qml create mode 100644 src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/ObjectReferenceModel.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/ObjectReferenceView.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/TabOrderHandler.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/TextureChooser.qml create mode 100644 src/Authoring/Studio/Palettes/Inspector/TextureChooserView.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/TextureChooserView.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/UICDMInspectable.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/UICDMInspectorGroup.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/UICDMInspectorRow.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/UICDMMaterialInspectable.h create mode 100644 src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.cpp create mode 100644 src/Authoring/Studio/Palettes/Inspector/UICDMSceneInspectable.h create mode 100644 src/Authoring/Studio/Palettes/Master/MasterControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Master/MasterControl.h create mode 100644 src/Authoring/Studio/Palettes/Master/MasterView.cpp create mode 100644 src/Authoring/Studio/Palettes/Master/MasterView.h create mode 100644 src/Authoring/Studio/Palettes/Progress/ProgressCallback.h create mode 100644 src/Authoring/Studio/Palettes/Progress/ProgressControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Progress/ProgressControl.h create mode 100644 src/Authoring/Studio/Palettes/Project/ProjectContextMenu.cpp create mode 100644 src/Authoring/Studio/Palettes/Project/ProjectContextMenu.h create mode 100644 src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp create mode 100644 src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.h create mode 100644 src/Authoring/Studio/Palettes/Project/ProjectView.cpp create mode 100644 src/Authoring/Studio/Palettes/Project/ProjectView.h create mode 100644 src/Authoring/Studio/Palettes/Project/ProjectView.qml create mode 100644 src/Authoring/Studio/Palettes/Slide/SlideContextMenu.cpp create mode 100644 src/Authoring/Studio/Palettes/Slide/SlideContextMenu.h create mode 100644 src/Authoring/Studio/Palettes/Slide/SlideModel.cpp create mode 100644 src/Authoring/Studio/Palettes/Slide/SlideModel.h create mode 100644 src/Authoring/Studio/Palettes/Slide/SlideView.cpp create mode 100644 src/Authoring/Studio/Palettes/Slide/SlideView.h create mode 100644 src/Authoring/Studio/Palettes/Slide/SlideView.qml create mode 100644 src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/AreaBoundingRect.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/AssetTimelineKeyframe.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/BaseStateRow.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/BaseStateRow.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/BaseTimebarlessRow.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/BaseTimelineTreeControl.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/BehaviorTimelineItemBinding.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/EmptyTimelineTimebar.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/GroupTimelineItemBinding.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/IKeyframeSelector.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItem.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemProperty.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineTimebar.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/ImageTimelineItemBinding.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/KeyframesManager.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/LayerTimelineItemBinding.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/MaterialTimelineItemBinding.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/OffsetKeyframesCommandHelper.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/PasteKeyframesCommandHelper.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/PathAnchorPointTimelineItemBinding.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/PathTimelineItemBinding.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/SlideTimelineItemBinding.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineBreadCrumbProvider.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMAssetTimelineKeyframe.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimeline.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemBinding.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineItemProperty.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineKeyframe.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Bindings/UICDMTimelineTimebar.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/BlankToggleControl.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/ColorBlankControl.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/ColorControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/ColorControl.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/CommentEdit.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/CommentEdit.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/ComponentContextMenu.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/FilterToolbar.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/FilterToolbar.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/IBreadCrumbProvider.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/ITimelineControl.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/KeyframeContextMenu.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/MultiSelectAspect.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Playhead.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Playhead.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyColorControl.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyGraphKeyframe.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyRow.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyRow.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyTimebarGraph.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyTimebarRow.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyTimelineKeyframe.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyToggleControl.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/PropertyTreeControl.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/ScalableScroller.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/ScalableScroller.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/ScalableScrollerBar.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/SlideRow.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/SlideRow.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/SlideTimebarRow.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/Snapper.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/Snapper.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/StateRow.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/StateRow.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/StateRowFactory.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/StateRowFactory.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/StateTimebarRow.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/StateTimebarlessRow.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimeEditAspect.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimeMeasure.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimeMeasure.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimeToolbar.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimeToolbar.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimebarControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimebarControl.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimebarTip.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimebarTip.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineControl.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineFilter.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineFilter.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineKeyframe.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineRow.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineRow.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineSplitter.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineTimelineLayout.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/TimelineTreeLayout.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/ToggleBlankControl.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/ToggleControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/ToggleControl.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/ToggleToolbar.h create mode 100644 src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.cpp create mode 100644 src/Authoring/Studio/Palettes/Timeline/TreeBlankControl.h create mode 100644 src/Authoring/Studio/Palettes/controls/BrowserCombo.qml create mode 100644 src/Authoring/Studio/Palettes/controls/FloatTextField.qml create mode 100644 src/Authoring/Studio/Palettes/controls/StyledComboBox.qml create mode 100644 src/Authoring/Studio/Palettes/controls/StyledLabel.qml create mode 100644 src/Authoring/Studio/Palettes/controls/StyledMenuItem.qml create mode 100644 src/Authoring/Studio/Palettes/controls/StyledMenuSeparator.qml create mode 100644 src/Authoring/Studio/Palettes/controls/StyledTextField.qml create mode 100644 src/Authoring/Studio/Palettes/controls/StyledToolButton.qml create mode 100644 src/Authoring/Studio/Palettes/controls/StyledTooltip.qml create mode 100644 src/Authoring/Studio/PreviewHelper.cpp create mode 100644 src/Authoring/Studio/PreviewHelper.h create mode 100644 src/Authoring/Studio/Render/IStudioRenderer.h create mode 100644 src/Authoring/Studio/Render/PathWidget.cpp create mode 100644 src/Authoring/Studio/Render/PathWidget.h create mode 100644 src/Authoring/Studio/Render/StudioPickValues.h create mode 100644 src/Authoring/Studio/Render/StudioRenderer.cpp create mode 100644 src/Authoring/Studio/Render/StudioRendererImpl.h create mode 100644 src/Authoring/Studio/Render/StudioRendererTranslation.cpp create mode 100644 src/Authoring/Studio/Render/StudioRendererTranslation.h create mode 100644 src/Authoring/Studio/Render/StudioRotationWidget.cpp create mode 100644 src/Authoring/Studio/Render/StudioScaleWidget.cpp create mode 100644 src/Authoring/Studio/Render/StudioTranslationWidget.cpp create mode 100644 src/Authoring/Studio/Render/StudioWidget.cpp create mode 100644 src/Authoring/Studio/Render/StudioWidget.h create mode 100644 src/Authoring/Studio/Render/StudioWidgetImpl.h create mode 100644 src/Authoring/Studio/Render/WGLRenderContext.cpp create mode 100644 src/Authoring/Studio/Render/WGLRenderContext.h create mode 100644 src/Authoring/Studio/UI/ContextMenu.h create mode 100644 src/Authoring/Studio/UI/CustomReBar.cpp create mode 100644 src/Authoring/Studio/UI/CustomReBar.h create mode 100644 src/Authoring/Studio/UI/PaletteState.cpp create mode 100644 src/Authoring/Studio/UI/PaletteState.h create mode 100644 src/Authoring/Studio/Utils/CmdLineParser.cpp create mode 100644 src/Authoring/Studio/Utils/CmdLineParser.h create mode 100644 src/Authoring/Studio/Utils/ITickTock.h create mode 100644 src/Authoring/Studio/Utils/ImportUtils.cpp create mode 100644 src/Authoring/Studio/Utils/ImportUtils.h create mode 100644 src/Authoring/Studio/Utils/MouseCursor.h create mode 100644 src/Authoring/Studio/Utils/ResourceCache.cpp create mode 100644 src/Authoring/Studio/Utils/ResourceCache.h create mode 100644 src/Authoring/Studio/Utils/StringLoader.cpp create mode 100644 src/Authoring/Studio/Utils/StringLoader.h create mode 100644 src/Authoring/Studio/Utils/StudioUtils.cpp create mode 100644 src/Authoring/Studio/Utils/StudioUtils.h create mode 100644 src/Authoring/Studio/Utils/SystemPreferences.cpp create mode 100644 src/Authoring/Studio/Utils/SystemPreferences.h create mode 100644 src/Authoring/Studio/Utils/TickTock.cpp create mode 100644 src/Authoring/Studio/Workspace/Dialogs.h create mode 100644 src/Authoring/Studio/Workspace/Views/Views.h create mode 100644 src/Authoring/Studio/_Win/Application/AboutDlg.cpp create mode 100644 src/Authoring/Studio/_Win/Application/AboutDlg.h create mode 100644 src/Authoring/Studio/_Win/Application/AboutDlg.ui create mode 100644 src/Authoring/Studio/_Win/Application/BaseLink.cpp create mode 100644 src/Authoring/Studio/_Win/Application/BaseLink.h create mode 100644 src/Authoring/Studio/_Win/Application/MsgRouter.cpp create mode 100644 src/Authoring/Studio/_Win/Application/StudioApp.cpp create mode 100644 src/Authoring/Studio/_Win/Application/StudioApp.h create mode 100644 src/Authoring/Studio/_Win/Application/StudioColors.h create mode 100644 src/Authoring/Studio/_Win/Application/SubPresentationsDlg.cpp create mode 100644 src/Authoring/Studio/_Win/Application/SubPresentationsDlg.h create mode 100644 src/Authoring/Studio/_Win/Application/SubPresentationsDlg.ui create mode 100644 src/Authoring/Studio/_Win/Application/TextLink.cpp create mode 100644 src/Authoring/Studio/_Win/Application/TextLink.h create mode 100644 src/Authoring/Studio/_Win/Application/WebLink.cpp create mode 100644 src/Authoring/Studio/_Win/Application/WebLink.h create mode 100644 src/Authoring/Studio/_Win/Controls/AppFonts.cpp create mode 100644 src/Authoring/Studio/_Win/Controls/AppFonts.h create mode 100644 src/Authoring/Studio/_Win/Controls/BufferedRenderer.cpp create mode 100644 src/Authoring/Studio/_Win/Controls/BufferedRenderer.h create mode 100644 src/Authoring/Studio/_Win/Controls/MFCEditControl.cpp create mode 100644 src/Authoring/Studio/_Win/Controls/MFCEditControl.h create mode 100644 src/Authoring/Studio/_Win/Controls/OffscreenRenderer.cpp create mode 100644 src/Authoring/Studio/_Win/Controls/OffscreenRenderer.h create mode 100644 src/Authoring/Studio/_Win/Controls/PlatformEditControl.cpp create mode 100644 src/Authoring/Studio/_Win/Controls/PlatformEditControl.h create mode 100644 src/Authoring/Studio/_Win/Controls/PlatformStaticControl.cpp create mode 100644 src/Authoring/Studio/_Win/Controls/PlatformStaticControl.h create mode 100644 src/Authoring/Studio/_Win/Controls/PlatformWindowControl.cpp create mode 100644 src/Authoring/Studio/_Win/Controls/PlatformWindowControl.h create mode 100644 src/Authoring/Studio/_Win/Controls/WinRenderer.cpp create mode 100644 src/Authoring/Studio/_Win/Controls/WinRenderer.h create mode 100644 src/Authoring/Studio/_Win/Controls/WndControl.cpp create mode 100644 src/Authoring/Studio/_Win/Controls/WndControl.h create mode 100644 src/Authoring/Studio/_Win/DragNDrop/DropProxy.cpp create mode 100644 src/Authoring/Studio/_Win/DragNDrop/DropProxy.h create mode 100644 src/Authoring/Studio/_Win/DragNDrop/WinDnd.cpp create mode 100644 src/Authoring/Studio/_Win/DragNDrop/WinDnd.h create mode 100644 src/Authoring/Studio/_Win/Include/StudioPrefixWin32.h create mode 100644 src/Authoring/Studio/_Win/Palettes/PaletteManager.cpp create mode 100644 src/Authoring/Studio/_Win/Palettes/PaletteManager.h create mode 100644 src/Authoring/Studio/_Win/Palettes/Progress/ProgressPalette.cpp create mode 100644 src/Authoring/Studio/_Win/Palettes/Progress/ProgressPalette.h create mode 100644 src/Authoring/Studio/_Win/Palettes/Progress/ProgressView.cpp create mode 100644 src/Authoring/Studio/_Win/Palettes/Progress/ProgressView.h create mode 100644 src/Authoring/Studio/_Win/Palettes/Splash/SplashPalette.cpp create mode 100644 src/Authoring/Studio/_Win/Palettes/Splash/SplashPalette.h create mode 100644 src/Authoring/Studio/_Win/Palettes/Splash/SplashView.cpp create mode 100644 src/Authoring/Studio/_Win/Palettes/Splash/SplashView.h create mode 100644 src/Authoring/Studio/_Win/Studio/stdafx.cpp create mode 100644 src/Authoring/Studio/_Win/Studio/stdafx.h create mode 100644 src/Authoring/Studio/_Win/UI/ContextMenu.cpp create mode 100644 src/Authoring/Studio/_Win/UI/ControlButton.cpp create mode 100644 src/Authoring/Studio/_Win/UI/ControlButton.h create mode 100644 src/Authoring/Studio/_Win/UI/CrashDlg.cpp create mode 100644 src/Authoring/Studio/_Win/UI/CrashDlg.h create mode 100644 src/Authoring/Studio/_Win/UI/EditCameraBar.cpp create mode 100644 src/Authoring/Studio/_Win/UI/EditCameraBar.h create mode 100644 src/Authoring/Studio/_Win/UI/EditorPane.cpp create mode 100644 src/Authoring/Studio/_Win/UI/EditorPane.h create mode 100644 src/Authoring/Studio/_Win/UI/FileDialogEX.cpp create mode 100644 src/Authoring/Studio/_Win/UI/FileDialogEX.h create mode 100644 src/Authoring/Studio/_Win/UI/GLVersionDlg.cpp create mode 100644 src/Authoring/Studio/_Win/UI/GLVersionDlg.h create mode 100644 src/Authoring/Studio/_Win/UI/InterpolationDlg.cpp create mode 100644 src/Authoring/Studio/_Win/UI/InterpolationDlg.h create mode 100644 src/Authoring/Studio/_Win/UI/InterpolationDlg.ui create mode 100644 src/Authoring/Studio/_Win/UI/MemoryDC.cpp create mode 100644 src/Authoring/Studio/_Win/UI/MemoryDC.h create mode 100644 src/Authoring/Studio/_Win/UI/MenuEdit.cpp create mode 100644 src/Authoring/Studio/_Win/UI/MenuEdit.h create mode 100644 src/Authoring/Studio/_Win/UI/MenuItem.cpp create mode 100644 src/Authoring/Studio/_Win/UI/MenuItem.h create mode 100644 src/Authoring/Studio/_Win/UI/NumericEdit.cpp create mode 100644 src/Authoring/Studio/_Win/UI/NumericEdit.h create mode 100644 src/Authoring/Studio/_Win/UI/PlayerContainerWnd.cpp create mode 100644 src/Authoring/Studio/_Win/UI/PlayerContainerWnd.h create mode 100644 src/Authoring/Studio/_Win/UI/PlayerWnd.cpp create mode 100644 src/Authoring/Studio/_Win/UI/PlayerWnd.h create mode 100644 src/Authoring/Studio/_Win/UI/PopupWnd.cpp create mode 100644 src/Authoring/Studio/_Win/UI/PopupWnd.h create mode 100644 src/Authoring/Studio/_Win/UI/PreviewOutputDlg.cpp create mode 100644 src/Authoring/Studio/_Win/UI/PreviewOutputDlg.h create mode 100644 src/Authoring/Studio/_Win/UI/RecentItems.cpp create mode 100644 src/Authoring/Studio/_Win/UI/RecentItems.h create mode 100644 src/Authoring/Studio/_Win/UI/ReportDlg.cpp create mode 100644 src/Authoring/Studio/_Win/UI/ReportDlg.h create mode 100644 src/Authoring/Studio/_Win/UI/ResetKeyframeValuesDlg.cpp create mode 100644 src/Authoring/Studio/_Win/UI/ResetKeyframeValuesDlg.h create mode 100644 src/Authoring/Studio/_Win/UI/SceneView.cpp create mode 100644 src/Authoring/Studio/_Win/UI/SceneView.h create mode 100644 src/Authoring/Studio/_Win/UI/StartupDlg.cpp create mode 100644 src/Authoring/Studio/_Win/UI/StartupDlg.h create mode 100644 src/Authoring/Studio/_Win/UI/StartupDlg.ui create mode 100644 src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.cpp create mode 100644 src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.h create mode 100644 src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.ui create mode 100644 src/Authoring/Studio/_Win/UI/StudioPaletteBar.cpp create mode 100644 src/Authoring/Studio/_Win/UI/StudioPaletteBar.h create mode 100644 src/Authoring/Studio/_Win/UI/StudioPreferencesPropSheet.cpp create mode 100644 src/Authoring/Studio/_Win/UI/StudioPreferencesPropSheet.h create mode 100644 src/Authoring/Studio/_Win/UI/StudioPreferencesPropSheet.ui create mode 100644 src/Authoring/Studio/_Win/UI/StudioProjectSettingsPage.cpp create mode 100644 src/Authoring/Studio/_Win/UI/StudioProjectSettingsPage.h create mode 100644 src/Authoring/Studio/_Win/UI/StudioProjectSettingsPage.ui create mode 100644 src/Authoring/Studio/_Win/UI/TimeEditDlg.cpp create mode 100644 src/Authoring/Studio/_Win/UI/TimeEditDlg.h create mode 100644 src/Authoring/Studio/_Win/UI/timeeditdlg.ui create mode 100644 src/Authoring/Studio/_Win/Utils/MouseCursor.cpp create mode 100644 src/Authoring/Studio/_Win/Utils/WinUtils.cpp create mode 100644 src/Authoring/Studio/_Win/Utils/WinUtils.h create mode 100644 src/Authoring/Studio/_Win/Workspace/Dialogs.cpp create mode 100644 src/Authoring/Studio/_Win/Workspace/Views.cpp create mode 100644 src/Authoring/Studio/images.qrc create mode 100644 src/Authoring/Studio/images/Action-Action.png create mode 100644 src/Authoring/Studio/images/Action-ChildAction.png create mode 100644 src/Authoring/Studio/images/Action-ChildMasterAction.png create mode 100644 src/Authoring/Studio/images/Action-ComponentAction.png create mode 100644 src/Authoring/Studio/images/Action-ComponentMasterAction.png create mode 100644 src/Authoring/Studio/images/Action-MasterAction.png create mode 100644 src/Authoring/Studio/images/Action-Trash-Disabled.png create mode 100644 src/Authoring/Studio/images/Action-Trash-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Action-Trash-Normal.png create mode 100644 src/Authoring/Studio/images/Action-Trash-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Asset-Alias-Normal.png create mode 100644 src/Authoring/Studio/images/Asset-Alias-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Asset-Camera-Normal.png create mode 100644 src/Authoring/Studio/images/Asset-Camera-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Asset-Component-Normal.png create mode 100644 src/Authoring/Studio/images/Asset-Component-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Asset-Cone-Normal.png create mode 100644 src/Authoring/Studio/images/Asset-Cone-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Asset-Cube-Normal.png create mode 100644 src/Authoring/Studio/images/Asset-Cube-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Asset-Cylinder-Normal.png create mode 100644 src/Authoring/Studio/images/Asset-Cylinder-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Asset-Group-Normal.png create mode 100644 src/Authoring/Studio/images/Asset-Group-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Asset-Layer-Normal.png create mode 100644 src/Authoring/Studio/images/Asset-Layer-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Asset-Light-Normal.png create mode 100644 src/Authoring/Studio/images/Asset-Light-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Asset-Rectangle-Normal.png create mode 100644 src/Authoring/Studio/images/Asset-Rectangle-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Asset-Sphere-Normal.png create mode 100644 src/Authoring/Studio/images/Asset-Sphere-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Asset-Text-Normal.png create mode 100644 src/Authoring/Studio/images/Asset-Text-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Insert-Left.png create mode 100644 src/Authoring/Studio/images/Insert-Rearrange-Left.png create mode 100644 src/Authoring/Studio/images/Insert-Rearrange-Right.png create mode 100644 src/Authoring/Studio/images/Insert-Right.png create mode 100644 src/Authoring/Studio/images/Inspector-AnimateToggle-Active.png create mode 100644 src/Authoring/Studio/images/Inspector-AnimateToggle-Active@2x.png create mode 100644 src/Authoring/Studio/images/Inspector-AnimateToggle-Normal.png create mode 100644 src/Authoring/Studio/images/Inspector-AnimateToggle-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Keyframe-Master-Disabled.png create mode 100644 src/Authoring/Studio/images/Keyframe-Master-Normal.png create mode 100644 src/Authoring/Studio/images/Keyframe-Master-Selected.png create mode 100644 src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.png create mode 100644 src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.png create mode 100644 src/Authoring/Studio/images/Keyframe-MasterLeft-Normal.png create mode 100644 src/Authoring/Studio/images/Keyframe-MasterLeft-Selected.png create mode 100644 src/Authoring/Studio/images/Keyframe-MasterLeft-disabled.png create mode 100644 src/Authoring/Studio/images/Keyframe-MasterLeftDynamic-Normal.png create mode 100644 src/Authoring/Studio/images/Keyframe-MasterLeftDynamic-Selected.png create mode 100644 src/Authoring/Studio/images/Keyframe-MasterRight-Normal.png create mode 100644 src/Authoring/Studio/images/Keyframe-MasterRight-Selected.png create mode 100644 src/Authoring/Studio/images/Keyframe-MasterRight-disabled.png create mode 100644 src/Authoring/Studio/images/Keyframe-MasterRightDynamic-Normal.png create mode 100644 src/Authoring/Studio/images/Keyframe-MasterRightDynamic-Selected.png create mode 100644 src/Authoring/Studio/images/Keyframe-Property-Disabled.png create mode 100644 src/Authoring/Studio/images/Keyframe-Property-Normal.png create mode 100644 src/Authoring/Studio/images/Keyframe-Property-Selected.png create mode 100644 src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.png create mode 100644 src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.png create mode 100644 src/Authoring/Studio/images/Objects-Alias-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Alias-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Alias-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Alias-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Behavior-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Behavior-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Behavior-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Behavior-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Camera-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Camera-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Camera-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Camera-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Component-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Component-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Component-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Component-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Effect-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Effect-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Effect-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Effect-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Folder-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Folder-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Folder-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Folder-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Group-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Group-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Group-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Group-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Image-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Image-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Image-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Image-Normal@2.png create mode 100644 src/Authoring/Studio/images/Objects-Layer-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Layer-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Layer-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Layer-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Light-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Light-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Light-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Light-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Material-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Material-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Material-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Material-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Model-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Model-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Model-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Model-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Property-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Property-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Property-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Property-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Scene-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Scene-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Scene-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Scene-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Text-Disabled.png create mode 100644 src/Authoring/Studio/images/Objects-Text-Disabled@2x.png create mode 100644 src/Authoring/Studio/images/Objects-Text-Normal.png create mode 100644 src/Authoring/Studio/images/Objects-Text-Normal@2x.png create mode 100644 src/Authoring/Studio/images/PlaybackHead.png create mode 100644 src/Authoring/Studio/images/PlaybackHead@2x.png create mode 100644 src/Authoring/Studio/images/Slide-Active.png create mode 100644 src/Authoring/Studio/images/Slide-Active@2x.png create mode 100644 src/Authoring/Studio/images/Slide-Master-Active.png create mode 100644 src/Authoring/Studio/images/Slide-Master-Active@2x.png create mode 100644 src/Authoring/Studio/images/Slide-Normal.png create mode 100644 src/Authoring/Studio/images/Slide-Normal@2x.png create mode 100644 src/Authoring/Studio/images/Toggle-Empty.png create mode 100644 src/Authoring/Studio/images/Toggle-HideShow-disabled.png create mode 100644 src/Authoring/Studio/images/Toggle-HideShow-disabled@2x.png create mode 100644 src/Authoring/Studio/images/Toggle-HideShow.png create mode 100644 src/Authoring/Studio/images/Toggle-HideShow@2x.png create mode 100644 src/Authoring/Studio/images/Toggle-Lock.png create mode 100644 src/Authoring/Studio/images/Toggle-Lock@2x.png create mode 100644 src/Authoring/Studio/images/Toggle-Shy.png create mode 100644 src/Authoring/Studio/images/Toggle-Shy@2x.png create mode 100644 src/Authoring/Studio/images/add.png create mode 100644 src/Authoring/Studio/images/add@2x.png create mode 100644 src/Authoring/Studio/images/arrow.png create mode 100644 src/Authoring/Studio/images/arrow@2x.png create mode 100644 src/Authoring/Studio/images/arrow_down.png create mode 100644 src/Authoring/Studio/images/arrow_down@2x.png create mode 100644 src/Authoring/Studio/images/breadcrumb_component_button.png create mode 100644 src/Authoring/Studio/images/breadcrumb_component_colon_button.png create mode 100644 src/Authoring/Studio/images/breadcrumb_component_grey_button.png create mode 100644 src/Authoring/Studio/images/breadcrumb_component_scene.png create mode 100644 src/Authoring/Studio/images/checkbox-checked.png create mode 100644 src/Authoring/Studio/images/checkbox-unchecked.png create mode 100644 src/Authoring/Studio/images/empty-pixel.png create mode 100644 src/Authoring/Studio/images/filter-shy-down.png create mode 100644 src/Authoring/Studio/images/filter-shy-down@2x.png create mode 100644 src/Authoring/Studio/images/filter-toggle-eye-down.png create mode 100644 src/Authoring/Studio/images/filter-toggle-eye-down@2x.png create mode 100644 src/Authoring/Studio/images/filter-toggle-eye-up.png create mode 100644 src/Authoring/Studio/images/filter-toggle-eye-up@2x.png create mode 100644 src/Authoring/Studio/images/obsolete_placeholder.png create mode 100644 src/Authoring/Studio/images/scrollbar-arrows-down-depressed.png create mode 100644 src/Authoring/Studio/images/scrollbar-arrows-down-disabled.png create mode 100644 src/Authoring/Studio/images/scrollbar-arrows-down-normal.png create mode 100644 src/Authoring/Studio/images/scrollbar-arrows-left-depressed.png create mode 100644 src/Authoring/Studio/images/scrollbar-arrows-left-disabled.png create mode 100644 src/Authoring/Studio/images/scrollbar-arrows-left-normal.png create mode 100644 src/Authoring/Studio/images/scrollbar-arrows-right-depressed.png create mode 100644 src/Authoring/Studio/images/scrollbar-arrows-right-disabled.png create mode 100644 src/Authoring/Studio/images/scrollbar-arrows-right-normal.png create mode 100644 src/Authoring/Studio/images/scrollbar-arrows-up-depressed.png create mode 100644 src/Authoring/Studio/images/scrollbar-arrows-up-disabled.png create mode 100644 src/Authoring/Studio/images/scrollbar-arrows-up-normal.png create mode 100644 src/Authoring/Studio/images/timebarhandle-disabled-left.png create mode 100644 src/Authoring/Studio/images/timebarhandle-disabled-right.png create mode 100644 src/Authoring/Studio/images/timebarhandle-left.png create mode 100644 src/Authoring/Studio/images/timebarhandle-right.png create mode 100644 src/Authoring/Studio/qt3dstudio.qrc create mode 100644 src/Authoring/Studio/remoteproject.cpp create mode 100644 src/Authoring/Studio/remoteproject.h create mode 100644 src/Authoring/Studio/res/About Icon.bmp create mode 100644 src/Authoring/Studio/res/Flippy-Right.bmp create mode 100644 src/Authoring/Studio/res/Flippy-down.bmp create mode 100644 src/Authoring/Studio/res/Studio.ico create mode 100644 src/Authoring/Studio/res/Studio.manifest create mode 100644 src/Authoring/Studio/res/Studio.png create mode 100644 src/Authoring/Studio/res/StudioDoc.ico create mode 100644 src/Authoring/Studio/res/Toolbar-00.png create mode 100644 src/Authoring/Studio/res/Toolbar-01.png create mode 100644 src/Authoring/Studio/res/Toolbar-02.png create mode 100644 src/Authoring/Studio/res/Toolbar-03.png create mode 100644 src/Authoring/Studio/res/Toolbar-04.png create mode 100644 src/Authoring/Studio/res/Toolbar-05.png create mode 100644 src/Authoring/Studio/res/Toolbar-06.png create mode 100644 src/Authoring/Studio/res/Toolbar-07.png create mode 100644 src/Authoring/Studio/res/Toolbar.bmp create mode 100644 src/Authoring/Studio/res/Tutorial/button_back.png create mode 100644 src/Authoring/Studio/res/Tutorial/button_back@2x.png create mode 100644 src/Authoring/Studio/res/Tutorial/button_next.png create mode 100644 src/Authoring/Studio/res/Tutorial/button_next@2x.png create mode 100644 src/Authoring/Studio/res/Tutorial/screens/1.png create mode 100644 src/Authoring/Studio/res/Tutorial/screens/2.png create mode 100644 src/Authoring/Studio/res/Tutorial/screens/3.png create mode 100644 src/Authoring/Studio/res/Tutorial/screens/4.png create mode 100644 src/Authoring/Studio/res/Tutorial/screens/5.png create mode 100644 src/Authoring/Studio/res/Tutorial/screens/6.png create mode 100644 src/Authoring/Studio/res/Tutorial/screens/7.png create mode 100644 src/Authoring/Studio/res/arrow_down.png create mode 100644 src/Authoring/Studio/res/arrow_down@2x.png create mode 100644 src/Authoring/Studio/res/client_tools_grayed_out.bmp create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-00.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-00@2x.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-01.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-01@2x.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-02.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-02@2x.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-03.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-03@2x.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-04.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-04@2x.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-05.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-05@2x.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-06.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color-06@2x.png create mode 100644 src/Authoring/Studio/res/client_tools_hi_color.bmp create mode 100644 src/Authoring/Studio/res/client_tools_low_color.bmp create mode 100644 src/Authoring/Studio/res/cursors.bmp create mode 100644 src/Authoring/Studio/res/edit_camera_pan.png create mode 100644 src/Authoring/Studio/res/edit_camera_rot.png create mode 100644 src/Authoring/Studio/res/edit_camera_zoom.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_disabled.bmp create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-00.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-00@2x.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-00_disabled.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-00_disabled@2x.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-01.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-01@2x.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-01_disabled.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-01_disabled@2x.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-02.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-02@2x.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-02_disabled.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-02_disabled@2x.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-03.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-03@2x.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-03_disabled.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-03_disabled@2x.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-04.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-04@2x.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-04_disabled.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-04_disabled@2x.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-05.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-05@2x.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-05_disabled.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi-05_disabled@2x.png create mode 100644 src/Authoring/Studio/res/editcamera_tools_hi.bmp create mode 100644 src/Authoring/Studio/res/editcamera_tools_low.bmp create mode 100644 src/Authoring/Studio/res/group_move.png create mode 100644 src/Authoring/Studio/res/group_rotate.png create mode 100644 src/Authoring/Studio/res/group_scale.png create mode 100644 src/Authoring/Studio/res/item_move.png create mode 100644 src/Authoring/Studio/res/item_rotate.png create mode 100644 src/Authoring/Studio/res/item_scale.png create mode 100644 src/Authoring/Studio/res/keyframe.bmp create mode 100644 src/Authoring/Studio/res/library_buttons_hi_color.bmp create mode 100644 src/Authoring/Studio/res/library_buttons_low_color.bmp create mode 100644 src/Authoring/Studio/res/libtoolb.bmp create mode 100644 src/Authoring/Studio/res/menubtn_down.bmp create mode 100644 src/Authoring/Studio/res/menubtn_normal.bmp create mode 100644 src/Authoring/Studio/res/menubtn_selected.bmp create mode 100644 src/Authoring/Studio/res/menuedit.bmp create mode 100644 src/Authoring/Studio/res/menutool.bmp create mode 100644 src/Authoring/Studio/res/open_dialog.png create mode 100644 src/Authoring/Studio/res/playback_tools_grayed.bmp create mode 100644 src/Authoring/Studio/res/playback_tools_hi.bmp create mode 100644 src/Authoring/Studio/res/playback_tools_low-00.png create mode 100644 src/Authoring/Studio/res/playback_tools_low-00@2x.png create mode 100644 src/Authoring/Studio/res/playback_tools_low-01.png create mode 100644 src/Authoring/Studio/res/playback_tools_low-01@2x.png create mode 100644 src/Authoring/Studio/res/playback_tools_low-02.png create mode 100644 src/Authoring/Studio/res/playback_tools_low-02@2x.png create mode 100644 src/Authoring/Studio/res/playback_tools_low-03.png create mode 100644 src/Authoring/Studio/res/playback_tools_low-03@2x.png create mode 100644 src/Authoring/Studio/res/playback_tools_low.bmp create mode 100644 src/Authoring/Studio/res/prefstab-00.png create mode 100644 src/Authoring/Studio/res/prefstab-00@2x.png create mode 100644 src/Authoring/Studio/res/prefstab-01.png create mode 100644 src/Authoring/Studio/res/prefstab-01@2x.png create mode 100644 src/Authoring/Studio/res/prefstab.bmp create mode 100644 src/Authoring/Studio/res/preview_tools.bmp create mode 100644 src/Authoring/Studio/res/project-icon-new.bmp create mode 100644 src/Authoring/Studio/res/project-icon-open.bmp create mode 100644 src/Authoring/Studio/res/qt3ds_header.bmp create mode 100644 src/Authoring/Studio/res/separator.png create mode 100644 src/Authoring/Studio/res/separator@2x.png create mode 100644 src/Authoring/Studio/res/stmtool.bmp create mode 100644 src/Authoring/Studio/res/storagep.bmp create mode 100644 src/Authoring/Studio/res/tmchmenu.bmp create mode 100644 src/Authoring/Studio/res/tmlntool.bmp create mode 100644 src/Authoring/Studio/res/tmtbmenu.bmp create mode 100644 src/Authoring/Studio/res/weblinkc.bmp create mode 100644 src/Authoring/Studio/res/winxp1.bin create mode 100644 src/Authoring/Studio/style.qss create mode 100644 src/Authoring/Studio/version.h (limited to 'src/Authoring/Studio') diff --git a/src/Authoring/Studio/Application/MsgRouter.h b/src/Authoring/Studio/Application/MsgRouter.h new file mode 100644 index 00000000..78dbf4f6 --- /dev/null +++ b/src/Authoring/Studio/Application/MsgRouter.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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_MSG_ROUTER_H +#define INCLUDED_MSG_ROUTER_H 1 +#pragma once + +//============================================================================== +// Defines +//============================================================================== + +//============================================================================== +// Includes +//============================================================================== +#include "StudioConst.h" + +#include +#include + +//============================================================================== +// Forwards +//============================================================================== +class CCmd; +class CCore; + +class CRoutedMessageBase +{ +public: + CRoutedMessageBase() {} + virtual ~CRoutedMessageBase() {} + + virtual void Notify() = 0; +}; + +template +class CRoutedMessageImpl : public CRoutedMessageBase +{ +protected: + typedef void (TObject::*TMethod)(const TData &); + +public: + TObject *m_Object; + TMethod m_Method; + TData m_Data; + + CRoutedMessageImpl(TObject *inObject, TMethod inMethod, const TData &inData) + : m_Object(inObject) + , m_Method(inMethod) + , m_Data(inData) + { + } + + virtual void Notify() { (m_Object->*m_Method)(m_Data); } +}; + +//============================================================================== +/** + * Routes user-defined messages between different threads of an application. + */ +class CMsgRouter : public QObject +{ +protected: + class SMessageData; + +public: + typedef void (CMsgRouter::*TMainThreadMethod)(SMessageData *inMessageData); + +public: + static CMsgRouter *GetInstance(); + virtual ~CMsgRouter(); + + void SendCommand(CCmd *inCommand, CCore *inCore); + +protected: + bool eventFilter(QObject *watched, QEvent *event) override; + + CMsgRouter(); ///< This is a singleton so the constructor is not public (call GetInstance) + + class SMessageData : public QEvent + { + public: + SMessageData(int eventType); + + TMainThreadMethod Method; + void *Data; + void *Data2; + }; + + void OnAsyncNotification(SMessageData *inMessageData); + void OnCommand(SMessageData *inMessageData); + +private: + int m_eventType; +}; + +#endif // INCLUDED_MSG_ROUTER_H diff --git a/src/Authoring/Studio/Application/StudioConst.h b/src/Authoring/Studio/Application/StudioConst.h new file mode 100644 index 00000000..6463cb7d --- /dev/null +++ b/src/Authoring/Studio/Application/StudioConst.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#pragma once +// User Windows messages +#ifndef WM_APP +#define WM_APP 0x8000 +#endif +#define WM_STUDIO_INITIALIZE_PALETTES (WM_APP + 1) +#define WM_STUDIO_DUPLICATE_SERIAL (WM_APP + 2) +#define WM_STUDIO_SHOWCOMPRESSION (WM_APP + 3) +#define WM_STUDIO_LOADPROGRESS (WM_APP + 4) +#define WM_STUDIO_NOTIFYLOADCOMPLETE (WM_APP + 5) +#define WM_STUDIO_TIMER (WM_APP + 6) +#define WM_STUDIO_MESSAGE_ROUTER (WM_APP + 7) +#define WM_STUDIO_OPEN_RECENT_MIN (WM_APP + 9) +#define WM_STUDIO_OPEN_RECENT_MAX (WM_APP + 19) +#define WM_STUDIO_QUICKSTART_MIN (WM_APP + 31) +#define WM_STUDIO_QUICKSTART_MAX (WM_APP + 44) +#define WM_CUSTOMIZE_TOOLBAR (WM_APP + 45) + +enum EPreviewApplication { INTERNET_EXPLORER = 0, UIC_MEDIA_PLAYER, WINDOWS_MEDIA_PLAYER }; + +// property pages +const long PAGE_STUDIOAPPPREFERENCES = 0; +const long PAGE_STUDIOPROJECTSETTINGS = 1; + +// Playhead moving with keyboard: +const long SHIFT_PLAYHEAD_SMALL_TICK = 0; +const long SHIFT_PLAYHEAD_LARGE_TICK = 1; + +// Used to reset default preferences +const long PREFS_RESET_DEFAULTS = 999; + +// Message values +#define STUDIO_PLAYHEADUPDATEONLY -1 +#define STUDIO_PLAYHEADSYNCPRESENTATION -2 + +const unsigned long PARAMINDEX_RED = 0; +const unsigned long PARAMINDEX_GREEN = 1; +const unsigned long PARAMINDEX_BLUE = 2; +const unsigned long PARAMINDEX_ALPHA = 3; + +const unsigned long PARAMINDEX_X = 0; +const unsigned long PARAMINDEX_Y = 1; +const unsigned long PARAMINDEX_Z = 2; + +// These are the new operation update masks +namespace FILTERMASK { +const long FILTER_MODELS = 0x02; // Mask for filtering out Models +const long FILTER_IMAGES = 0x20; // Mask for filtering out Images +const long FILTER_ALL = 0xff; // Used for adding all files back to display mode +} + +// Used for timebar display - should we display Comments or Time Start/End/Duration information? +const long TIMEBAR_COMMENTS = 1; +const long TIMEBAR_TIMEINFO = 2; + +// Used to set the number of decimal places in the float dialog boxes. +const long FLOAT_NUM_DECIMAL_PLACES = 3; + +// Default palette positions +const long DEFAULT_MAINFRM_STARTWIDTH = 25; +const long DEFAULT_MAINFRM_WIDTH = 50; +const long DEFAULT_MAINFRM_STARTHEIGHT = 0; +const long DEFAULT_MAINFRM_HEIGHT = 50; + +const long DEFAULT_INSPECTOR_STARTHEIGHT = 50; +const long DEFAULT_INSPECTOR_HEIGHT = 50; +const long DEFAULT_INSPECTOR_STARTWIDTH = 0; +const long DEFAULT_INSPECTOR_WIDTH = 25; + +const long DEFAULT_LIBRARY_STARTHEIGHT = 0; +const long DEFAULT_LIBRARY_HEIGHT = 50; +const long DEFAULT_LIBRARY_STARTWIDTH = 0; +const long DEFAULT_LIBRARY_WIDTH = 25; + +const long DEFAULT_TIMELINE_STARTHEIGHT = 50; +const long DEFAULT_TIMELINE_HEIGHT = 50; +const long DEFAULT_TIMELINE_STARTWIDTH = 25; +const long DEFAULT_TIMELINE_WIDTH = 75; + +const long DEFAULT_HISTORY_STARTHEIGHT = 0; +const long DEFAULT_HISTORY_HEIGHT = 50; +const long DEFAULT_HISTORY_STARTWIDTH = 75; +const long DEFAULT_HISTORY_WIDTH = 25; + +const long DEFAULT_STORAGE_STARTHEIGHT = 0; +const long DEFAULT_STORAGE_HEIGHT = 50; +const long DEFAULT_STORAGE_STARTWIDTH = 75; +const long DEFAULT_STORAGE_WIDTH = 25; + +const long DEFAULT_HELP_STARTHEIGHT = 25; +const long DEFAULT_HELP_HEIGHT = 50; +const long DEFAULT_HELP_STARTWIDTH = 25; +const long DEFAULT_HELP_WIDTH = 50; + +// Port number for serial number verification on the LAN +const long SERIAL_NUMBER_PORT = 3133; +const long SERIAL_NUMBER_BASE = 10; +const long NUMBER_SERIAL_DIGITS_CHECK = 12; + +// Constants for AKTRACE statements +// These are bitmasks - must be sequential and not overlap. +const long TRACE_STUDIO_OBJECT = 0x0001; +const long TRACE_TIMELINE = 0x0002; +const long TRACE_KEYFRAMEDATA = 0x0004; +const long TRACE_ANIMTRACKS = 0x0008; +const long TRACE_UNDOREDO = 0x0010; +const long TRACE_LIBRARY = 0x0020; +const long TRACE_MSGHANDLER = 0x0040; +const long TRACE_SNAPPING = 0x0080; +const long TRACE_INSPECTOR = 0x0100; +const long TRACE_CLIENT = 0x0200; +const long TRACE_STORAGE = 0x0400; +const long TRACE_TESTING = 0x0800; +const long TRACE_HELPVIEW = 0x1000; +const long TRACE_STUDIODOC = 0x2000; +const long TRACE_MAINFRAME = 0x4000; +const long TRACE_ALL = 0xffff; + +const char CLIENT_CORE_DLL_NAME[] = "AKCore.dll"; + +// Timeline icon dimensions +const long TREEICON_WIDTH = 14; +const long TREEICON_HEIGHT = 14; +const long TIMER_DRAGHOVEREXPAND = 2; +const long TIMER_DRAGDROPSCROLL = 1; +const long DRAGSCROLL_DIRECTION_UP = 1; +const long DRAGSCROLL_DIRECTION_DOWN = 2; +const long TIMER_DRAGDROPSCROLL_DELAY = 20; +const long TIMER_DRAGHOVEREXPAND_DELAY = 1500; // 2000; // 3-second delay diff --git a/src/Authoring/Studio/Application/StudioDefs.h b/src/Authoring/Studio/Application/StudioDefs.h new file mode 100644 index 00000000..16465427 --- /dev/null +++ b/src/Authoring/Studio/Application/StudioDefs.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2002 Anark Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 STUDIO_DEFINITIONS_H +#define STUDIO_DEFINITIONS_H 1 +// NOTE: no #pragma once otherwise Mac will not compile + +//============================================================================== +// Definitions +//============================================================================== + +// Copyright date (year only) used through out the Studio program; must be a quoted string. +#define STUDIO_COPYRIGHT_YEAR "2017" + +#endif // STUDIO_DEFINITIONS_H diff --git a/src/Authoring/Studio/Application/StudioInstance.cpp b/src/Authoring/Studio/Application/StudioInstance.cpp new file mode 100644 index 00000000..177e82c0 --- /dev/null +++ b/src/Authoring/Studio/Application/StudioInstance.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$ +** +****************************************************************************/ + +#include "stdafx.h" +#include "StudioInstance.h" +#include "StudioPreferences.h" + +// using namespace Q3DStudio; <-- Do not do this here because it will conflict with CList and make +// the template generator go blah + +CProductInstance *CStudioInstance::GenerateProductInstance() +{ + CProductInstance *theRetVal = new CProductInstance("UIComposer Studio"); + // CProductInstance* theClient = new CProductInstance( "Client" ); + + // theRetVal->AddProduct( "AKPluWAV.dll" ); + // theRetVal->AddProduct( "AKPluIMG.dll" ); + // theRetVal->AddProduct( "AKPlu3DS.dll" ); + // This section will soon be a call into the client dll + /* + theClient->AddProduct( "AKCore.dll" ); + theClient->AddProduct( "AKCorENU.dll" ); + theClient->AddProduct( "AKProENU.dll" ); + theRetVal->AddInstance( theClient ); + */ + + long theMajorVersion = 0; + long theMinorVersion = 0; + long theIterationNumber = 0; + long theBuildNumber = 0; + Q3DStudio::CString theUnparsedNumber; + Q3DStudio::CString theStudioVersion = CStudioPreferences::GetVersionString(); + + int theIndex = theStudioVersion.Find('.'); + if (theIndex != Q3DStudio::CString::ENDOFSTRING) { + theUnparsedNumber = theStudioVersion.Extract(0, theIndex); + theMajorVersion = atoi(theUnparsedNumber.GetCharStar()); + theStudioVersion = theStudioVersion.Extract(theIndex + 1); + } + + theIndex = theStudioVersion.Find('.'); + if (theIndex != Q3DStudio::CString::ENDOFSTRING) { + theUnparsedNumber = theStudioVersion.Extract(0, theIndex); + theMinorVersion = atoi(theUnparsedNumber.GetCharStar()); + theStudioVersion = theStudioVersion.Extract(theIndex + 1); + } + + theIndex = theStudioVersion.Find('.'); + if (theIndex != Q3DStudio::CString::ENDOFSTRING) { + theUnparsedNumber = theStudioVersion.Extract(0, theIndex); + theIterationNumber = atoi(theUnparsedNumber.GetCharStar()); + theStudioVersion = theStudioVersion.Extract(theIndex + 1); + } + + theBuildNumber = atoi(theStudioVersion.GetCharStar()); + + theRetVal->AddProduct("Studio.exe", theMajorVersion, theMinorVersion, theIterationNumber, + theBuildNumber); + return theRetVal; +} diff --git a/src/Authoring/Studio/Application/StudioInstance.h b/src/Authoring/Studio/Application/StudioInstance.h new file mode 100644 index 00000000..d2df3e24 --- /dev/null +++ b/src/Authoring/Studio/Application/StudioInstance.h @@ -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$ +** +****************************************************************************/ + +#ifndef INCLUDED_STUDIO_INSTANCE_H +#define INCLUDED_STUDIO_INSTANCE_H 1 + +#pragma once +#include "ProductInstance.h" + +//============================================================================== +/** + * @class CStudioInstance + * @brief Generates a product instance for studio. + * The product instance is essentially a set of modules and a name, and could have + * one or more product instances inside of it. + */ +class CStudioInstance +{ +public: + static CProductInstance *GenerateProductInstance(); +}; + +#endif // INCLUDED_STUDIO_INSTANCE_H \ No newline at end of file diff --git a/src/Authoring/Studio/Application/StudioTutorialWidget.cpp b/src/Authoring/Studio/Application/StudioTutorialWidget.cpp new file mode 100644 index 00000000..d354d731 --- /dev/null +++ b/src/Authoring/Studio/Application/StudioTutorialWidget.cpp @@ -0,0 +1,236 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "StudioTutorialWidget.h" +#include "ui_StudioTutorialWidget.h" +#include "StudioUtils.h" + +StudioTutorialWidget::StudioTutorialWidget(bool goToFileDialog) : + m_ui(new Ui::StudioTutorialWidget), + m_welcomeImages(0), + m_imgIter(0), + m_palette(0), + m_displayScale(1.0) +{ + m_ui->setupUi(this); + + connect(m_ui->studioTutorialBack, &QPushButton::released, this, + &StudioTutorialWidget::handleBack); + connect(m_ui->studioTutorialForward, &QPushButton::released, this, + &StudioTutorialWidget::handleFwd); + connect(m_ui->studioTutorialShowAgain, &QCheckBox::stateChanged, this, + &StudioTutorialWidget::handleDoNotShowAgainChange); + connect(m_ui->studioTutorialNew, &QPushButton::released, this, + &StudioTutorialWidget::handleCreateNew); + connect(m_ui->studioTutorialOpen, &QPushButton::released, this, + &StudioTutorialWidget::handleOpenSample); + + OnInitDialog(goToFileDialog); +} + +StudioTutorialWidget::~StudioTutorialWidget() +{ + delete m_ui; + delete m_welcomeImages; + delete m_palette; +} + +void StudioTutorialWidget::OnInitDialog(bool goToFileDialog) +{ + m_welcomeImages = new QList(); + + // populate welcome screen images + getImageList(); + m_imgIter = m_welcomeImages->begin(); + + // do we go straight to last page with file dialog buttons? + int page = goToFileDialog ? m_welcomeImages->size() - 1 : 0; + // based on first PNG, get the scale that we need to fit welcome + // screen and buttons comfortably on display + m_displayScale = getDisplayScalingForImage(m_imgIter); + + if (!m_welcomeImages->isEmpty()) { + for (int i = 0; i < page && m_imgIter != m_welcomeImages->end(); ++i) + m_imgIter++; + + m_ui->studioTutorialShowAgain->setVisible(false); + if (*m_imgIter == m_welcomeImages->last() || m_imgIter == m_welcomeImages->end()) { + if (m_imgIter == m_welcomeImages->end()) + m_imgIter--; + m_ui->studioTutorialForward->setVisible(false); + m_ui->studioTutorialOpen->setVisible(true); + m_ui->studioTutorialNew->setVisible(true); + } else { + if (m_imgIter == m_welcomeImages->begin()) { + m_ui->studioTutorialBack->setVisible(false); + m_ui->studioTutorialShowAgain->setVisible(true); + } + m_ui->studioTutorialOpen->setVisible(false); + m_ui->studioTutorialNew->setVisible(false); + } + } + + QSettings settings; + m_ui->studioTutorialShowAgain->setChecked(!settings.value("showWelcomeScreen").toBool()); + + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); +} + +void StudioTutorialWidget::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + if (m_palette) + return; + + m_palette = new QPalette; + QPixmap pic = getScaledPic(m_imgIter); + m_palette->setBrush(QPalette::Window, pic); + setPalette(*m_palette); + + // assume all welcome screen images are sized the same + resize(pic.size()); + setFixedSize(size()); +} + +void StudioTutorialWidget::handleFwd() +{ + if (*m_imgIter != m_welcomeImages->last()) { + QPixmap pic = getNextScaledPic(); + m_palette->setBrush(QPalette::Window, pic); + setPalette(*m_palette); + + m_ui->studioTutorialBack->setVisible(true); + m_ui->studioTutorialShowAgain->setVisible(false); + } + + if (*m_imgIter == m_welcomeImages->last()) { + m_ui->studioTutorialForward->setVisible(false); + m_ui->studioTutorialOpen->setVisible(true); + m_ui->studioTutorialNew->setVisible(true); + } +} + +void StudioTutorialWidget::handleBack() +{ + if (*m_imgIter != m_welcomeImages->first()) { + QPixmap pic = getPrevScaledPic(); + m_palette->setBrush(QPalette::Window, pic); + setPalette(*m_palette); + + m_ui->studioTutorialForward->setVisible(true); + m_ui->studioTutorialShowAgain->setVisible(false); + + m_ui->studioTutorialOpen->setVisible(false); + m_ui->studioTutorialNew->setVisible(false); + } + + if (*m_imgIter == m_welcomeImages->first()) { + m_ui->studioTutorialBack->setVisible(false); + m_ui->studioTutorialShowAgain->setVisible(true); + } +} + +void StudioTutorialWidget::handleDoNotShowAgainChange(int state) +{ + QSettings settings; + const bool show = !(state == Qt::Checked); + settings.setValue("showWelcomeScreen", show); +} + +void StudioTutorialWidget::handleOpenSample() +{ + this->done(StudioTutorialWidget::openSampleResult); +} + +void StudioTutorialWidget::handleCreateNew() +{ + this->done(StudioTutorialWidget::createNewResult); +} + +void StudioTutorialWidget::getImageList() +{ + QDirIterator *it = new QDirIterator(":/res/Tutorial/screens/", + QDirIterator::NoIteratorFlags); + + while (it->hasNext()) + m_welcomeImages->append(it->next()); +} + +int StudioTutorialWidget::page() const +{ + int i = 0; + QList::iterator iter = m_welcomeImages->begin(); + while (iter != m_imgIter) { ++i; iter++; } + return i; +} + +QPixmap StudioTutorialWidget::getNextScaledPic() +{ + return getScaledPic(++m_imgIter); +} + +QPixmap StudioTutorialWidget::getPrevScaledPic() +{ + return getScaledPic(--m_imgIter); +} + +QPixmap StudioTutorialWidget::getScaledPic(QList::iterator iter) +{ + QPixmap picOrig = QPixmap(*iter); + QPixmap pic = picOrig.scaledToHeight(m_displayScale * picOrig.height(), + Qt::SmoothTransformation); + + pic.setDevicePixelRatio(devicePixelRatio()); + return pic; +} + +qreal StudioTutorialWidget::getDisplayScalingForImage(QList::iterator iter) +{ + QPixmap picOrig = QPixmap(*iter); + + // Set the splash screen to 80% of display size. + // Note that high DPI scaling has an effect on the display + // resolution returned by GetAvailableDisplaySize(). + // DPI scaling factor is integer and taken from the primary screen. + // When running studio on secondary monitor with different DPI, + // or running it on primary with non-integer scaling, we might + // get different dialog size than intended. + QSize displaySize = GetAvailableDisplaySize(getWidgetScreen(this)) * 0.8; + + // scale down if images do not fit on screen, otherwise use + // 1:1 PNGs to avoid scaling artifacts + if (picOrig.height() > displaySize.height() || + picOrig.width() > displaySize.width()) { + QSize picScaledSize = picOrig.size(); + picScaledSize.scale(displaySize, Qt::KeepAspectRatio); + m_displayScale = qMin((qreal)picScaledSize.height() / (qreal)picOrig.height(), + (qreal)picScaledSize.width() / (qreal)picOrig.width()); + return m_displayScale; + } else { + return 1.0; + } +} diff --git a/src/Authoring/Studio/Application/StudioTutorialWidget.h b/src/Authoring/Studio/Application/StudioTutorialWidget.h new file mode 100644 index 00000000..3fa69489 --- /dev/null +++ b/src/Authoring/Studio/Application/StudioTutorialWidget.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 STUDIOTUTORIALWIDGET_H +#define STUDIOTUTORIALWIDGET_H + +#include +#include +#include +#include +#include +#include +#include + +#ifdef QT_NAMESPACE +using namespace QT_NAMESPACE; +#endif + +QT_BEGIN_NAMESPACE +namespace Ui { + class StudioTutorialWidget; +} +QT_END_NAMESPACE + +class StudioTutorialWidget : public QDialog +{ + Q_OBJECT +public: + explicit StudioTutorialWidget(bool goToFileDialog); + + ~StudioTutorialWidget(); + + enum result { + acceptResult = QDialog::Accepted, + rejectResult = QDialog::Rejected, + openSampleResult, + createNewResult + }; + +protected: + void paintEvent(QPaintEvent *event) override; + void OnInitDialog(bool goToFileDialog); + +public: + void handleFwd(); + void handleBack(); + void handleDoNotShowAgainChange(int state); + void handleOpenSample(); + void handleCreateNew(); + int page() const; + +private: + Ui::StudioTutorialWidget *m_ui; + + QList *m_welcomeImages; + QList::iterator m_imgIter; + + QPalette *m_palette; + + qreal m_displayScale; + + void getImageList(); + + QPixmap getScaledPic(QList::iterator iter); + QPixmap getPrevScaledPic(); + QPixmap getNextScaledPic(); + qreal getDisplayScalingForImage(QList::iterator iter); +}; + +#endif // STUDIOTUTORIALWIDGET_H diff --git a/src/Authoring/Studio/Application/StudioTutorialWidget.ui b/src/Authoring/Studio/Application/StudioTutorialWidget.ui new file mode 100644 index 00000000..cb83a5ce --- /dev/null +++ b/src/Authoring/Studio/Application/StudioTutorialWidget.ui @@ -0,0 +1,184 @@ + + + StudioTutorialWidget + + + + 0 + 0 + 1440 + 900 + + + + Welcome to Qt 3D Studio + + + StudioTutorialWidget + + + + + 10 + 10 + 701 + 20 + + + + studioTutorialShowAgain + + + Do Not Show This Again + + + + + + 10 + 820 + 1421 + 80 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::NoFocus + + + studioTutorialOpen + + + Open Sample Project + + + + + + + Qt::NoFocus + + + studioTutorialNew + + + Create New + + + + + + + + + + + 0 + 40 + 1441 + 51 + + + + + + + + 90 + 90 + + + + Qt::NoFocus + + + studioTutorialBack + + + + + + + :/res/Tutorial/button_back.png:/res/Tutorial/button_back.png + + + + 39 + 39 + + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 90 + 90 + + + + Qt::NoFocus + + + StudioTutorialWidget + + + + + + + :/res/Tutorial/button_next.png:/res/Tutorial/button_next.png + + + + 39 + 39 + + + + true + + + + + + + + + + + diff --git a/src/Authoring/Studio/Controls/BaseMeasure.cpp b/src/Authoring/Studio/Controls/BaseMeasure.cpp new file mode 100644 index 00000000..25d5c204 --- /dev/null +++ b/src/Authoring/Studio/Controls/BaseMeasure.cpp @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** 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 "BaseMeasure.h" +#include "Renderer.h" +#include "StudioPreferences.h" + +//============================================================================= +/** + * Create a new measure. + * @param inRatio the current ratio. + * @param inFillBackground true if the background of this control is to be drawn. + */ +CBaseMeasure::CBaseMeasure(double inRatio, bool inFillBackground /*= true */) + : m_SmallHashInterval(0) + , m_MediumHashInterval(0) + , m_LargeHashInterval(0) + , m_Ratio(inRatio) + , m_Offset(0) + , m_EdgeMargin(0) + , m_LargeHashOffset(0) + , m_MediumHashOffset(6) + , m_SmallHashOffset(3) + , m_FillBackground(inFillBackground) +{ + m_BackgroundColor = CStudioPreferences::GetBaseColor(); +} + +CBaseMeasure::~CBaseMeasure() +{ +} + +//============================================================================= +/** + * Overrides the control to set up clipping rects. + * @param inRenderer the renderer to be rendered to. + * @param inDirtyRect the resulting dirty rect. + * @param inIgnoreValidation true if everything needs to be drawn. + */ +void CBaseMeasure::OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation) +{ + inRenderer->PushClippingRect(CRct(GetSize())); + + CControl::OnDraw(inRenderer, inDirtyRect, inIgnoreValidation); + + inRenderer->PopClippingRect(); +} + +//============================================================================= +/** + * Draw the measure. + * @param inRenderer the renderer to draw to. + */ +void CBaseMeasure::Draw(CRenderer *inRenderer) +{ + CRct theRect(GetSize()); + + if (m_FillBackground) + inRenderer->FillSolidRect(theRect, m_BackgroundColor); + + long theLength = GetDisplayLength(); + long theHeight = GetDisplayHeight(); + + double theTotalMeasure = theLength / m_Ratio; + long thePos; + + long theNumLargeHashes = (long)(theTotalMeasure / m_LargeHashInterval) + 1; + + inRenderer->PushPen(CStudioPreferences::GetRulerTickColor()); + + long theOffset = m_Offset - (m_Offset % ::dtol(m_LargeHashInterval)); + + for (long i = 0; i < theNumLargeHashes + 1; ++i) { + double theMeasure = m_LargeHashInterval * i + theOffset; + + thePos = CalculatePos(theMeasure - m_Offset); + + if (thePos > 0) + DrawLine(inRenderer, thePos, theHeight, theHeight - m_LargeHashOffset); + + DrawMeasureText(inRenderer, thePos, long(theMeasure)); + + // sanity check + if (m_MediumHashInterval > 0) { + // in cases where the medium and small hashes must be filled up to the right of the + // first Large hash + if (m_Offset < 0 && i == 0) { + thePos = CalculatePos(theMeasure - m_Offset - m_MediumHashInterval); + if (thePos > 0) + DrawLine(inRenderer, thePos, theHeight, theHeight - m_MediumHashOffset); + + for (double theSmallInterval = 0; theSmallInterval < m_LargeHashInterval; + theSmallInterval += m_SmallHashInterval) { + thePos = CalculatePos(theMeasure - m_Offset - theSmallInterval); + if (thePos > 0) + DrawLine(inRenderer, thePos, theHeight, theHeight - m_SmallHashOffset); + } + } + + thePos = CalculatePos(theMeasure - m_Offset + m_MediumHashInterval); + if (thePos > 0) + DrawLine(inRenderer, thePos, theHeight, theHeight - m_MediumHashOffset); + + for (double theSmallInterval = 0; theSmallInterval < m_LargeHashInterval; + theSmallInterval += m_SmallHashInterval) { + thePos = CalculatePos(theMeasure - m_Offset + theSmallInterval); + + if (thePos > 0) + DrawLine(inRenderer, thePos, theHeight, theHeight - m_SmallHashOffset); + } + } // if medium is valid + } + // Draws the top outline + DrawOutline(inRenderer, theHeight, 0, theLength); + inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor()); + // Draws the bottom outline + DrawOutline(inRenderer, theHeight + 1, 0, theLength); + inRenderer->PopPen(); + + // Dark line at left and right ends of the measure + inRenderer->PushPen(CStudioPreferences::GetButtonShadowColor()); + DrawLine(inRenderer, theRect.size.x - 1, 0, theRect.size.y - 1); + + // Dark line across the top of the measure + DrawOutline(inRenderer, 0, 0, theRect.size.x - 1); + inRenderer->PopPen(); + + // pop for the first PushPen + inRenderer->PopPen(); +} + +//============================================================================= +/** + * Return the display length, by default, this is horizontal and returns the x + */ +long CBaseMeasure::GetDisplayLength() +{ + return GetSize().x; +} + +//============================================================================= +/** + * Return the display height, by default, this is horizontal and returns the y + */ +long CBaseMeasure::GetDisplayHeight() +{ + return GetSize().y - m_EdgeMargin; +} + +//============================================================================= +/** + * By default, this draws a vertical line. + * A subclass can override this and draw a horizontal one, if its orientation requires so. + * @parma inRenderer the renderer + * @param inPos the position that in the x-coordinate + * @param inStart start position of the line + * @param inEnd end position of the line + */ +void CBaseMeasure::DrawLine(CRenderer *inRenderer, long inPos, long inStart, long inEnd) +{ + inRenderer->MoveTo(CPt(inPos, inStart)); + inRenderer->LineTo(CPt(inPos, inEnd)); +} + +//============================================================================= +/** + * This draws a horizontal outline + * A subclass can override this and draw a vertical one, if its orientation requires so. + * @parma inRenderer the renderer + * @param inPos the position that in the x-coordinate + * @param inStart start position of the line + * @param inEnd end position of the line + */ +void CBaseMeasure::DrawOutline(CRenderer *inRenderer, long inPos, long inStart, long inEnd) +{ + inRenderer->MoveTo(CPt(inStart, inPos)); + inRenderer->LineTo(CPt(inEnd, inPos)); +} diff --git a/src/Authoring/Studio/Controls/BaseMeasure.h b/src/Authoring/Studio/Controls/BaseMeasure.h new file mode 100644 index 00000000..25916198 --- /dev/null +++ b/src/Authoring/Studio/Controls/BaseMeasure.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_BASE_MEASURE_H +#define INCLUDED_BASE_MEASURE_H 1 + +#pragma once + +#include "Control.h" +#include "CColor.h" +#include "CoreUtils.h" +#include + +class CBaseMarker; +class CSnapper; + +class CBaseMeasure : public CControl +{ +public: + CBaseMeasure(double inRatio, bool inFillBackground = true); + virtual ~CBaseMeasure(); + + virtual void OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation = false); + + virtual void Draw(CRenderer *inRenderer); + + // inline these + long GetLargeHashInterval() const { return ::dtol(m_LargeHashInterval); } + long GetMediumHashInterval() const { return ::dtol(m_MediumHashInterval); } + long GetSmallHashInterval() const { return ::dtol(m_SmallHashInterval); } + +protected: + virtual void DrawMeasureText(CRenderer *inRenderer, long inPosition, long inMeasure) = 0; + virtual long CalculatePos(double inNewValue) = 0; + virtual long GetDisplayLength(); + virtual long GetDisplayHeight(); + virtual void DrawLine(CRenderer *inRenderer, long inPos, long inStart, long inEnd); + virtual void DrawOutline(CRenderer *inRenderer, long inPos, long inStart, long inEnd); + + double m_SmallHashInterval; ///< the measurement represented by a small hash + double m_MediumHashInterval; ///< the measurement represented by a medium hash + double m_LargeHashInterval; ///< the measurement represented by a large hash + double m_Ratio; ///< Ratio that is used to calculate the size of the large hash + long m_Offset; ///< Offset of the point 0 from left or top + ::CColor m_BackgroundColor; ///< Background of this control + + // Tickmarks + long m_EdgeMargin; ///< Margin from the edge, so that no line draws all the way through + long m_LargeHashOffset; ///< Offset from the margin for the large hash + long m_MediumHashOffset; ///< Offset from the margin for the medium hash + long m_SmallHashOffset; ///< Offset from the margin for the small hash + + bool m_FillBackground; ///< true to fill the background (i.e. its not transparent) +}; +#endif // INCLUDED_BASE_MEASURE_H diff --git a/src/Authoring/Studio/Controls/BlankControl.cpp b/src/Authoring/Studio/Controls/BlankControl.cpp new file mode 100644 index 00000000..492bc630 --- /dev/null +++ b/src/Authoring/Studio/Controls/BlankControl.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** 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 "BlankControl.h" +#include "Renderer.h" +#include "SystemPreferences.h" + +//============================================================================= +/** + * constructor + */ +CBlankControl::CBlankControl(CColor inColor) + : m_DrawBorder(false) + , m_FillBackground(true) +{ + SetColor(inColor); +} + +//============================================================================= +/** + * destructor + */ +CBlankControl::~CBlankControl() +{ +} + +//============================================================================= +/** + * Draws this control + */ +void CBlankControl::Draw(CRenderer *inRenderer) +{ + CRct theRect(GetSize()); + + if (m_FillBackground) + inRenderer->FillSolidRect(theRect, m_Color); + + if (m_DrawBorder) { + // Get the normal colors for the 3D border + CColor theShadowColor = CStudioPreferences::GetButtonShadowColor(); + CColor theHiliteColor = CStudioPreferences::GetButtonHighlightColor(); + + // Draw a frame around the button + inRenderer->Draw3dRect( + CRct(theRect.position.x + 1, theRect.position.y, theRect.size.x, theRect.size.y), + theHiliteColor, theShadowColor); + inRenderer->PushPen(theShadowColor); + inRenderer->MoveTo(CPt(0, 0)); + inRenderer->LineTo(CPt(0, theRect.size.y)); + inRenderer->PopPen(); + } +} + +//============================================================================= +/** + * Sets the color for this control + */ +void CBlankControl::SetColor(CColor inColor) +{ + if (m_Color == inColor) + return; + + m_Color = inColor; + + Invalidate(); +} + +//============================================================================= +/** + * @param inDrawBorder true if we should draw the border + */ +void CBlankControl::SetDrawBorder(bool inDrawBorder) +{ + m_DrawBorder = inDrawBorder; +} + +//============================================================================= +/** + * @param inFillBackground true if we should draw the background + */ +void CBlankControl::SetFillBackground(bool inFillBackground) +{ + m_FillBackground = inFillBackground; +} diff --git a/src/Authoring/Studio/Controls/BlankControl.h b/src/Authoring/Studio/Controls/BlankControl.h new file mode 100644 index 00000000..b04337b0 --- /dev/null +++ b/src/Authoring/Studio/Controls/BlankControl.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$ +** +****************************************************************************/ + +#ifndef INCLUDED_BLANKCONTROL_H +#define INCLUDED_BLANKCONTROL_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" +#include "StudioPreferences.h" + +class CBlankControl : public CControl +{ +public: + CBlankControl(::CColor inColor = CStudioPreferences::GetBaseColor()); + virtual ~CBlankControl(); + void Draw(CRenderer *inRenderer) override; + void SetColor(::CColor inColor); + void SetDrawBorder(bool inDrawBorder); + void SetFillBackground(bool inFillBackground); + +protected: + ::CColor m_Color; + bool m_DrawBorder; + bool m_FillBackground; +}; + +#endif // INCLUDED_BLANKCONTROL_H diff --git a/src/Authoring/Studio/Controls/BreadCrumbControl.cpp b/src/Authoring/Studio/Controls/BreadCrumbControl.cpp new file mode 100644 index 00000000..5ccae438 --- /dev/null +++ b/src/Authoring/Studio/Controls/BreadCrumbControl.cpp @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (C) 2004 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "BreadCrumbControl.h" +#include "StudioPreferences.h" +#include "IBreadCrumbProvider.h" +//#include "Cmd.h" +#include + +#include + +IMPLEMENT_OBJECT_COUNTER(CBreadCrumbControl) + +//============================================================================== +// Internal Classes +//============================================================================== + +//============================================================================= +/** + * Constructor + */ +CBreadCrumbControl::CBreadCrumbControl() + : m_BreadCrumbProvider(nullptr) +{ + ADDTO_OBJECT_COUNTER(CBreadCrumbControl) + + SetName("BreadCrumbControl"); + SetAutoMin(false); + SetFlowDirection(FLOW_HORIZONTAL); + SetAlignment(ALIGN_TOP, ALIGN_LEFT); + SetTopMargin(0); + SetBottomMargin(0); + SetLeftMargin(0); + SetRightMargin(0); + SetGapBetweenChildren(0); + + long theHeaderHeight = CStudioPreferences::GetHeaderHeight(); + SetMaximumSize(CPt(LONG_MAX, theHeaderHeight)); + SetMinimumSize(CPt(0, theHeaderHeight)); + SetSize(CPt(LONG_MAX, theHeaderHeight)); + SetPosition(CPt(0, 0)); +} + +//============================================================================= +/** + * destructor + */ +CBreadCrumbControl::~CBreadCrumbControl() +{ + RemoveAllButtons(); + REMOVEFROM_OBJECT_COUNTER(CBreadCrumbControl) +} + +//============================================================================= +/** + * Helper class to create the colon separator button + */ +static inline CBreadCrumbControl::TSeparatorButtonType *CreateSeparatorButton(const QPixmap &inImage) +{ + CBreadCrumbControl::TSeparatorButtonType *theButton = + new CBreadCrumbControl::TSeparatorButtonType; + theButton->SetAutoSize(true); + theButton->SetUpImage(inImage); + theButton->SetSize(CPt(12, 21)); + theButton->SetMinimumSize(CPt(12, 21)); + theButton->SetMaximumSize(CPt(12, 21)); + return theButton; +} + +//============================================================================= +/** + * Helper function to create a new button to be placed on the breadcrumb bar + * @param inButtonName Name of the button to be displayed and stored + * inImageName The specific .png file to load in for the button + * @return TButtonType returns the newly created button + */ +static inline CBreadCrumbControl::TButtonType *CreateButton(const QPixmap &inImage) +{ + CBreadCrumbControl::TButtonType *theButton = new CBreadCrumbControl::TButtonType(); + theButton->SetAutoSize(true); + theButton->SetUpImage(inImage); + CBreadCrumbControl::TButtonType::SBorderOptions theBorderOptions(false, false, false, false); + theButton->SetBorderVisibilityAll(theBorderOptions); + theButton->SetFillStyleUp(CBreadCrumbControl::TButtonType::EFILLSTYLE_FLOOD); + theButton->SetFillStyleOver(CBreadCrumbControl::TButtonType::EFILLSTYLE_FLOOD); + theButton->SetFillColorUp(CStudioPreferences::GetBaseColor()); + theButton->SetFillColorDown(CStudioPreferences::GetBaseColor()); + theButton->SetFillColorOver(CStudioPreferences::GetMouseOverHighlightColor()); + theButton->SetMinimumSize(CPt(16, 21)); + theButton->SetMaximumSize(CPt(125, 21)); + return theButton; +} + +//============================================================================= +/** + * Generate/Reset the text appearing on the breadcrumb which is currently + * appending the slide name as well. + * @param inBreadCrumb containing color/text info for display + * @param inButton The button to be modified + */ +void CBreadCrumbControl::GenerateButtonText(const SBreadCrumb &inBreadCrumb, TButtonType *inButton) +{ + Q3DStudio::CString theDisplayName(Q3DStudio::CString::fromQString(inBreadCrumb.m_String)); + inButton->SetTextColorUp(CStudioPreferences::GetNormalColor()); + inButton->SetTextColorDown(CStudioPreferences::GetNormalColor()); + inButton->SetText(theDisplayName); + inButton->SetTooltipText(theDisplayName); + inButton->SetName(theDisplayName); +} + +//============================================================================= +/** + * Draws this control + */ +void CBreadCrumbControl::Draw(CRenderer *inRenderer) +{ + const auto size = GetSize(); + + // Fill in the background + inRenderer->FillSolidRect(QRect(0, 0, size.x, size.y), CStudioPreferences::GetBaseColor()); + + // Outline the control + CColor theOutlineColor = CStudioPreferences::GetButtonShadowColor(); + inRenderer->DrawRectOutline(QRect(0, 0, size.x, size.y -1), theOutlineColor, theOutlineColor, + theOutlineColor, theOutlineColor); + + // Draw the highlight at the bottom + inRenderer->PushPen(CStudioPreferences::GetButtonHighlightColor()); + inRenderer->MoveTo(QPoint(0, size.y - 1)); + inRenderer->LineTo(QPoint(size.x - 1, size.y - 1)); + inRenderer->PopPen(); +} + +//============================================================================= +/** + * Update the entire bread crumb trail. This will 'reuse' created controls, creating more if + *trail is longer than previous, and deleting extra if shorter. + */ +void CBreadCrumbControl::RefreshTrail(IBreadCrumbProvider *inBreadCrumbProvider) +{ + bool theChangedProvider = m_BreadCrumbProvider != inBreadCrumbProvider; + if (theChangedProvider && m_BreadCrumbProvider) + m_BreadCrumbProvider->SigBreadCrumbUpdate.disconnect(boost::bind(&CBreadCrumbControl::OnUpdateBreadCrumb, this)); + + m_BreadCrumbProvider = inBreadCrumbProvider; + + SuspendRecalcLayout(true); + size_t theIndex = 0; + + if (m_BreadCrumbProvider) { + // listen for single breadcrumb update (i.e. name changes) + if (theChangedProvider) + m_BreadCrumbProvider->SigBreadCrumbUpdate.connect(boost::bind(&CBreadCrumbControl::OnUpdateBreadCrumb, this)); + + const IBreadCrumbProvider::TTrailList &theList = m_BreadCrumbProvider->GetTrail(); + // By design, if this is only 1 item in the list, nothing is shown. + if (theList.size() > 1) { + for (; theIndex < theList.size(); ++theIndex) { + TButtonType *theButton = nullptr; + if (theIndex < m_BreadCrumbList.size()) + theButton = m_BreadCrumbList[theIndex].m_BreadCrumb; + else // create new + { + theButton = + CreateButton((theIndex == 0) ? m_BreadCrumbProvider->GetRootImage() + : m_BreadCrumbProvider->GetBreadCrumbImage()); + theButton->SigToggle.connect(boost::bind(&CBreadCrumbControl::OnButtonToggled, this, _1, _2)); + + TSeparatorButtonType *theSeparator = + CreateSeparatorButton(m_BreadCrumbProvider->GetSeparatorImage()); + + // the ":" is always added as a pair + m_BreadCrumbList.push_back(SBreadCrumbItem(theButton, theSeparator)); + AddChild(theButton); + AddChild(theSeparator); + } + // Update text and color + GenerateButtonText(theList[theIndex], theButton); + + // Refresh all properties that might be outdated since buttons are reused + QPixmap theImage; + bool theEnabled = true; + if (theIndex + == theList.size() + - 1) { // The last button is displayed differently (grayed-out) + theButton->SetTextColorUp(CColor(94, 91, 85)); + theButton->SetTextColorDown(CColor(94, 91, 85)); + theImage = m_BreadCrumbProvider->GetActiveBreadCrumbImage(); + + theEnabled = false; // the last item being the 'active' is disabled. + } else if (theIndex > 0) + theImage = m_BreadCrumbProvider->GetBreadCrumbImage(); + + if (!theImage.isNull()) + theButton->SetUpImage(theImage); + + theButton->SetToggleState(!theEnabled); + theButton->SetEnabled(theEnabled); + // the separator is hidden for the last one + m_BreadCrumbList[theIndex].m_Separator->SetVisible(theEnabled); + + theButton->Invalidate(); + } + } + } + // Discard 'extras' OR if this is no provider, this will remove all breadcrumbs + while (m_BreadCrumbList.size() > theIndex) { + RemoveButton(m_BreadCrumbList.back()); + m_BreadCrumbList.pop_back(); + } + SuspendRecalcLayout(false); + RecalcLayout(); +} + +//============================================================================= +/** + * Check for changes in the existing list and update. + */ +void CBreadCrumbControl::OnUpdateBreadCrumb() +{ + ASSERT(m_BreadCrumbProvider); + bool theUpdated = false; + + const IBreadCrumbProvider::TTrailList &theList = m_BreadCrumbProvider->GetTrail(false); + ASSERT(m_BreadCrumbList.size() == theList.size() + || (m_BreadCrumbList.size() == 0 + && theList.size() + == 1)); // By design, if this is only 1 item in the list, nothing is shown. + + for (size_t theIndex = 0; theIndex < m_BreadCrumbList.size(); ++theIndex) { + TButtonType *theButton = m_BreadCrumbList[theIndex].m_BreadCrumb; + if (theButton->GetText().toQString() != theList[theIndex].m_String + || theButton->GetTextColorUp().getQColor() != theList[theIndex].m_Color) { + GenerateButtonText(theList[theIndex], theButton); + theUpdated = true; + } + } + + if (theUpdated) // Make sure that this entire BreadCrumbControl has room for extraneous length + // buttons + RecalcLayout(); +} + +//============================================================================= +/** + * Removes and clean up button + */ +void CBreadCrumbControl::RemoveButton(SBreadCrumbItem &inBreadCrumb) +{ + inBreadCrumb.m_BreadCrumb->SigToggle.disconnect(boost::bind(&CBreadCrumbControl::OnButtonToggled, this, _1, _2)); + RemoveChild(inBreadCrumb.m_BreadCrumb); + RemoveChild(inBreadCrumb.m_Separator); + delete inBreadCrumb.m_BreadCrumb; + delete inBreadCrumb.m_Separator; +} + +//============================================================================= +/** + * Removes all buttons (trail and separators) + */ +void CBreadCrumbControl::RemoveAllButtons() +{ + while (!m_BreadCrumbList.empty()) { + RemoveButton(m_BreadCrumbList.back()); + m_BreadCrumbList.pop_back(); + } +} + +//============================================================================= +/** + * 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 CBreadCrumbControl::OnButtonToggled(CToggleButton *inButton, + CButtonControl::EButtonState inState) +{ + Q_UNUSED(inState); + + ASSERT(m_BreadCrumbProvider); + + // Find the index into the trail list + size_t theIndex = 0; + for (; theIndex < m_BreadCrumbList.size(); ++theIndex) { + if (m_BreadCrumbList[theIndex].m_BreadCrumb == inButton) + break; + } + ASSERT(theIndex < m_BreadCrumbList.size()); // sanity check + + m_BreadCrumbProvider->OnBreadCrumbClicked((long)theIndex); +} diff --git a/src/Authoring/Studio/Controls/BreadCrumbControl.h b/src/Authoring/Studio/Controls/BreadCrumbControl.h new file mode 100644 index 00000000..c8fc519a --- /dev/null +++ b/src/Authoring/Studio/Controls/BreadCrumbControl.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2004 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_BREADCRUMBCONTROL_H +#define INCLUDED_BREADCRUMBCONTROL_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "FlowLayout.h" +#include "ProceduralButton.h" +#include "ToggleButton.h" +#include "TextButton.h" +#include "IBreadCrumbProvider.h" + +//============================================================================== +// Forwards +//============================================================================== +class IDoc; +class CRenderer; + +class CBreadCrumbControl : public CFlowLayout +{ +public: + typedef CProceduralButton> TButtonType; + typedef CTextButton TSeparatorButtonType; + struct SBreadCrumbItem + { + TButtonType *m_BreadCrumb; + TSeparatorButtonType *m_Separator; + + SBreadCrumbItem(TButtonType *inBreadCrumb, TSeparatorButtonType *inSeparator) + { + m_BreadCrumb = inBreadCrumb; + m_Separator = inSeparator; + } + }; + typedef std::vector TBreadCrumbList; + + // Construction +public: + CBreadCrumbControl(); + virtual ~CBreadCrumbControl(); + + DEFINE_OBJECT_COUNTER(CBreadCrumbControl) + + // CControl +public: + virtual void Draw(CRenderer *inRenderer); + + void RefreshTrail(IBreadCrumbProvider *inBreadCrumbProvider); + void OnUpdateBreadCrumb(); + + // Implementation +protected: + void GenerateButtonText(const SBreadCrumb &inBreadCrumb, TButtonType *inButton); + void OnButtonToggled(CToggleButton *inButton, CButtonControl::EButtonState inState); + void RemoveButton(SBreadCrumbItem &inBreadCrumb); + void RemoveAllButtons(); + +protected: + IBreadCrumbProvider *m_BreadCrumbProvider; + TBreadCrumbList m_BreadCrumbList; +}; + +#endif // INCLUDED_BREADCRUMBCONTROL_H diff --git a/src/Authoring/Studio/Controls/ButtonControl.cpp b/src/Authoring/Studio/Controls/ButtonControl.cpp new file mode 100644 index 00000000..c242915a --- /dev/null +++ b/src/Authoring/Studio/Controls/ButtonControl.cpp @@ -0,0 +1,425 @@ +/**************************************************************************** +** +** 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 "ButtonControl.h" +#include "Renderer.h" +#include "ResourceCache.h" + +//============================================================================= +/** + * Constructor + * + * @param inToggleButton true if this is suppose to be a toggle button. Toggle + * buttons stay pressed when clicked on and have to be clicked again in order + * to release. Normal buttons return to the up state when the button is released. + */ +CButtonControl::CButtonControl() + : m_State(EBUTTONSTATE_UP) + , m_AutoSize(true) + , m_MouseEnter(true) + , m_IsMouseDown(false) + , m_VCenterImage(false) + , m_HCenterImage(false) + , m_Margin(0) +{ +} + +//============================================================================= +/** + * Destructor + */ +CButtonControl::~CButtonControl() +{ +} + +//============================================================================= +/** + * Returns the current state of the button. A button can be "up", "down", or + * "indeterminate". The up state is the normal state of the button. The down + * state is when the mouse is pressing the button. The indeterminate state is + * provided for subclasses and not used here. + * @return the button's current state + */ +CButtonControl::EButtonState CButtonControl::GetButtonState() const +{ + return m_State; +} + +//============================================================================= +/** + * Sets the current state of the button. No listeners are notified. + * @param inState new state of the button + */ +void CButtonControl::SetButtonState(EButtonState inState) +{ + if (m_State == inState) + return; + + m_State = inState; + Invalidate(); +} + +//============================================================================= +/** + * Sets the image to use when this button is in the up state. A button is "up" + * if it is not disabled, not depressed, and the mouse is not over it. + * @param inImage image to be loaded when this button is up + */ +void CButtonControl::SetUpImage(const QPixmap &inImage) +{ + m_ImageUp = inImage; + Resize(); +} + +//============================================================================= +/** + * Sets the image to use when this button is in the up state. A button is "up" + * if it is not disabled, not depressed, and the mouse is not over it. + * @param inImageName name of the image to be loaded when this button is up + */ +void CButtonControl::SetUpImage(const QString &inImageName) +{ + QPixmap theImage ; + if (!inImageName.isEmpty()) + theImage = CResourceCache::GetInstance()->GetBitmap(inImageName); + SetUpImage(theImage); +} + +//============================================================================= +/** + * Sets the image to use when this button is in the down state. + * @param inImage image to be loaded when this button is down + */ +void CButtonControl::SetDownImage(const QPixmap &inImage) +{ + m_ImageDown = inImage; +} + +//============================================================================= +/** + * Sets the image to use when this button is in the down state. + * @param inImageName name of the image to be loaded when this button is down + */ +void CButtonControl::SetDownImage(const QString &inImageName) +{ + QPixmap theImage; + if (!inImageName.isEmpty()) + theImage = CResourceCache::GetInstance()->GetBitmap(inImageName); + SetDownImage(theImage); +} + +//============================================================================= +/** + * Sets the image to use when this button the mouse is over the button. To + * leave the button displaying the "up" state, pass NULL to this function. + * @param inImage image to be loaded when the mouse is over this button + */ +void CButtonControl::SetOverImage(const QPixmap &inImage) +{ + m_ImageOver = inImage; +} + +//============================================================================= +/** + * Sets the image to use when this button the mouse is over the button. To + * leave the button displaying the "up" state, pass an empty string to this function. + * @param inImageName name of the image to be loaded when the mouse is over this button + */ +void CButtonControl::SetOverImage(const QString &inImageName) +{ + QPixmap theImage; + if (!inImageName.isEmpty()) + theImage = CResourceCache::GetInstance()->GetBitmap(inImageName); + SetOverImage(theImage); +} + +//============================================================================= +/** + * Sets the image to use when this button is disabled, when the button is in a DOWN state + * @param inImage image to be loaded when this button is disabled + */ +void CButtonControl::SetDisabledImage(const QPixmap &inImage) +{ + m_ImageDownDisabled = inImage; +} + +//============================================================================= +/** + * Sets the image to use when this button is in the disabled state. + * @param inImageName name of the image to be loaded when this button is disabled + */ +void CButtonControl::SetDisabledImage(const QString &inImageName) +{ + QPixmap theImage; + if (!inImageName.isEmpty()) + theImage = CResourceCache::GetInstance()->GetBitmap(inImageName); + SetDisabledImage(theImage); +} + +//============================================================================= +/** + * In cases, where there is a different (disabled) image for button UP state + */ +void CButtonControl::SetUpDisabledImage(const QString &inImageName) +{ + if (!inImageName.isEmpty()) + m_ImageUpDisabled = CResourceCache::GetInstance()->GetBitmap(inImageName); +} + +//============================================================================= +/** + * Allows you to enable or disable auto sizing for this button. Auto sizing + * causes the button's size to change whenever the "Up" image is changed for + * this button. Button size does NOT change as the button state changes. + * @return true if this button is currently in Auto Size mode + */ +void CButtonControl::SetAutoSize(bool inEnableAutoSize) +{ + m_AutoSize = inEnableAutoSize; + Resize(); +} + +//============================================================================= +/** + * Determines if this button will auto size or not. Auto sizing causes the + * button's size to change whenever the "Up" image is changed for this button. + * Button size does NOT change as the button state changes. + * @return true if this button is currently in Auto Size mode + */ +bool CButtonControl::GetAutoSize() +{ + return m_AutoSize; +} + +void CButtonControl::SetCenterImage(bool inVCenter, bool inHCenter) +{ + if (m_VCenterImage == inVCenter && m_HCenterImage == inHCenter) + return; + m_VCenterImage = inVCenter; + m_HCenterImage = inHCenter; + Invalidate(); +} + +void CButtonControl::SetMarginImage(long inMargin) +{ + m_Margin = inMargin; +} + +//============================================================================= +/** + * Draws the button based on the current state + */ +void CButtonControl::Draw(CRenderer *inRenderer) +{ + Render(inRenderer); +} + +//============================================================================= +/** + * Handles mouse down on the button. Flags the button as down which results + * in some possible drawing changes. + */ +bool CButtonControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDown(inPoint, inFlags)) { + m_IsMouseDown = true; + SetButtonState(EBUTTONSTATE_DOWN); + SigButtonDown(this); + Invalidate(); + } + + return true; +} + +//============================================================================= +/** + * Handles mouse up on the button. Sets the button to the "up" state and fires + * an event to interested listeners. + * @param inPoint location of the mouse when the event occurred + * @param inFlags state of the modifier keys when this event occurred + */ +void CButtonControl::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseUp(inPoint, inFlags); + + SetButtonState(EBUTTONSTATE_UP); + + if (IsMouseOver()) { + SigButtonUp(this); + if (m_IsMouseDown) + SigClicked(this); + } + m_IsMouseDown = false; + + Invalidate(); +} + +//============================================================================= +/** + * This function is called when the mouse passes over this button. The button + * is invalidated so that any custom drawing for when the mouse is over the + * button can occurr. + * @param inPoint location of the mouse when the event occurred + * @param inFlags state of the modifier keys when this event occurred + */ +void CButtonControl::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOver(inPoint, inFlags); + + // Only invalidate the first time the mouse enters this control + if (m_MouseEnter) { + Invalidate(); + m_MouseEnter = false; + } +} + +//============================================================================= +/** + * This function is called when the mouse exits the bounds of this button. The + * button is invalidated so that any custom drawing caused by the OnMouseOver + * event can be undone. + * @param inPoint location of the mouse when the event occurred + * @param inFlags state of the modifier keys when this event occurred + */ +void CButtonControl::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOut(inPoint, inFlags); + Invalidate(); + // Change the flag so that next time we get a mouse over event, we know to invalidate this + // button + m_MouseEnter = true; +} + +//============================================================================= +/** + * 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. + * @return the currently displayed image or NULL if there is no image on this button + */ +QPixmap CButtonControl::GetCurrentImage() const +{ + // Default to the up state + auto theImage = m_ImageUp; + + EButtonState theState = GetButtonState(); + + // If the mouse is over the button, switch to the mouse over image + if (IsMouseOver() && !m_ImageOver.isNull()) + theImage = m_ImageOver; + + // If the button is currently pressed, this cancels the up and over states, so return the down + // image + if (theState == EBUTTONSTATE_DOWN && !m_ImageDown.isNull()) + theImage = m_ImageDown; + + // If this button is disabled just return the disabled image (overrides any other states) + if (!IsEnabled()) { // use the specified butuon UP disabled if specified, otherwise fall back on + // the DOWN ( that's how the legacy system does it ) + if (theState == EBUTTONSTATE_UP && !m_ImageUpDisabled.isNull()) + theImage = m_ImageUpDisabled; + else if (!m_ImageDownDisabled.isNull()) + theImage = m_ImageDownDisabled; + } + return theImage; +} + +//============================================================================= +/** + * Get the size of the image that this control is currently using. + * @return the size of the ImageUp image. + */ +QSize CButtonControl::GetImageSize() const +{ + // Get the image map. + QPixmap theImage = GetCurrentImage(); + + return theImage.size(); +} + +//============================================================================= +/** + * Override of invalidate to invalidate the parent as well. + * @param inIsInvalidated true if this is to be invalidated. + */ +void CButtonControl::Invalidate(bool inIsInvalidated /* = true */) +{ + // Since the button is transparent the parent needs to be drawn as well. + if (inIsInvalidated && GetParent() != nullptr) + GetParent()->Invalidate(); + + CControl::Invalidate(inIsInvalidated); +} + +//============================================================================= +/** + * Draws the appropriate image for the current button state to the renderer. + * @param inRenderer the renderer to draw to + */ +void CButtonControl::Render(CRenderer *inRenderer) +{ + CPt thePos(0, 0); + const auto theImage = GetCurrentImage(); + + if (m_VCenterImage || m_HCenterImage) { + const auto theSize = theImage.size(); + + if (m_HCenterImage) + thePos.x = (GetSize().x / 2) - (theSize.width() / 2); + + if (m_VCenterImage) + thePos.y = (GetSize().y / 2) - (theSize.height() / 2); + } + + thePos.x += m_Margin; + + if (!theImage.isNull()) + inRenderer->DrawBitmap(thePos, theImage); +} + +//============================================================================= +/** + * If auto sizing is enabled, this function resizes the button to be the same + * size as the image that it contains. Note: it does not set the Min/Max sizes. + */ +void CButtonControl::Resize() +{ + if (m_AutoSize) { + auto theSize = m_ImageUp.size(); + + SetSize(CPt(theSize.width(), theSize.height())); + } +} diff --git a/src/Authoring/Studio/Controls/ButtonControl.h b/src/Authoring/Studio/Controls/ButtonControl.h new file mode 100644 index 00000000..4baf71dc --- /dev/null +++ b/src/Authoring/Studio/Controls/ButtonControl.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** 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_BUTTON_CONTROL_H +#define INCLUDED_BUTTON_CONTROL_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" +#include "Multicaster.h" + +#include + +#include + +//============================================================================== +// Forwards +//============================================================================== + +//============================================================================= +/** + * Base class for creating button controls. + */ +class CButtonControl : public CControl +{ +public: + /// States for procedural buttons that might result in drawing changes + enum EButtonState { + EBUTTONSTATE_UP, ///< Indicates that the button is currently in the up position + EBUTTONSTATE_DOWN, ///< Indicates that the button is currently in the up position + EBUTTONSTATE_INDETERMINATE ///< Not used yet; provided for sub-classes to implement a + ///tri-state functionality + }; + +protected: + EButtonState m_State; ///< Specifies what state the button is currently in; state changes as the + ///button is clicked on + QPixmap m_ImageUp; ///< The image for the button in its normal state + QPixmap m_ImageDown; ///< The image for the button while it is being clicked + QPixmap m_ImageOver; ///< The image for the button while the mouse is over + QPixmap m_ImageUpDisabled; ///< The image for the button when it is disabled and unavailable + ///to the user + QPixmap m_ImageDownDisabled; ///< The image for the button when it is disabled and unavailable + ///to the user + bool m_AutoSize; ///< true if the button will automatically resize itself + bool m_MouseEnter; ///< Flag for determining mouse enter/exit status so that the number of + ///invalidations is minimized. See OnMouseOver and OnMouseOut. + bool m_IsMouseDown; + bool m_VCenterImage; + bool m_HCenterImage; + long m_Margin; + +public: + CButtonControl(); + virtual ~CButtonControl(); + + EButtonState GetButtonState() const; + virtual void SetButtonState(EButtonState inState); + + void SetUpImage(const QPixmap &inImage); + void SetUpImage(const QString &inImageName); + void SetDownImage(const QPixmap &inImage); + void SetDownImage(const QString &inImageName); + void SetOverImage(const QPixmap &inImage); + void SetOverImage(const QString &inImageName); + void SetDisabledImage(const QPixmap &inImage); + void SetDisabledImage(const QString &inImageName); + void SetUpDisabledImage(const QString &inImageName); + QSize GetImageSize() const; + + void SetAutoSize(bool inEnableAutoSize); + bool GetAutoSize(); + + void SetCenterImage(bool inVCenter, bool inHCenter); + void SetMarginImage(long inMargin); + + void Draw(CRenderer *inRenderer) override; + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void Invalidate(bool inIsInvalidated = true) override; + + boost::signal1 SigButtonDown; + boost::signal1 SigButtonUp; + boost::signal1 SigClicked; + +protected: + virtual void Render(CRenderer *inRenderer); + virtual QPixmap GetCurrentImage() const; + virtual void Resize(); +}; + +#endif // INCLUDED_BUTTON_CONTROL_H diff --git a/src/Authoring/Studio/Controls/ClickableLabel.cpp b/src/Authoring/Studio/Controls/ClickableLabel.cpp new file mode 100644 index 00000000..73995fcf --- /dev/null +++ b/src/Authoring/Studio/Controls/ClickableLabel.cpp @@ -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$ +** +****************************************************************************/ + +#include "ClickableLabel.h" + +#include + +ClickableLabel::ClickableLabel(QWidget *pr) : + QLabel(pr) +{ + +} + +void ClickableLabel::mousePressEvent(QMouseEvent *event) +{ + if (rect().contains(event->pos())) + event->accept(); +} + +void ClickableLabel::mouseReleaseEvent(QMouseEvent *event) +{ + if (rect().contains(event->pos())) { + event->accept(); + Q_EMIT clicked(); + } +} diff --git a/src/Authoring/Studio/Controls/ClickableLabel.h b/src/Authoring/Studio/Controls/ClickableLabel.h new file mode 100644 index 00000000..591baa9a --- /dev/null +++ b/src/Authoring/Studio/Controls/ClickableLabel.h @@ -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$ +** +****************************************************************************/ + +#ifndef CLICKABLELABEL_H +#define CLICKABLELABEL_H + +#include + +class ClickableLabel : public QLabel +{ + Q_OBJECT +public: + ClickableLabel(QWidget *pr = nullptr); + +Q_SIGNALS: + void clicked(); + +protected: + void mouseReleaseEvent(QMouseEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; +}; + +#endif // CLICKABLELABEL_H diff --git a/src/Authoring/Studio/Controls/ComboTextBox.h b/src/Authoring/Studio/Controls/ComboTextBox.h new file mode 100644 index 00000000..dbb3f199 --- /dev/null +++ b/src/Authoring/Studio/Controls/ComboTextBox.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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_COMBO_TEXT_BOX_H +#define INCLUDED_COMBO_TEXT_BOX_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "StringEdit.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; + +//============================================================================== +/** + * @class CComboTextBox extends CTextEdit to handle custom drawing, etc. + */ +class CComboTextBox : public CStringEdit +{ +public: + CComboTextBox(); + virtual ~CComboTextBox(); + void Draw(CRenderer *inRenderer) override; + bool OnMouseDown(CPt inLocation, Qt::KeyboardModifiers inFlags) override; + bool CanAcceptChar(const Q3DStudio::CString &inCheckString, unsigned int inChar, + unsigned int inPosition) override; + +protected: +}; + +#endif // INCLUDED_COMBO_TEXT_BOX_H diff --git a/src/Authoring/Studio/Controls/Control.cpp b/src/Authoring/Studio/Controls/Control.cpp new file mode 100644 index 00000000..dbf06690 --- /dev/null +++ b/src/Authoring/Studio/Controls/Control.cpp @@ -0,0 +1,1806 @@ +/**************************************************************************** +** +** 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 "Control.h" +#include "Renderer.h" +#include "MasterP.h" +#include "StudioUtils.h" +#include "HotKeys.h" +#include "ControlGraph.h" +#include "ControlData.h" +#include "ResourceCache.h" +#include "MouseCursor.h" + +#include + +using namespace Q3DStudio::Control; + +IMPLEMENT_OBJECT_COUNTER(CControl) + +//============================================================================= +/** + * Constructor, creates a control with all default values. + */ +CControl::CControl() + : m_cursorSet(-1) +{ + m_ControlData = CControlData::CreateControlData(*this); + ADDTO_OBJECT_COUNTER(CControl) +} + +//============================================================================= +/** + * Destructor + */ +CControl::~CControl() +{ + REMOVEFROM_OBJECT_COUNTER(CControl) + m_ControlData->ReleaseControl(); +} + +//============================================================================= +/** + * Draw this control and all children below it. + * This can be overriden by controls to draw themselves but should still be + * called if sub controls are to be drawn. + * This will call Draw if this control is actually supposed to be drawn. It will + * be drawn if it is invalidated or if anything above it in it's heirarchy has + * been invalidated. + * @param inRenderer the renderer to draw this control out to. + */ +void CControl::OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, + bool inIgnoreValidation /* = false */) +{ + EnsureLayout(); + bool isInvalidated = IsInvalidated(); + + // inRenderer->PushClippingRect( GetSize( ) ); + + CRct theBoundingBox = inRenderer->GetClippingRect(); + + if (isInvalidated) { + CRct theRect(GetSize()); + theRect.And(theBoundingBox); + theRect.Offset(inRenderer->GetTranslation()); + inDirtyRect.Or(theRect); + } + + if (isInvalidated || inIgnoreValidation) { + Draw(inRenderer); + } + + // Notify the children in the reverse order that they are drawn. + ControlGraph::SReverseIterator theRPos = ControlGraph::GetRChildren(*this); + for (; !theRPos.IsDone(); ++theRPos) { + (*theRPos)->EnsureLayout(); + (*theRPos)->BeginDrawChildren(inRenderer); + } + + // Go through all the children and draw them in the correct order. By keeping + // this order there is a semblance of depth. + ControlGraph::SIterator thePos = ControlGraph::GetChildren(*this); + for (; !thePos.IsDone(); ++thePos) { + std::shared_ptr theChild = (*thePos); + if (theChild->IsVisible()) //&& ( theChild->IsChildInvalidated( ) || inIgnoreValidation || + //isInvalidated ) ) + { + CPt thePosition = theChild->GetPosition(); + inRenderer->PushTranslation(thePosition); + + // Clipping of non-visible objects. + if (theChild->IsInRect(theBoundingBox)) { + theChild->OnDraw(inRenderer, inDirtyRect, inIgnoreValidation || isInvalidated); + } else { + theChild->NotifyNotInClipRect(); + } + inRenderer->PopTranslation(); + } + } + + // inRenderer->PopClippingRect( ); + + // Set this as not being invalidated. + Invalidate(false); +} + +//============================================================================= +/** + * Performs the drawing for this control. + * Does nothing by default. + * @param inRenderer the renderer to draw to. + */ +void CControl::Draw(CRenderer *inRenderer) +{ + Q_UNUSED(inRenderer); +} + +//============================================================================= +/** + * Notification that this control is not in the clipping rect and hence will + * not be drawn. + * By default, tell inform its children + */ +void CControl::NotifyNotInClipRect() +{ + ControlGraph::SIterator thePos = ControlGraph::GetChildren(*this); + for (; !thePos.IsDone(); ++thePos) { + std::shared_ptr theChild = (*thePos); + theChild->NotifyNotInClipRect(); + } +} + +//============================================================================= +/** + * Get the position of this control. + * The position of this control is relative to it's parent's 0,0 coordinate. + * @return the position relative to it's parent's position. + */ +CPt CControl::GetPosition() const +{ + return m_ControlData->m_Position; +} + +//============================================================================= +/** + * Set the position of this control. + * The position of this control is relative to it's parent's 0,0 coordinate. + * @return the position relative to it's parent's position. + */ +void CControl::SetPosition(CPt inPosition) +{ + if (inPosition != m_ControlData->m_Position) { + MarkChildrenNeedLayout(); + m_ControlData->m_Position = inPosition; + Invalidate(); + } +} + +//============================================================================= +/** + * Overload of SetPosition to allow it to take 2 parameters. + * This will call SetPosition( CPt ) so there is no need to extend this + * method. + * @param inX the X position to set. + * @param inY the Y position to set. + */ +void CControl::SetPosition(long inX, long inY) +{ + SetPosition(CPt(inX, inY)); +} + +//============================================================================= +/** + * Get the size of the control. + * The size is the width and height of the control from it's position. + * @return the size of this control. + */ +CPt CControl::GetSize() const +{ + return m_ControlData->m_Size; +} + +//============================================================================= +/** + * Set the size of this control. + * The size is the width and height of the control from it's position. + * @param inSize the new size of the control. + */ +void CControl::SetSize(CPt inSize) +{ + if (GetSize() != inSize) { + m_ControlData->m_Size = inSize; + if (GetParent() != nullptr) + GetParent()->OnChildSizeChanged(this); // this callback needs to die + OnSizeChanged(inSize); + } +} + +void CControl::OnSizeChanged(CPt /*inSize*/) +{ + MarkChildrenNeedLayout(); + Invalidate(); +} + +//============================================================================= +/** + * Overload of SetSize to allow it to take 2 parameters. + * This will call SetSize( CPt ) so there is no need to extend this method. + * @param inWidth the new width of this control. + * @param inHeight the new height of this control. + */ +void CControl::SetSize(long inX, long inY) +{ + SetSize(CPt(inX, inY)); +} + +//============================================================================= +/** + * Get the minimum allowable size of this control. + * This is used by layout managers to get the minimum size that a control is + * allowed to be when it is resizing the control. This defaults to 0,0. + * @return the minimum size that this control is allowed to be. + */ +CPt CControl::GetMinimumSize() +{ + return m_ControlData->m_MinSize; +} + +//============================================================================= +/** + * Set the minimum allowable size of this control. + * This is used by layout managers to get the minimum size that a control is + * allowed to be when it is resizing the control. This defaults to 0,0. + * param inSize the minimum size that this control is allowed to be. + */ +void CControl::SetMinimumSize(CPt inSize) +{ + if (inSize != m_ControlData->m_MinSize) { + NotifyParentNeedsLayout(); + m_ControlData->m_MinSize = inSize; + if (inSize.x > m_ControlData->m_MaxSize.x) + m_ControlData->m_MaxSize.x = inSize.x; + if (inSize.y > m_ControlData->m_MaxSize.y) + m_ControlData->m_MaxSize.y = inSize.y; + } +} + +//============================================================================= +/** + * Get the maximum allowable size of this control. + * This is used by layout managers to get the maximum size that a control is + * allowed to be when it is resizing the control. This defaults to LONG_MAX,LONG_MAX. + * @return the maximum size that this control is allowed to be. + */ +CPt CControl::GetMaximumSize() +{ + return m_ControlData->m_MaxSize; +} + +//============================================================================= +/** + * Set the maximum allowable size of this control. + * This is used by layout managers to get the maximum size that a control is + * allowed to be when it is resizing the control. This defaults to LONG_MAX,LONG_MAX. + * @param inSize the maximum size that this control is allowed to be. + */ +void CControl::SetMaximumSize(CPt inSize) +{ + if (inSize != m_ControlData->m_MaxSize) { + NotifyParentNeedsLayout(); + m_ControlData->m_MaxSize = inSize; + } +} + +//============================================================================= +/** + * Get the preferred size of this control. + * This is used by layout managers to get the preferred size of the control. + * The preferred size is often used for relative scaling of sibling controls. + * @return the preferred size of this control. + */ +CPt CControl::GetPreferredSize() +{ + return m_ControlData->m_PrefSize; +} + +//============================================================================= +/** + * Set the preferred size of this control. + * This is used by layout managers to get the preferred size of the control. + * The preferred size is often used for relative scaling of sibling controls. + * @param the preferred size of this control. + */ +void CControl::SetPreferredSize(CPt inSize) +{ + if (inSize != m_ControlData->m_PrefSize) { + NotifyParentNeedsLayout(); + Invalidate(); + m_ControlData->m_PrefSize = inSize; + } +} + +void CControl::SetAbsoluteSize(CPt inSize) +{ + SetMinimumSize(inSize); + SetMaximumSize(inSize); + SetPreferredSize(inSize); + SetSize(inSize); +} + +//============================================================================= +/** + * Event called when the mouse is moving. + * This event will be called when the mouse is over this control or when this + * control has the focus. This can be extended by controls but should be called + * if the event is to be propagated down to child controls. + * @param inPoint the location of the mouse relative to this control. + * @param inFlags Modifier keys that are down at time of event. Can be any + * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT | + * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON + */ +void CControl::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theHitFlag = false; + // Go through all the children notifying them of mouse moves. + ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + // If a child has not already gotten the move (higher level child covering a lower level + // one) + // then check the hit test. + if (!theHitFlag && theChild->HitTest(inPoint)) { + CPt theChildPoint = inPoint - theChild->GetPosition(); + // This is the first child to be hit, do not allow the message to go onto another + // sibling under this one. + theHitFlag = true; + + // Do not fire events to non-enabled children. + if (theChild->IsEnabled()) { + // If this is the first time the mouse is over this then fire a mouse over + if (!theChild->IsMouseOver()) { + theChild->OnMouseOver(theChildPoint, inFlags); + } + // Fire a mouse move as well, this will also propagate the mouse over to + // grand-children etc. + theChild->OnMouseMove(theChildPoint, inFlags); + } + } + // Check all the children and if they think the mouse is over them then notify them of a + // mouse out. + else if (theChild->IsMouseOver()) { + CPt theChildPoint = inPoint - theChild->GetPosition(); + theChild->OnMouseOut(theChildPoint, inFlags); + } + } + + // If there is a child with focus and the mouse is not over it then still notify it of the mouse + // move + // If the mouse is over it then it would have gotten the move from the above loop. + if (m_ControlData->m_MouseFocus && !m_ControlData->m_MouseFocus->IsMouseOver()) { + CPt theChildPoint = inPoint - m_ControlData->m_MouseFocus->GetPosition(); + m_ControlData->m_MouseFocus->OnMouseMove(theChildPoint, inFlags); + } +} + +//============================================================================= +/** + * Notification that the mouse is over this control. + * This is only called once when the mouse enters the control, and does not get + * called until the mouse leaves then re-enters the control. + * @param inPoint where the mouse is, relative to this control. + * @param inFlags Modifier keys that are down at time of event. Can be any + * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT | + * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON + */ +void CControl::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inPoint); + Q_UNUSED(inFlags); + m_ControlData->m_IsMouseOver = true; +} + +//============================================================================= +/** + * Notification that the mouse left this control. + * This is only called once when the mouse leaves the control and does not get + * called until the mouse enters then re-leaves the control. + * This also notifies all children that the mouse is over that it is no longer + * over. + * @param inPoint where the mouse is, relative to this control. + * @param inFlags Modifier keys that are down at time of event. Can be any + * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT | + * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON + */ +void CControl::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + m_ControlData->m_IsMouseOver = false; + + GetWindowListener()->HideTooltips(); + // Go through all the children looking for ones that think the mouse is over. + // If it is then notify it of a mouse out. + ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + if (theChild->IsMouseOver()) { + CPt theChildPoint = inPoint - theChild->GetPosition(); + theChild->OnMouseOut(inPoint, inFlags); + } + } +} + +//============================================================================= +/** + * Notification that the left mouse button was clicked on this control. + * This handles the mouse hits and sets the focus to the control that was + * clicked on. + * @param inPoint where the mouse was clicked, in local coordinates. + * @param inFlags Modifier keys that are down at time of event. Can be any + * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT | + * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON + * @return true if the mouse event is processed. + */ +bool CControl::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theRetVal = false; + bool theChildGotHit = false; + + // Go through all the children looking for the first one that was clicked on + ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + // If the child was hit then notify it of the mouse down, and set the focus to + // be it. + if (theChild->HitTest(inPoint)) { + CPt theChildPoint = inPoint - theChild->GetPosition(); + theChildGotHit = true; + // Only send the event if the child is enabled. + if (theChild->IsEnabled()) { + theRetVal = theChild->OnMouseDown(theChildPoint, inFlags); + + if (m_ControlData->m_Focus != theChild) { + if (m_ControlData->m_Focus) + m_ControlData->m_Focus->OnLoseFocus(); + if (theChild->CanGainFocus()) { + m_ControlData->m_Focus = theChild; + m_ControlData->m_Focus->OnGainFocus(); + } else + m_ControlData->m_Focus = std::shared_ptr(); + } + m_ControlData->m_MouseFocus = theChild; + } else { + m_ControlData->m_Focus = std::shared_ptr(); + } + + // only want OnMouseDown to be called on the first child under the point. + break; + } + } + if (!theChildGotHit && m_ControlData->m_Focus) { + m_ControlData->m_Focus->OnLoseFocus(); + m_ControlData->m_Focus = std::shared_ptr(); + } + m_ControlData->SetMouseDown(!theRetVal); + + return theRetVal; +} + +//============================================================================= +/** + * Notification that the right mouse button was clicked on this control. + * This handles the mouse hits and sets the focus to the control that was + * clicked on. + * @param inPoint where the mouse was clicked, in local coordinates. + * @param inFlags Modifier keys that are down at time of event. Can be any + * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT | + * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON + * @return true if the mouse event is processed. + */ +bool CControl::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theRetVal = false; + + // Go through all the children looking for the first one that was clicked on + ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + // If the child was hit then notify it of the mouse down, and set the focus to + // be it. + if (theChild->HitTest(inPoint)) { + CPt theChildPoint = inPoint - theChild->GetPosition(); + + // Only send the event if the child is enabled. + if (theChild->IsEnabled()) { + if (m_ControlData->m_Focus != theChild) { + if (m_ControlData->m_Focus) + m_ControlData->m_Focus->OnLoseFocus(); + if (theChild->CanGainFocus()) { + m_ControlData->m_Focus = theChild; + m_ControlData->m_Focus->OnGainFocus(); + } else + m_ControlData->m_Focus = std::shared_ptr(); + } + m_ControlData->m_MouseFocus = theChild; + theRetVal = theChild->OnMouseRDown(theChildPoint, inFlags); + } else { + m_ControlData->m_Focus = std::shared_ptr(); + } + + // only want OnMouseDown to be called on the first child under the point. + break; + } + } + + return theRetVal; +} + +//============================================================================= +/** + * Notification thatthe mouse was double clicked on this control. + * This handled the mouse hits and passes it down to all the children. + * @param inPoint where the mouse was clicked, in local coordinates. + * @param inFlags Modifier keys that are down at time of event. Can be any + * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT | + * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON + * @return true if the mouse event is processed. + */ +bool CControl::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theRetVal = false; + + // Go through all the children looking for the first one that was clicked on + ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + // If the child was hit then notify it of the mouse down, and set the focus to + // be it. + if (theChild->HitTest(inPoint)) { + CPt theChildPoint = inPoint - theChild->GetPosition(); + // Only send the event if the child is enabled. + if (theChild->IsEnabled()) { + theRetVal = theChild->OnMouseDoubleClick(theChildPoint, inFlags); + } + + // only want OnMouseDown to be called on the first child under the point. + break; + } + } + + return theRetVal; +} + +bool CControl::OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags) +{ + bool theRetVal = false; + + // try letting the focus getting the wheel first + if (m_ControlData->m_Focus) { + CPt theChildPoint = inPoint - m_ControlData->m_Focus->GetPosition(); + theRetVal = m_ControlData->m_Focus->OnMouseWheel(theChildPoint, inAmount, inFlags); + } + + // if the focus does not want the wheel then let the mouse pos do it. + if (!theRetVal) { + // Go through all the children looking for the first one that was clicked on + ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + if (theChild->GetMouseWheelEventState() == ControlEventState::Listening + && theChild->IsEnabled() && theChild->HitTest(inPoint)) { + CPt theChildPoint = inPoint - theChild->GetPosition(); + theRetVal = theChild->OnMouseWheel(theChildPoint, inAmount, inFlags); + break; + } + } + } + + return theRetVal; +} + +//============================================================================= +/** + * Notification that the mouse is hovering over this control. + * This handles the mouse hover and passes it down to all the children. + * @param inPoint where the mouse is located, in local coordinates. + * @param inFlags Modifier keys that are down at time of event. Can be any + * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT | + * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON + * @return true if the mouse event is processed. + */ +bool CControl::OnMouseHover(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theRetVal = false; + + // Go through all the children looking for the first one that was clicked on + ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + // If the child was hit then notify it of the mouse down, and set the focus to + // be it. + if (theChild->HitTest(inPoint)) { + CPt theChildPoint = inPoint - theChild->GetPosition(); + // Only send the event if the child is enabled. + if (theChild->IsEnabled()) { + theRetVal = theChild->OnMouseHover(theChildPoint, inFlags); + } + + // only want OnMouseHover to be called on the first child under the point. + break; + } + } + + // If the mouseover was not handled + if (!theRetVal) { + // If the tooltip text is not empty + Q3DStudio::CString theTooltipText = GetTooltipText(); + if (!theTooltipText.IsEmpty()) { + // Show the tooltip, and return true so that parents don't cover this tooltip with their + // own + // Note that we are offsetting the point so that it appears below the mouse cursor + GetWindowListener()->ShowTooltips(GetGlobalPosition(CPt(inPoint.x, inPoint.y + 32)), + GetTooltipText()); + theRetVal = true; + } + } + + return theRetVal; +} + +//============================================================================= +/** + * Notification that the left mouse button was released. + * This is only called on the control that has focus, not on the control under + * the mouse. + * @param inPoint where the mouse was released, in local coordinates. + * @param inFlags Modifier keys that are down at time of event. Can be any + * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT | + * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON + */ +void CControl::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_ControlData->m_MouseFocus) { + CPt theChildPoint = inPoint - m_ControlData->m_MouseFocus->GetPosition(); + m_ControlData->m_MouseFocus->OnMouseUp(theChildPoint, inFlags); + } + + // Go through all the children looking for the first one that was clicked on + ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + // If the child was hit then notify it of the mouse down, and set the focus to + // be it. + if (theChild->HitTest(inPoint)) { + CPt theChildPoint = inPoint - theChild->GetPosition(); + // Only send the event if the child is enabled. + if (theChild->IsEnabled() && theChild != m_ControlData->m_MouseFocus + && theChild != m_ControlData->m_Focus) { + theChild->OnMouseUp(theChildPoint, inFlags); + } + + // only want OnMouseUp to be called on the first child under the point. + break; + } + } + m_ControlData->m_MouseFocus = std::shared_ptr(); + + if (m_ControlData->m_IsMouseDown) { + OnMouseClick(inPoint, inFlags); + m_ControlData->SetMouseDown(false); + } +} + +//============================================================================= +/** + * Notification that the right mouse button was released. + * This is only called on the control that has focus, not on the control under + * the mouse. + * @param inPoint where the mouse was released, in local coordinates. + * @param inFlags Modifier keys that are down at time of event. Can be any + * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT | + * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON + */ +void CControl::OnMouseRUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_ControlData->m_MouseFocus) { + CPt theChildPoint = inPoint - m_ControlData->m_MouseFocus->GetPosition(); + m_ControlData->m_MouseFocus->OnMouseRUp(theChildPoint, inFlags); + } + + // Go through all the children looking for the first one that was clicked on + ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + // If the child was hit then notify it of the mouse down, and set the focus to + // be it. + if (theChild->HitTest(inPoint)) { + CPt theChildPoint = inPoint - theChild->GetPosition(); + // Only send the event if the child is enabled. + if (theChild->IsEnabled() && theChild != m_ControlData->m_MouseFocus + && theChild != m_ControlData->m_Focus) { + theChild->OnMouseRUp(theChildPoint, inFlags); + } + + // only want OnMouseUp to be called on the first child under the point. + break; + } + } + m_ControlData->m_MouseFocus = std::shared_ptr(); +} + +//============================================================================= +/** + * Handles character input from the keyboard. + * + * @param inChar Character that was pressed + * @return true if the character was handled, false if this control does not + * care about the character that was pressed + */ +bool CControl::OnChar(const QString &inChar, Qt::KeyboardModifiers inModifiers) +{ + if (m_ControlData->m_Focus) + return m_ControlData->m_Focus->OnChar(inChar, inModifiers); + else + return false; +} + +//============================================================================= +/** + * Handles a key down message from the keyboard. + * + * @param inChar Character that was pressed + * @return true if the character was handled, false if this control does not + * care about the character that was pressed + */ +bool CControl::OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inModifiers) +{ + bool theRetVal = false; + + if (m_ControlData->m_Focus) + theRetVal = m_ControlData->m_Focus->OnKeyDown(inChar, inModifiers); + + if (!theRetVal) { + if (inChar == Qt::Key_Tab) { + if (inModifiers & Qt::ShiftModifier) { + OnReverseTab(); + } else { + OnTab(); + } + theRetVal = true; + } + } + + return theRetVal; +} + +//============================================================================= +/** + * Handles a key up from the keyboard. + * + * @param inChar Character that was pressed + * @return true if the character was handled, false if this control does not + * care about the character that was pressed + */ +bool CControl::OnKeyUp(unsigned int inChar, Qt::KeyboardModifiers) +{ + Q_UNUSED(inChar); + return false; +} + +//============================================================================= +/** + * Find the first child (descendant) control that has a valid drop target. + */ +CDropTarget *CControl::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags) +{ + CDropTarget *theDropTarget = NULL; + + // Go through all the children looking for the first one that was clicked on + ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + if (theChild->IsMouseOver() && theChild->IsEnabled()) { + // Put the point into this childs coords. + CPt theChildPoint = inMousePoint - theChild->GetPosition(); + + // Allow the child the opportunity to respond + theDropTarget = theChild->FindDropCandidate(theChildPoint, inFlags); + + if (theDropTarget) + break; + } + } + return theDropTarget; +} + +//============================================================================= +/** + * Add a child control to this control. + * This will make the child behave as a child of this, get set up for drawing + * and events. The inInsertBefore control is used to determine Z-depth, or + * manually insert a control into a specific location. + * The child cannot already be a child of another control. + * @param inControl the control to be added. + * @param inInsertBefore the control to be inserted before, or std::shared_ptr() to + * be at the back.\ + */ +void CControl::AddChild(CControl *inControl, + CControl *inInsertBefore /*=std::shared_ptr()*/) +{ + NotifyParentNeedsLayout(); + ControlGraph::AddChild(*this, *inControl, inInsertBefore); +} + +//============================================================================= +/** + * Remove a child control from this control. + * This will remove it from drawing and getting any events. + * @param inControl the control to be removed. + */ +void CControl::RemoveChild(CControl *inControl) +{ + if (inControl) { + ControlGraph::RemoveChild(*this, *inControl); + + if (m_ControlData->m_Focus == inControl->m_ControlData) { + m_ControlData->m_Focus = std::shared_ptr(); + } + if (m_ControlData->m_MouseFocus == inControl->m_ControlData) { + m_ControlData->m_MouseFocus = std::shared_ptr(); + } + } +} + +//============================================================================= +/** + * Remove all child controls from this control. + * This will remove it from drawing and getting any events. + * + * This is not recursive + */ +void CControl::RemoveAllChildren() +{ + NotifyParentNeedsLayout(); + ControlGraph::RemoveAllChildren(*this); + + m_ControlData->m_Focus = std::shared_ptr(); + m_ControlData->m_MouseFocus = std::shared_ptr(); +} + +//============================================================================= +/** + * Retrieve the index of a child control. The index will return the zero based position. + * @param inChildControl the control that is a direct child of this control + * @return the zero-based index of this control we will return -1 if we don't find the control + */ +long CControl::GetChildIndex(CControl *inChildControl) +{ + return ControlGraph::GetChildIndex(*this, *inChildControl); +} + +static inline CControl *ToControl(std::shared_ptr inPtr) +{ + if (inPtr) + return inPtr->GetControl(); + return nullptr; +} + +//============================================================================= +/** + * Finds a child control by its name + * @return the child if found, std::shared_ptr() otherwise + */ +CControl *CControl::FindChildByName(const Q3DStudio::CString &inName) +{ + std::shared_ptr theResult = std::shared_ptr(); + + ControlGraph::SIterator theChildIter = GetChildren(); + for (; !theChildIter.IsDone(); ++theChildIter) { + if (theChildIter.GetCurrent()->GetName() == inName) { + theResult = theChildIter.GetCurrent(); + break; + } + } + + return ToControl(theResult); +} + +CControl *CControl::FocusedChild() +{ + CControl *theResult = nullptr; + + ControlGraph::SIterator theChildIter = GetChildren(); + for (; !theChildIter.IsDone(); ++theChildIter) { + auto current = ToControl(theChildIter.GetCurrent()); + auto hasFocus = HasFocus(current); + if (hasFocus) { + if (current->GetFirstChild()) + theResult = current->FocusedChild(); + else + theResult = current; + break; + } + } + + return theResult; +} + +//============================================================================= +/** + * Check to see if the mouse is over this control or not. + * @return true if the mouse is over this control. + */ +bool CControl::IsMouseOver() const +{ + return m_ControlData->m_IsMouseOver; +} + +//============================================================================= +/** + * Check to see if inPoint is over this control or not. + * This is used for mouse hits and can be extended for non-standard control + * shapes. Non-visible controls always return false. + * @param inPoint the location of the mouse in local coordinates. + */ +bool CControl::HitTest(const CPt &inPoint) const +{ + CPt thePoint = inPoint - GetPosition(); + CPt theSize = GetSize(); + // Basic check to see if it's in the size. + if (IsVisible() && thePoint.x >= 0 && thePoint.y >= 0 && thePoint.x < theSize.x + && thePoint.y < theSize.y) + return true; + return false; +} + +//============================================================================= +/** + * Checks to see if any part of this control is in the rect. + * This is used for drawing and ignoring objects that do not need to be + * redrawn or need to be drawn. + * @param inRect the rect to check to see if this is in. + * @return true if this is in the rect. + */ +bool CControl::IsInRect(const CRct &inRect) const +{ + CRct myRect(GetPosition(), GetSize()); + + if (myRect.position <= inRect.size + inRect.position) { + if (myRect.size + myRect.position >= inRect.position) { + return true; + } + } + return false; +} + +//============================================================================= +/** + * Invalidate this control and cause it to be redrawn. + * @param inInvalidate true if this is to be invalidated. + */ +void CControl::Invalidate(bool inInvalidate /*= true*/) +{ + m_ControlData->m_IsInvalidated = inInvalidate; + if (inInvalidate && GetParent() != nullptr) { + GetParent()->OnChildInvalidated(); + } + if (!inInvalidate) { + m_ControlData->m_IsChildInvalidated = false; + } +} + +//============================================================================= +/** + * Invalidate this object and all children within inRect. + * @param inRect the rect in which to invalidate all children. + */ +void CControl::InvalidateRect(const CRct &inRect) +{ + Invalidate(); + + ControlGraph::SIterator thePos = GetChildren(); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + if (theChild->IsInRect(inRect)) { + CRct theChildRect = inRect; + theChildRect.Offset(theChild->GetPosition()); + + theChild->InvalidateRect(inRect); + } + } +} + +//============================================================================= +/** + * Check to see if this control is invalidated or not. + * @return true if this control is invalidated. + */ +bool CControl::IsInvalidated() const +{ + return m_ControlData->IsInvalidated(); +} + +//============================================================================= +/** + * Notifies this control that a child of it has been invalidated. + */ +void CControl::OnChildInvalidated() +{ + // Only do it if we haven't already, avoid multiple traversals up the tree. + if (!m_ControlData->m_IsChildInvalidated) { + if (GetParent() != nullptr) + GetParent()->OnChildInvalidated(); + else if (m_ControlData->m_WindowListener != nullptr) + m_ControlData->m_WindowListener->OnControlInvalidated(); + + m_ControlData->m_IsChildInvalidated = true; + } +} + +//============================================================================= +/** + * Checks to see if a child of this control is invalidated. + */ +bool CControl::IsChildInvalidated() const +{ + return m_ControlData->m_IsChildInvalidated || m_ControlData->m_IsInvalidated; +} + +void CControl::SetWindowListener(CControlWindowListener *inListener) +{ + m_ControlData->m_WindowListener = inListener; +} + +//============================================================================= +/** + * Retrieves the topmost window of this control. The window listener is the + * bridge between the OS and the cross-platform custom control code below. + * This function was added specifically to support drag-and-drop by providing + * a way of setting the drag state on the outermost window. + * @return pointer to the control window listener or std::shared_ptr() if there is + * not one + */ +CControlWindowListener *CControl::GetWindowListener() +{ + CControlWindowListener *theWindowListener = nullptr; + if (GetParent() != nullptr) + theWindowListener = GetParent()->GetWindowListener(); + else + theWindowListener = m_ControlData->m_WindowListener; + return theWindowListener; +} + +//============================================================================= +/** + * 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 CControl::SetVisible(bool inIsVisible) +{ + if (inIsVisible != m_ControlData->m_IsVisible) { + m_ControlData->m_IsVisible = inIsVisible; + NotifyParentNeedsLayout(); + + if (GetParent() != nullptr) + GetParent()->OnChildSizeChanged(this); + + OnVisibleStateChange(inIsVisible); + OnParentVisibleStateChanged(inIsVisible); + + this->Invalidate(); + } +} + +//============================================================================= +/** + * Notification that the visible state of a control has changed + */ +void CControl::OnVisibleStateChange(bool inIsVisible) +{ + Q_UNUSED(inIsVisible); +} + +void CControl::OnParentVisibleStateChanged(bool inIsVisible) +{ + NotifyParentNeedsLayout(); + ControlGraph::SIterator thePos = GetChildren(); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + theChild->OnParentVisibleStateChanged(inIsVisible); + } +} + +//============================================================================= +/** + * Checks to see if this control is visible or not. + * If the control is not visible then it will not be drawn and will not + * get mouse clicks. + * @return true if this control is visible. + */ +bool CControl::IsVisible() const +{ + return m_ControlData->m_IsVisible; +} + +//============================================================================= +/** + * 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 CControl::SetEnabled(bool inIsEnabled) +{ + if (inIsEnabled != m_ControlData->m_IsEnabled) { + NotifyParentNeedsLayout(); + m_ControlData->m_IsEnabled = inIsEnabled; + + ControlGraph::SIterator thePos = GetChildren(); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + theChild->SetParentEnabled(inIsEnabled); + } + Invalidate(); + } +} + +void CControl::SetParentEnabled(bool inParentEnabled) +{ + NotifyParentNeedsLayout(); + m_ControlData->m_IsParentEnabled = inParentEnabled; + ControlGraph::SIterator thePos = GetChildren(); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + theChild->SetParentEnabled(inParentEnabled); + } + Invalidate(); +} + +//============================================================================= +/** + * Gets 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. + */ +bool CControl::IsEnabled() const +{ + return m_ControlData->IsEnabled(); +} + +//============================================================================= +/** + * Gets teh value of the enabled flag without its parent's flag + */ +bool CControl::GetEnabledFlag() +{ + return m_ControlData->GetEnabledFlag(); +} + +//============================================================================= +/** + * Sets the enabled flag...this is used when a control wants to override the + * SetEnabled function and does not necessarily want to pass enabled messages + * to its children no matter what + */ +void CControl::SetEnabledFlag(bool inIsEnabled) +{ + m_ControlData->SetEnabledFlag(inIsEnabled); + Invalidate(); +} + +//============================================================================= +/** + * Notification that the size of a child has changed. + * @param inControl the control that has changed size. + */ +void CControl::OnChildSizeChanged(CControl *inControl) +{ + Q_UNUSED(inControl); +} + +void CControl::SetName(const Q3DStudio::CString &inName) +{ + m_ControlData->SetName(inName); +} + +Q3DStudio::CString CControl::GetName() +{ + return m_ControlData->GetName(); +} + +void CControl::BeginDrawChildren(CRenderer *inRenderer) +{ + Q_UNUSED(inRenderer); +} + +long CControl::DoPopup(QMenu *inMenu, CPt inLocation) +{ + inLocation.Offset(GetPosition()); + CControl *theParent(GetParent()); + if (theParent) { + return theParent->DoPopup(inMenu, inLocation); + } else { + return m_ControlData->m_WindowListener->DoPopup(inMenu, inLocation); + } +} + +//============================================================================= +/** + * Called when a control acquires focus + */ +void CControl::OnGainFocus() +{ +} + +//============================================================================= +/** + * Causes focus to be lost. + */ +void CControl::OnLoseFocus() +{ + if (m_ControlData->m_Focus) { + m_ControlData->m_Focus->OnLoseFocus(); + } + FireFocusEvent(false); + m_ControlData->m_Focus = std::shared_ptr(); +} + +//============================================================================= +/** + * @return the parent control of this class + */ +CControl *CControl::GetParent() +{ + return m_ControlData->GetParent(); +} + +const CControl *CControl::GetParent() const +{ + return m_ControlData->GetParent(); +} + +//============================================================================= +/** + * Removes a control from the top level control + */ +void CControl::RemoveUberControl(CControl *inControl) +{ + if (GetParent() != nullptr) { + GetParent()->RemoveUberControl(inControl); + } else { + RemoveChild(inControl); + } + Invalidate(); +} + +long CControl::GetChildCount() +{ + return ControlGraph::GetNumChildren(*this); +} + +Q3DStudio::Control::ControlGraph::SIterator CControl::GetChildren() +{ + return ControlGraph::GetChildren(*this); +} + +Q3DStudio::Control::ControlGraph::SReverseIterator CControl::GetReverseChildren() +{ + return ControlGraph::GetRChildren(*this); +} + +//============================================================================= +/** + * Gets the global position of the point in regards to the top level control + */ +CPt CControl::GetGlobalPosition(CPt inChildPoint) const +{ + CPt thePosition(GetPosition()); + CPt thePoint = CPt(inChildPoint.x + thePosition.x, inChildPoint.y + thePosition.y); + if (GetParent()) + return GetParent()->GetGlobalPosition(thePoint); + else + return thePoint; +} + +//============================================================================= +/** + * Query the platform specific render device (window) + */ +UICRenderDevice CControl::GetPlatformDevice() +{ + if (GetParent()) + return GetParent()->GetPlatformDevice(); + return nullptr; +} + +//============================================================================= +/** + * Does self or child use this render device? + * @see CWndControl::OnKillFocus + */ +bool CControl::IsChildPlatformDevice(UICRenderDevice inDevice) +{ + if (GetPlatformDevice() == inDevice) + return true; + + ControlGraph::SIterator thePos = GetChildren(); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + if (theChild->IsChildPlatformDevice(inDevice)) + return true; + } + + return false; +} + +//============================================================================= +/** + * Shows the window's moveable window with text + * + * @param inLocation the postion of hte center point of the window + * @param inText the text the window will display + */ +void CControl::ShowMoveableWindow(CPt inLocation, const Q3DStudio::CString &inText, CRct inBoundingRct) +{ + CPt thePosition(GetPosition()); + CPt thePoint = CPt(inLocation.x + thePosition.x, inLocation.y + thePosition.y); + + if (GetParent()) + GetParent()->ShowMoveableWindow(thePoint, inText, inBoundingRct); + else if (m_ControlData->m_WindowListener) { + m_ControlData->m_WindowListener->ShowMoveableWindow(thePoint, inText, inBoundingRct); + } +} + +//============================================================================= +/** + * Hides the window's moveable window + */ +void CControl::HideMoveableWindow() +{ + if (GetParent() != nullptr) + GetParent()->HideMoveableWindow(); + else if (m_ControlData->m_WindowListener) + m_ControlData->m_WindowListener->HideMoveableWindow(); +} + +//============================================================================= +/** + * Offsets the position of this control... this is useful if you don't want to calculate + * the global position every time + */ +void CControl::OffsetPosition(CPt inOffset) +{ + CPt thePosition(GetPosition()); + thePosition.Offset(inOffset); + SetPosition(thePosition); +} + +//============================================================================= +/** + * Gets the first child of this control + */ +CControl *CControl::GetFirstChild() +{ + std::shared_ptr theChild = std::shared_ptr(); + ControlGraph::SIterator thePos = ControlGraph::GetChildren(*this); + if (!thePos.IsDone()) { + theChild = (*thePos); + } + return ToControl(theChild); +} + +//============================================================================= +/** + * @return true if this control has focus + */ +bool CControl::HasFocus(CControl *inControl) +{ + return (ToControl(m_ControlData->m_Focus) == inControl); +} + +//============================================================================= +/** + * default is true for controls... override if the control cannot have focus + */ +bool CControl::CanGainFocus() +{ + if (IsVisible()) + for (ControlGraph::SIterator thePos = ControlGraph::GetChildren(*this); !thePos.IsDone(); + ++thePos) + if ((*thePos)->CanGainFocus()) + return true; + + return false; +} + +//============================================================================= +/** + * Returns true if this CControl is in focus. + * @return True if this CControl is in focus. + */ +bool CControl::IsInFocus() +{ + if (GetParent()) + return GetParent()->HasFocus(this); + + return false; +} + +//============================================================================= +/** + * Handles the tab button in controls + */ +void CControl::OnTab() +{ + // Go through the children... if there is a focus, then get the next control + ControlGraph::SIterator thePos = ControlGraph::GetChildren(*this); + bool theFoundFlag = false; + if (m_ControlData->m_Focus) { + while (!thePos.IsDone() && !theFoundFlag) { + std::shared_ptr theCurrentControl = (*thePos); + if (theCurrentControl == m_ControlData->m_Focus) { + ++thePos; + while (!thePos.IsDone() && !theFoundFlag) { + std::shared_ptr theNextFocusCanidate = (*thePos); + if (theNextFocusCanidate->CanGainFocus()) { + m_ControlData->m_Focus->OnLoseFocus(); + theFoundFlag = true; + m_ControlData->m_Focus = theNextFocusCanidate; + m_ControlData->m_Focus->SetFocusToFirstAvailable(); + } else { + ++thePos; + } + } + } else { + ++thePos; + } + } + // If we didn't find it and we have a parent, then allow the parent to decide + if (!theFoundFlag) { + m_ControlData->m_Focus->OnLoseFocus(); + m_ControlData->m_Focus = std::shared_ptr(); + if (GetParent()) + GetParent()->OnTab(); + else + SetFocusToFirstAvailable(); + } + } + // If no focus, then go to first available control + else { + SetFocusToFirstAvailable(); + } +} + +//============================================================================= +/** + * Handles the shift tab button in controls + */ +void CControl::OnReverseTab() +{ + // Go through the children in reverse order... if there is a focus, then get the next control + ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this); + bool theFoundFlag = false; + if (m_ControlData->m_Focus) { + while (!thePos.IsDone() && !theFoundFlag) { + std::shared_ptr theCurrentControl = (*thePos); + if (theCurrentControl == m_ControlData->m_Focus) { + ++thePos; + while (!thePos.IsDone() && !theFoundFlag) { + std::shared_ptr theNextFocusCanidate = (*thePos); + if (theNextFocusCanidate->CanGainFocus()) { + m_ControlData->m_Focus->OnLoseFocus(); + theFoundFlag = true; + m_ControlData->m_Focus = theNextFocusCanidate; + m_ControlData->m_Focus->SetFocusToLastAvailable(); + } else { + ++thePos; + } + } + } else { + ++thePos; + } + } + // If we didn't find it and we have a parent, then allow the parent to decide + if (!theFoundFlag) { + m_ControlData->m_Focus->OnLoseFocus(); + m_ControlData->m_Focus = std::shared_ptr(); + if (GetParent()) + GetParent()->OnReverseTab(); + else + SetFocusToLastAvailable(); + } + } + + // If no focus, then go to last available control + else { + SetFocusToLastAvailable(); + } +} + +//============================================================================= +/** + * Sets the focus to the first available child control + */ +void CControl::SetFocusToFirstAvailable() +{ + bool theFlag = false; + OnGainFocus(); + + // if there are any child controls, then go through them + for (ControlGraph::SIterator thePos = ControlGraph::GetChildren(*this); + !thePos.IsDone() && !theFlag; ++thePos) { + std::shared_ptr theControl = (*thePos); + if (theControl->CanGainFocus()) { + m_ControlData->m_Focus = theControl; + m_ControlData->m_Focus->SetFocusToFirstAvailable(); + theFlag = true; + } + } +} + +//============================================================================= +/** + * Sets the focus to the last available child control + */ +void CControl::SetFocusToLastAvailable() +{ + bool theFlag = false; + OnGainFocus(); + + // if there are any child controls, then go through them + for (ControlGraph::SReverseIterator thePos = ControlGraph::GetRChildren(*this); + !thePos.IsDone() && !theFlag; ++thePos) { + std::shared_ptr theControl = (*thePos); + if (theControl->CanGainFocus()) { + m_ControlData->m_Focus = theControl; + m_ControlData->m_Focus->SetFocusToLastAvailable(); + theFlag = true; + } + } +} + +//=============================================================================== +/** +* Coverts the given point from local coordinates into global coordinates. +* @param inPoint the point in local coordinates to be converted +* @return The point translated to global coordinates +*/ +CPt CControl::ClientToScreen(CPt inPoint) +{ + CPt theFinalPt = inPoint + m_ControlData->m_Position; + + if (GetParent()) + theFinalPt = GetParent()->ClientToScreen(theFinalPt); + else if (m_ControlData->m_WindowListener) + theFinalPt = m_ControlData->m_WindowListener->ClientToScreen(theFinalPt); + + return theFinalPt; +} + +//=============================================================================== +/** +* Coverts the given point from screen coordinates into local space. +* @param inPoint the point in screen coordinates to be converted +* @return The point translated to local, client coordinates +*/ +CPt CControl::ScreenToClient(CPt inPoint) +{ + CPt theFinalPt = inPoint - m_ControlData->m_Position; + + if (GetParent()) + theFinalPt = GetParent()->ScreenToClient(theFinalPt); + else if (m_ControlData->m_WindowListener) + theFinalPt = m_ControlData->m_WindowListener->ScreenToClient(theFinalPt); + + return theFinalPt; +} + +//=============================================================================== +/** +* Adds a focus listener to this control +*/ +void CControl::AddFocusListener(CChildFocusListener *inListener) +{ + m_ControlData->m_FocusListeners.AddListener(inListener); +} + +//=============================================================================== +/** +* Removes a focus listener to this control +*/ +void CControl::RemoveFocusListener(CChildFocusListener *inListener) +{ + m_ControlData->m_FocusListeners.RemoveListener(inListener); +} + +//=============================================================================== +/** +* tells anyone listeneing that the focus of this control has changed +*/ +void CControl::FireFocusEvent(bool inStatus) +{ + m_ControlData->m_FocusListeners.FireEvent(&CChildFocusListener::OnChildFocusChange, inStatus); +} + +//=============================================================================== +/** + * Get the platform specific view that this is embedded into. + * Used for when platform dependent controls have to be embedded or used. + */ +TPlatformView CControl::GetPlatformView() +{ + if (GetParent()) + return GetParent()->GetPlatformView(); + else if (m_ControlData->m_WindowListener) + return m_ControlData->m_WindowListener->GetPlatformView(); + return nullptr; +} + +bool CControl::IsMouseDown() +{ + return m_ControlData->m_IsMouseDown; +} + +void CControl::OnMouseClick(CPt, Qt::KeyboardModifiers) +{ +} + +//=============================================================================== +/** + * Sets the text of the tooltip for this control. If the string is empty, no + * tooltip will be shown. + * @param inText text of the tooltip + */ +void CControl::SetTooltipText(const Q3DStudio::CString &inText) +{ + m_ControlData->SetTooltipText(inText); +} + +//=============================================================================== +/** + * @return the current tooltip text for this control + */ +Q3DStudio::CString CControl::GetTooltipText() +{ + return m_ControlData->GetTooltipText(); +} + +void CControl::GrabFocus(CControl *inControl) +{ + if (GetParent()) + GetParent()->GrabFocus(this); + + std::shared_ptr theNewFocus; + if (inControl) + theNewFocus = inControl->m_ControlData; + + if (m_ControlData->m_Focus != theNewFocus) { + if (m_ControlData->m_Focus) + m_ControlData->m_Focus->OnLoseFocus(); + m_ControlData->m_Focus = theNewFocus; + if (m_ControlData->m_Focus) + m_ControlData->m_Focus->OnGainFocus(); + } +} + +//=============================================================================== +/** + * Used to notify scrolling views that something should be visible. + */ +void CControl::EnsureVisible(CRct inRect) +{ + if (GetParent()) { + inRect.Offset(GetPosition()); + GetParent()->EnsureVisible(inRect); + } +} + +//=============================================================================== +/** + * Call to make this control visible. + */ +void CControl::EnsureVisible() +{ + CRct theRect(CPt(0, 0), GetSize()); + EnsureVisible(theRect); +} + +void CControl::OnParentChanged(CControl * /*inNewParent*/) +{ +} + +void CControl::MarkChildrenNeedLayout() +{ + if (m_ControlData->m_ChildrenNeedLayout == false) { + for (ControlGraph::SIterator theIter = GetChildren(); theIter.IsDone() == false; ++theIter) + (*theIter)->MarkNeedsLayout(); + m_ControlData->m_ChildrenNeedLayout = true; + } +} + +void CControl::NotifyParentNeedsLayout() +{ + CControl *theParent(GetParent()); + if (theParent) + theParent->MarkChildrenNeedLayout(); +} + +void CControl::MarkNeedsLayout() +{ + m_ControlData->m_NeedsLayout = true; +} +// Tell this control that one of its children need to be layed out. +void CControl::SetLayout(CPt inSize, CPt inPosition) +{ + SetSize(inSize); + SetPosition(inPosition); + m_ControlData->m_NeedsLayout = false; +} + +void CControl::LayoutChildren() +{ + for (ControlGraph::SIterator theIter = GetChildren(); theIter.IsDone() == false; ++theIter) { + std::shared_ptr theChild(*theIter); + // By default the children get the exact same layout that I do. + theChild->SetLayout(theChild->m_Size, theChild->m_Position); + } + m_ControlData->m_ChildrenNeedLayout = false; +} + +void CControl::EnsureLayout() +{ + if (m_ControlData->m_NeedsLayout) { + if (IsVisible()) { + CControl *parent = GetParent(); + if (parent) + parent->LayoutChildren(); + } + m_ControlData->m_NeedsLayout = false; + } + if (m_ControlData->m_ChildrenNeedLayout) { + LayoutChildren(); + m_ControlData->m_ChildrenNeedLayout = false; + } +} + +void CControl::ChildrenChanged() +{ + MarkChildrenNeedLayout(); + Invalidate(); + m_ControlData->OnHierarchyChanged(); +} + +void CControl::setCursorIfNotSet(long cursor) +{ + if (cursor != m_cursorSet) { + if (m_cursorSet != -1) + qApp->restoreOverrideCursor(); + m_cursorSet = cursor; + qApp->setOverrideCursor(CResourceCache::GetInstance()->GetCursor(cursor)); + } +} + +void CControl::resetCursor() +{ + if (m_cursorSet != -1) { + qApp->restoreOverrideCursor(); + m_cursorSet = -1; + } +} + +QCursor CControl::getCursor() const +{ + if (m_cursorSet != -1) + return CResourceCache::GetInstance()->GetCursor(m_cursorSet); + return QCursor(); +} diff --git a/src/Authoring/Studio/Controls/Control.h b/src/Authoring/Studio/Controls/Control.h new file mode 100644 index 00000000..0d2ea79e --- /dev/null +++ b/src/Authoring/Studio/Controls/Control.h @@ -0,0 +1,263 @@ +/**************************************************************************** +** +** 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_CONTROL_H +#define INCLUDED_CONTROL_H 1 + +#pragma once + +#include "Pt.h" +#include "Rct.h" +#include "SafeArray.h" +#include "GenericFunctor.h" +#include "PlatformTypes.h" + +#include "DropTarget.h" +#include +#include +#include "ControlGraphIterators.h" + +class CRenderer; +class CContextMenu; +class CUICFile; +class IDragable; +class CAsset; +class CStudioApp; + +class QMenu; + +namespace Q3DStudio { +namespace Control { + class CControlData; + using std::pair; + using std::make_pair; + using std::vector; +} +} + +// this functor is used to tell when a child loses focus the boolean should be true if the child +// gains focus +GENERIC_FUNCTOR_1(CChildFocusListener, OnChildFocusChange, bool) + +#ifdef _WIN32 +typedef HWND TPlatformView; +#else +typedef void *TPlatformView; +#endif + +class CControlWindowListener +{ +public: + virtual void OnControlInvalidated() = 0; + virtual long DoPopup(QMenu *inMenu, CPt inLocation) = 0; + virtual CPt ClientToScreen(CPt inPoint) = 0; + virtual CPt ScreenToClient(CPt inPoint) = 0; + virtual TPlatformView GetPlatformView() = 0; + virtual void SetIsDragging(bool inIsDragging) = 0; + virtual void ShowTooltips(CPt inLocation, const Q3DStudio::CString &inText) = 0; + virtual void HideTooltips() = 0; + virtual void DoStartDrag(IDragable *inDragable) = 0; + virtual void DoStartDrag(std::vector &inDragFileList) = 0; + virtual void ShowMoveableWindow(CPt inLocation, const Q3DStudio::CString &inText, + CRct inBoundingRct) = 0; + virtual void HideMoveableWindow() = 0; +}; + +namespace Q3DStudio { +namespace Control { + class CControlData; +} +} + +class CControl : public boost::BOOST_SIGNALS_NAMESPACE::trackable +{ + + CControl(CControl &inOther); + CControl &operator=(CControl &inOther); + +public: + CControl(); + virtual ~CControl(); + + DEFINE_OBJECT_COUNTER(CControl) + + CControl *GetParent(); + const CControl *GetParent() const; + + virtual void OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation = false); + virtual void Draw(CRenderer *inRenderer); + virtual void NotifyNotInClipRect(); + + virtual CPt GetPosition() const; + virtual void SetPosition(CPt inPosition); + void SetPosition(long inX, long inY); + + virtual CPt GetSize() const; + virtual void SetSize(CPt inSize); + void SetSize(long inWidth, long inHeight); + virtual void OnSizeChanged(CPt inSize); + + virtual CPt GetMinimumSize(); + virtual void SetMinimumSize(CPt inSize); + + virtual CPt GetMaximumSize(); + virtual void SetMaximumSize(CPt inSize); + + virtual CPt GetPreferredSize(); + virtual void SetPreferredSize(CPt inSize); + + virtual void SetAbsoluteSize(CPt inSize); + + virtual void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual void OnMouseRUp(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual void OnMouseClick(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual bool OnMouseHover(CPt inPoint, Qt::KeyboardModifiers inFlags); + /** + Note that just overriding this isn't enough, you need to call + m_ControlData->SetMouseWheelEnabled( true ) + in order to receive mouse wheel events + */ + virtual bool OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags); + virtual bool OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inFlags); + virtual bool OnKeyUp(unsigned int inChar, Qt::KeyboardModifiers inFlags); + virtual bool OnChar(const QString &inChar, Qt::KeyboardModifiers inFlags); + virtual void OnLoseFocus(); + virtual void OnGainFocus(); + virtual bool CanGainFocus(); + virtual bool IsInFocus(); + void OnTab(); + void OnReverseTab(); + void SetFocusToFirstAvailable(); + void SetFocusToLastAvailable(); + + virtual CDropTarget *FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags); + + virtual void AddChild(CControl *inControl, CControl *inInsertBefore = NULL); + virtual void RemoveChild(CControl *inControl); + virtual void RemoveAllChildren(); + virtual long GetChildIndex(CControl *inChildControl); + virtual CControl *FindChildByName(const Q3DStudio::CString &inName); + CControl *FocusedChild(); + + virtual bool IsMouseOver() const; + + virtual bool HitTest(const CPt &inPoint) const; + virtual bool IsInRect(const CRct &inRect) const; + + virtual void Invalidate(bool inInvalidate = true); + virtual void InvalidateRect(const CRct &inRect); + virtual bool IsInvalidated() const; + + virtual void OnChildInvalidated(); + virtual bool IsChildInvalidated() const; + + virtual void SetVisible(bool inIsVisible); + virtual bool IsVisible() const; + virtual void OnVisibleStateChange(bool inIsVisible); + virtual void OnParentVisibleStateChanged(bool inIsVisible); + + virtual void SetParentEnabled(bool inParentEnabled); + virtual void SetEnabled(bool inIsEnabled); + virtual bool IsEnabled() const; + bool GetEnabledFlag(); + void SetEnabledFlag(bool inIsEnabled); + + void SetWindowListener(CControlWindowListener *inListener); + CControlWindowListener *GetWindowListener(); + + virtual void OnChildSizeChanged(CControl *inChild); + virtual void ResetMinMaxPref(){} + + void SetName(const Q3DStudio::CString &inName); + Q3DStudio::CString GetName(); + + virtual void BeginDrawChildren(CRenderer *inRenderer); + + virtual long DoPopup(QMenu *inContextMenu, CPt inPoint); + virtual void RemoveUberControl(CControl *inControl); + virtual void OffsetPosition(CPt inOffset); + + virtual CPt GetGlobalPosition(CPt inChildPoint) const; + virtual UICRenderDevice GetPlatformDevice(); + bool IsChildPlatformDevice(UICRenderDevice inDevice); + virtual void ShowMoveableWindow(CPt inLocation, const Q3DStudio::CString &inText, CRct inBoundingRct); + virtual void HideMoveableWindow(); + CControl *GetFirstChild(); + bool HasFocus(CControl *inControl); + virtual void GrabFocus(CControl *inControl); + + virtual CPt ClientToScreen(CPt inPoint); + virtual CPt ScreenToClient(CPt inPoint); + + void AddFocusListener(CChildFocusListener *inListener); + void RemoveFocusListener(CChildFocusListener *inListener); + void FireFocusEvent(bool inStatus); + + void SetTooltipText(const Q3DStudio::CString &inText); + Q3DStudio::CString GetTooltipText(); + + virtual void EnsureVisible(CRct inRect); + void EnsureVisible(); + + virtual void OnParentChanged(CControl *inNewParent); + + virtual void MarkChildrenNeedLayout(); + virtual void MarkNeedsLayout(); + // Tell our parent that we (and all our siblings) need to be + // laid out. + virtual void NotifyParentNeedsLayout(); + // Tell this control that one of its children need to be layed out. + virtual void SetLayout(CPt inSize, CPt inPosition); + virtual void LayoutChildren(); + virtual void EnsureLayout(); + + virtual void ChildrenChanged(); + + Q3DStudio::Control::ControlGraph::SIterator GetChildren(); + Q3DStudio::Control::ControlGraph::SReverseIterator GetReverseChildren(); + +protected: ///< Current size of this control + // Member Functions + + long GetChildCount(); + TPlatformView GetPlatformView(); + bool IsMouseDown(); + void setCursorIfNotSet(long cursor); + void resetCursor(); + QCursor getCursor() const; + + std::shared_ptr m_ControlData; + long m_cursorSet; +}; +#endif // INCLUDED_CONTROL_H diff --git a/src/Authoring/Studio/Controls/ControlData.cpp b/src/Authoring/Studio/Controls/ControlData.cpp new file mode 100644 index 00000000..65122537 --- /dev/null +++ b/src/Authoring/Studio/Controls/ControlData.cpp @@ -0,0 +1,763 @@ +/**************************************************************************** +** +** 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 "ControlData.h" +#include "ControlGraph.h" +#include "Control.h" + +#include + +using namespace Q3DStudio::Control; +using Q3DStudio::CString; + +CControlData::CControlData(CControl &inControl) + : m_Control(&inControl) + , m_MinSize(0, 0) + , m_MaxSize(LONG_MAX, LONG_MAX) + , m_PrefSize(10, 10) + , m_IsMouseOver(false) + , m_IsInvalidated(true) + , m_IsChildInvalidated(false) + , m_IsVisible(true) + , m_IsEnabled(true) + , m_IsParentEnabled(true) + , m_HasFocus(false) + , m_IsMouseDown(false) + , m_ShowTooltips(false) + , m_NeedsLayout(true) + , m_ChildrenNeedLayout(true) + , m_WindowListener(NULL) +{ +} + +CControlData::~CControlData() +{ +} + +void CControlData::ReleaseControl() +{ + if (m_Control) { + ControlGraph::RemoveNode(*m_Control); + m_Control = nullptr; + } +} + +std::shared_ptr CControlData::CreateControlData(CControl &inControl) +{ + std::shared_ptr retval = + std::make_shared(std::ref(inControl)); + ControlGraph::AddNode(retval); + return retval; +} + +CControl *CControlData::GetControl() +{ + return m_Control; +} + +CControl *CControlData::GetParent() +{ + + if (m_Control) { + std::shared_ptr theParent(ControlGraph::GetParent(*m_Control)); + if (theParent) + return theParent->GetControl(); + } + return nullptr; +} + +void CControlData::OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation) +{ + if (m_Control) + m_Control->OnDraw(inRenderer, inDirtyRect, inIgnoreValidation); +} + +void CControlData::Draw(CRenderer *inRenderer) +{ + if (m_Control) + m_Control->Draw(inRenderer); +} + +void CControlData::NotifyNotInClipRect() +{ + if (m_Control) + m_Control->NotifyNotInClipRect(); +} + +CPt CControlData::GetPosition() const +{ + if (m_Control) + return m_Control->GetPosition(); + return CPt(); +} +void CControlData::SetPosition(CPt inPosition) +{ + if (m_Control) + m_Control->SetPosition(inPosition); +} +void CControlData::SetPosition(long inX, long inY) +{ + SetPosition(CPt(inX, inY)); +} + +CPt CControlData::GetSize() const +{ + if (m_Control) + return m_Control->GetSize(); + return CPt(); +} +void CControlData::SetSize(CPt inSize) +{ + if (m_Control) + m_Control->SetSize(inSize); +} +void CControlData::SetSize(long inWidth, long inHeight) +{ + SetSize(CPt(inWidth, inHeight)); +} + +CPt CControlData::GetMinimumSize() +{ + if (m_Control) + return m_Control->GetMinimumSize(); + return CPt(); +} +void CControlData::SetMinimumSize(CPt inSize) +{ + if (m_Control) + m_Control->SetMinimumSize(inSize); +} + +CPt CControlData::GetMaximumSize() +{ + if (m_Control) + return m_Control->GetMaximumSize(); + return CPt(); +} +void CControlData::SetMaximumSize(CPt inSize) +{ + if (m_Control) + m_Control->SetMaximumSize(inSize); +} + +CPt CControlData::GetPreferredSize() +{ + if (m_Control) + return m_Control->GetPreferredSize(); + return CPt(); +} +void CControlData::SetPreferredSize(CPt inSize) +{ + if (m_Control) + return m_Control->SetPreferredSize(inSize); +} + +void CControlData::SetAbsoluteSize(CPt inSize) +{ + if (m_Control) + m_Control->SetAbsoluteSize(inSize); +} +void CControlData::SetMouseDown(bool inMouseDown) +{ + m_IsMouseDown = inMouseDown; +} + +void CControlData::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + m_Control->OnMouseMove(inPoint, inFlags); +} +void CControlData::OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + m_Control->OnMouseOver(inPoint, inFlags); +} +void CControlData::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + m_Control->OnMouseOut(inPoint, inFlags); +} +bool CControlData::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + return m_Control->OnMouseDown(inPoint, inFlags); + return false; +} +bool CControlData::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + return m_Control->OnMouseRDown(inPoint, inFlags); + return false; +} +void CControlData::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + m_Control->OnMouseUp(inPoint, inFlags); +} +void CControlData::OnMouseRUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + m_Control->OnMouseRUp(inPoint, inFlags); +} +void CControlData::OnMouseClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + m_Control->OnMouseClick(inPoint, inFlags); +} +bool CControlData::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + return m_Control->OnMouseDoubleClick(inPoint, inFlags); + return false; +} +bool CControlData::OnMouseHover(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + return m_Control->OnMouseHover(inPoint, inFlags); + return false; +} +bool CControlData::OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + return m_Control->OnMouseWheel(inPoint, inAmount, inFlags); + return false; +} +bool CControlData::OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + return m_Control->OnKeyDown(inChar, inFlags); + return false; +} +bool CControlData::OnKeyUp(unsigned int inChar, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + return m_Control->OnKeyUp(inChar, inFlags); + return false; +} +bool CControlData::OnChar(const QString &inChar, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) + return m_Control->OnChar(inChar, inFlags); + return false; +} +void CControlData::OnLoseFocus() +{ + if (m_Control) { + m_Control->OnLoseFocus(); + } +} +void CControlData::OnGainFocus() +{ + if (m_Control) { + m_Control->OnGainFocus(); + } +} +bool CControlData::CanGainFocus() +{ + if (m_Control) { + return m_Control->CanGainFocus(); + } + return false; +} +bool CControlData::IsInFocus() +{ + if (m_Control) { + return m_Control->IsInFocus(); + } + return false; +} +void CControlData::OnTab() +{ + if (m_Control) { + m_Control->OnTab(); + } +} +void CControlData::OnReverseTab() +{ + if (m_Control) { + m_Control->OnReverseTab(); + } +} +void CControlData::SetFocusToFirstAvailable() +{ + if (m_Control) { + m_Control->SetFocusToFirstAvailable(); + } +} +void CControlData::SetFocusToLastAvailable() +{ + if (m_Control) { + m_Control->SetFocusToLastAvailable(); + } +} +void CControlData::ChildrenChanged() +{ + if (m_Control) + m_Control->ChildrenChanged(); +} + +void CControlData::SetMouseWheelEnabled(bool inEnabled) +{ + if (m_Control == nullptr) + return; + + if (m_MouseWheelState.m_Enabled != inEnabled) { + m_MouseWheelState.m_Enabled = inEnabled; + ControlEventState::Enum theNewState; + if (m_MouseWheelState.m_Enabled == false) + theNewState = ControlEventState::Unknown; + else + theNewState = ControlEventState::Listening; + SetMouseWheelEventState(theNewState); + } +} + +void CControlData::OnHierarchyChanged() +{ + ControlEventState::Enum theNewState; + if (m_MouseWheelState.m_Enabled) + theNewState = ControlEventState::Listening; + else + theNewState = ControlEventState::Unknown; + SetMouseWheelEventState(theNewState); +} + +/** + Look at hierarchy information to figure out which events should + trickle down the tree to here (or deeper). Recursive call that + may take some time to complete. +*/ +void CControlData::UpdateMouseWheelEventState() +{ + if (m_Control == nullptr) + return; + ControlEventState::Enum theNewState(ControlEventState::Ignoring); + if (m_MouseWheelState.m_Enabled == true) + theNewState = ControlEventState::Listening; + else if (m_MouseWheelState.m_EventState == ControlEventState::Unknown && m_Control != nullptr) { + for (ControlGraph::SIterator theIter(ControlGraph::GetChildren(*m_Control)); + theIter.IsDone() == false; ++theIter) { + if (theIter->GetMouseWheelEventState() == ControlEventState::Listening) { + theNewState = ControlEventState::Listening; + break; + } + } + } + SetMouseWheelEventState(theNewState); +} + +/** + Update our mouse wheel state and notify our parent if necessary. Note that we + can't set our event state to ignoring without checking all of our children + so the result of this function is that our event state is either listening + or unknown. +*/ +void CControlData::SetMouseWheelEventState(ControlEventState::Enum inNewState) +{ + if (m_MouseWheelState.m_EventState != inNewState) { + m_MouseWheelState.m_EventState = inNewState; + std::shared_ptr theParent = ControlGraph::GetParent(*m_Control); + if (theParent) + theParent->ChildMouseWheelEventStateChanged(m_MouseWheelState.m_EventState); + } +} + +/** + When a given child notifies us that its event state has changed then we can update + our state. We can't set the state to ignoring unless we *know* all of our + children are ignoring mouse wheel. + */ +void CControlData::ChildMouseWheelEventStateChanged(ControlEventState::Enum inNewState) +{ + ControlEventState::Enum theNewState; + if (inNewState == ControlEventState::Listening || m_MouseWheelState.m_Enabled == true) + theNewState = ControlEventState::Listening; + else + theNewState = ControlEventState::Unknown; + + SetMouseWheelEventState(theNewState); +} + +ControlEventState::Enum CControlData::GetMouseWheelEventState() +{ + if (m_MouseWheelState.m_EventState == ControlEventState::Unknown) + UpdateMouseWheelEventState(); + assert(m_MouseWheelState.m_EventState != ControlEventState::Unknown); + return m_MouseWheelState.m_EventState; +} + +CDropTarget *CControlData::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags) +{ + if (m_Control) { + return m_Control->FindDropCandidate(inMousePoint, inFlags); + } + return nullptr; +} + +void CControlData::AddChild(CControl *inControl, CControl *inInsertBefore) +{ + if (m_Control) + m_Control->AddChild(inControl, inInsertBefore); +} + +void CControlData::RemoveChild(CControl *inControl) +{ + if (m_Control) + m_Control->RemoveChild(inControl); +} +void CControlData::RemoveAllChildren() +{ + if (m_Control) + m_Control->RemoveAllChildren(); +} +long CControlData::GetChildIndex(CControl *inChildControl) +{ + if (m_Control) + return m_Control->GetChildIndex(inChildControl); + return 0; +} +CControl *CControlData::FindChildByName(const Q3DStudio::CString &inName) +{ + if (m_Control) { + m_Control->FindChildByName(inName); + } + return nullptr; +} + +bool CControlData::IsMouseOver() const +{ + if (m_Control) { + return m_Control->IsMouseOver(); + } + return false; +} + +bool CControlData::HitTest(const CPt &inPoint) const +{ + if (m_Control) { + return m_Control->HitTest(inPoint); + } + return false; +} +bool CControlData::IsInRect(const CRct &inRect) const +{ + if (m_Control) { + return m_Control->IsInRect(inRect); + } + return false; +} + +void CControlData::Invalidate(bool inInvalidate) +{ + if (m_Control) { + m_Control->Invalidate(inInvalidate); + } +} +void CControlData::InvalidateRect(const CRct &inRect) +{ + if (m_Control) { + m_Control->InvalidateRect(inRect); + } +} +bool CControlData::IsInvalidated() const +{ + return m_IsInvalidated; +} + +void CControlData::OnChildInvalidated() +{ + if (m_Control) { + m_Control->OnChildInvalidated(); + } +} +bool CControlData::IsChildInvalidated() const +{ + if (m_Control) { + return m_Control->IsChildInvalidated(); + } + return false; +} + +void CControlData::SetVisible(bool inIsVisible) +{ + if (m_Control) { + m_Control->SetVisible(inIsVisible); + } +} +bool CControlData::IsVisible() const +{ + if (m_Control) { + return m_Control->IsVisible(); + } + return false; +} +void CControlData::OnVisibleStateChange(bool inIsVisible) +{ + if (m_Control) { + m_Control->OnVisibleStateChange(inIsVisible); + } +} +void CControlData::OnParentVisibleStateChanged(bool inIsVisible) +{ + if (m_Control) { + m_Control->OnParentVisibleStateChanged(inIsVisible); + } +} + +void CControlData::SetParentEnabled(bool inParentEnabled) +{ + if (m_Control) { + m_Control->SetParentEnabled(inParentEnabled); + } +} +void CControlData::SetEnabled(bool inIsEnabled) +{ + if (m_Control) { + m_Control->SetEnabled(inIsEnabled); + } +} + +bool CControlData::IsEnabled() const +{ + return m_IsEnabled && m_IsParentEnabled; +} +bool CControlData::GetEnabledFlag() +{ + return m_IsEnabled; +} +void CControlData::SetEnabledFlag(bool inIsEnabled) +{ + m_IsEnabled = inIsEnabled; +} + +void CControlData::SetWindowListener(CControlWindowListener *inListener) +{ + m_WindowListener = inListener; +} +CControlWindowListener *CControlData::GetWindowListener() +{ + return m_WindowListener; +} + +void CControlData::OnChildSizeChanged(CControl *inChild) +{ + if (m_Control) { + m_Control->OnChildSizeChanged(inChild); + } +} +void CControlData::ResetMinMaxPref() +{ + if (m_Control) { + m_Control->ResetMinMaxPref(); + } +} + +void CControlData::SetName(CString inName) +{ + m_ControlName = inName; +} +CString CControlData::GetName() +{ + return m_ControlName; +} + +void CControlData::BeginDrawChildren(CRenderer *inRenderer) +{ + if (m_Control) { + m_Control->BeginDrawChildren(inRenderer); + } +} + +long CControlData::DoPopup(QMenu *inContextMenu, CPt inPoint) +{ + if (m_Control) { + return m_Control->DoPopup(inContextMenu, inPoint); + } + return 0; +} +void CControlData::RemoveUberControl(CControl *inControl) +{ + if (m_Control) { + m_Control->RemoveUberControl(inControl); + } +} +void CControlData::OffsetPosition(CPt inOffset) +{ + if (m_Control) { + m_Control->OffsetPosition(inOffset); + } +} + +CPt CControlData::GetGlobalPosition(CPt inChildPoint) const +{ + if (m_Control) { + return m_Control->GetGlobalPosition(inChildPoint); + } + return CPt(); +} +UICRenderDevice CControlData::GetPlatformDevice() +{ + if (m_Control) { + return m_Control->GetPlatformDevice(); + } + return nullptr; +} +bool CControlData::IsChildPlatformDevice(UICRenderDevice inDevice) +{ + if (m_Control) { + return m_Control->IsChildPlatformDevice(inDevice); + } + return false; +} +void CControlData::ShowMoveableWindow(CPt inLocation, Q3DStudio::CString inText, CRct inBoundingRct) +{ + if (m_Control) { + m_Control->ShowMoveableWindow(inLocation, inText, inBoundingRct); + } +} +void CControlData::HideMoveableWindow() +{ + if (m_Control) { + m_Control->HideMoveableWindow(); + } +} +CControl *CControlData::GetFirstChild() +{ + if (m_Control) { + m_Control->GetFirstChild(); + } + return nullptr; +} +bool CControlData::HasFocus(CControl *inControl) +{ + if (m_Control) { + return m_Control->HasFocus(inControl); + } + return false; +} +void CControlData::GrabFocus(CControl *inControl) +{ + if (m_Control) { + m_Control->GrabFocus(inControl); + } +} + +CPt CControlData::ClientToScreen(CPt inPoint) +{ + if (m_Control) { + return m_Control->ClientToScreen(inPoint); + } + return CPt(); +} +CPt CControlData::ScreenToClient(CPt inPoint) +{ + if (m_Control) { + return m_Control->ScreenToClient(inPoint); + } + return CPt(); +} + +void CControlData::AddFocusListener(CChildFocusListener *inListener) +{ + if (m_Control) { + m_Control->AddFocusListener(inListener); + } +} +void CControlData::RemoveFocusListener(CChildFocusListener *inListener) +{ + if (m_Control) { + m_Control->RemoveFocusListener(inListener); + } +} +void CControlData::FireFocusEvent(bool inStatus) +{ + if (m_Control) { + m_Control->FireFocusEvent(inStatus); + } +} + +void CControlData::SetTooltipText(const Q3DStudio::CString &inText) +{ + m_TooltipText = inText; +} +CString CControlData::GetTooltipText() +{ + return m_TooltipText; +} + +void CControlData::EnsureVisible(CRct inRect) +{ + if (m_Control) { + m_Control->EnsureVisible(inRect); + } +} +void CControlData::EnsureVisible() +{ + if (m_Control) { + m_Control->EnsureVisible(); + } +} + +void CControlData::OnParentChanged(CControl *inControl) +{ + if (m_Control) + m_Control->OnParentChanged(inControl); +} + +void CControlData::NotifyParentNeedsLayout() +{ + if (m_Control) + m_Control->NotifyParentNeedsLayout(); +} +void CControlData::MarkChildrenNeedLayout() +{ + if (m_Control) + m_Control->MarkChildrenNeedLayout(); +} +void CControlData::MarkNeedsLayout() +{ + if (m_Control) + m_Control->MarkNeedsLayout(); +} +// Tell this control that one of its children need to be layed out. +void CControlData::SetLayout(CPt inSize, CPt inPosition) +{ + if (m_Control) + m_Control->SetLayout(inSize, inPosition); +} +void CControlData::LayoutChildren() +{ + if (m_Control) + m_Control->LayoutChildren(); +} +void CControlData::EnsureLayout() +{ + if (m_Control) + m_Control->EnsureLayout(); +} diff --git a/src/Authoring/Studio/Controls/ControlData.h b/src/Authoring/Studio/Controls/ControlData.h new file mode 100644 index 00000000..83ebaf7d --- /dev/null +++ b/src/Authoring/Studio/Controls/ControlData.h @@ -0,0 +1,276 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ +#pragma once +#ifndef CONTROLDATAH +#define CONTROLDATAH + +#include "DropTarget.h" +#include "Pt.h" +#include "Rct.h" +#include "Multicaster.h" +#include "UICString.h" + +class CControl; +class CControlWindowListener; +class CChildFocusListener; +class CRenderer; + +class QMenu; + +namespace Q3DStudio { +namespace Control { + + using namespace std; + + struct ControlEventState + { + enum Enum { + Unknown = 0, + Listening, + Ignoring, + }; + }; + + struct SControlEventData + { + bool m_Enabled; + ControlEventState::Enum m_EventState; + SControlEventData() + : m_Enabled(false) + , m_EventState(ControlEventState::Ignoring) + { + } + }; + + // Smart pointer object that referees access to a control. + class CControlData + { + Q_DISABLE_COPY(CControlData) + public: + friend class ::CControl; + friend class std::shared_ptr; + + private: + // The physical address of the control is the key in the graph + // that points to this data item. + CControl *m_Control; + + CPt m_Size; ///< Current size of this control + + CPt m_Position; ///< Position of this control, relative to the parent + CPt m_MinSize; ///< Minimum allowed size of this control + CPt m_MaxSize; ///< Maximum allowed size of this contrl + CPt m_PrefSize; ///< Preferred size of this control + + bool m_IsMouseOver; ///< True if the mouse is over this control + bool m_IsInvalidated; ///< True if this control needs to be redrawn + bool m_IsChildInvalidated; ///< True if a child of this control is invalidated. + bool m_IsVisible; ///< True if this control is to be visible + bool m_IsEnabled; ///< True if this control is enabled. + bool m_IsParentEnabled; + bool m_HasFocus; + bool m_IsMouseDown; + bool m_ShowTooltips; ///< Specifies whether or not tooltips should be shown + bool m_NeedsLayout; ///< True if this control needs to be layed out. + bool m_ChildrenNeedLayout; ///< True if my children need layout + SControlEventData + m_MouseWheelState; ///< Tracks whether this object cares about mouse wheel. + + Q3DStudio::CString m_TooltipText; ///< Text to be displayed for tooltips + + std::shared_ptr m_Focus; ///< Child control that has the focus. + std::shared_ptr m_MouseFocus; ///< Child control that got the mouse down. + CControlWindowListener + *m_WindowListener; ///< External listener for when this control is invalidated. + + Q3DStudio::CString m_ControlName; + CMulticaster m_FocusListeners; ///< Used for focus changes + + public: + CControlData(CControl &inControl); + ~CControlData(); + + CControl *GetControl(); + + CControl *GetParent(); + + void OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation = false); + void Draw(CRenderer *inRenderer); + void NotifyNotInClipRect(); + + CPt GetPosition() const; + void SetPosition(CPt inPosition); + void SetPosition(long inX, long inY); + + CPt GetSize() const; + void SetSize(CPt inSize); + void SetSize(long inWidth, long inHeight); + + CPt GetMinimumSize(); + void SetMinimumSize(CPt inSize); + + CPt GetMaximumSize(); + void SetMaximumSize(CPt inSize); + + CPt GetPreferredSize(); + void SetPreferredSize(CPt inSize); + + void SetAbsoluteSize(CPt inSize); + + void SetMouseDown(bool inMouseDown); + void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags); + void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags); + void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags); + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags); + bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags); + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags); + void OnMouseRUp(CPt inPoint, Qt::KeyboardModifiers inFlags); + void OnMouseClick(CPt inPoint, Qt::KeyboardModifiers inFlags); + bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags); + bool OnMouseHover(CPt inPoint, Qt::KeyboardModifiers inFlags); + bool OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags); + bool OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inFlags); + bool OnKeyUp(unsigned int inChar, Qt::KeyboardModifiers inFlags); + bool OnChar(const QString &inChar, Qt::KeyboardModifiers inFlags); + void OnLoseFocus(); + void OnGainFocus(); + bool CanGainFocus(); + bool IsInFocus(); + void OnTab(); + void OnReverseTab(); + void SetFocusToFirstAvailable(); + void SetFocusToLastAvailable(); + void ChildrenChanged(); + + // Mouse wheel event state. + void SetMouseWheelEnabled(bool inEnabled); + /** + Callback so we can update any event states to unknown + from ignoring forcing a refresh of hierarchy event information + the next time the event state is queried. + */ + void OnHierarchyChanged(); + /** + If our event state is unknown, force resolution by asking children what their + event state is. Else return our event state. + */ + ControlEventState::Enum GetMouseWheelEventState(); + + protected: + void UpdateMouseWheelEventState(); + void ChildMouseWheelEventStateChanged(ControlEventState::Enum inNewState); + void SetMouseWheelEventState(ControlEventState::Enum inNewState); + + public: + CDropTarget *FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags); + + void AddChild(CControl *inControl, CControl *inInsertBefore = NULL); + void RemoveChild(CControl *inControl); + void RemoveAllChildren(); + long GetChildIndex(CControl *inChildControl); + CControl *FindChildByName(const Q3DStudio::CString &inName); + + bool IsMouseOver() const; + + bool HitTest(const CPt &inPoint) const; + bool IsInRect(const CRct &inRect) const; + + void Invalidate(bool inInvalidate = true); + void InvalidateRect(const CRct &inRect); + bool IsInvalidated() const; + + void OnChildInvalidated(); + bool IsChildInvalidated() const; + + void SetVisible(bool inIsVisible); + bool IsVisible() const; + void OnVisibleStateChange(bool inIsVisible); + void OnParentVisibleStateChanged(bool inIsVisible); + + void SetParentEnabled(bool inParentEnabled); + void SetEnabled(bool inIsEnabled); + bool IsEnabled() const; + bool GetEnabledFlag(); + void SetEnabledFlag(bool inIsEnabled); + + void SetWindowListener(CControlWindowListener *inListener); + CControlWindowListener *GetWindowListener(); + + void OnChildSizeChanged(CControl *inChild); + void ResetMinMaxPref(); + + void SetName(Q3DStudio::CString inName); + Q3DStudio::CString GetName(); + + void BeginDrawChildren(CRenderer *inRenderer); + + long DoPopup(QMenu *inContextMenu, CPt inPoint); + void RemoveUberControl(CControl *inControl); + void OffsetPosition(CPt inOffset); + + CPt GetGlobalPosition(CPt inChildPoint) const; + UICRenderDevice GetPlatformDevice(); + bool IsChildPlatformDevice(UICRenderDevice inDevice); + void ShowMoveableWindow(CPt inLocation, Q3DStudio::CString inText, CRct inBoundingRct); + void HideMoveableWindow(); + CControl *GetFirstChild(); + bool HasFocus(CControl *inControl); + void GrabFocus(CControl *inControl); + + CPt ClientToScreen(CPt inPoint); + CPt ScreenToClient(CPt inPoint); + + void AddFocusListener(CChildFocusListener *inListener); + void RemoveFocusListener(CChildFocusListener *inListener); + void FireFocusEvent(bool inStatus); + + void SetTooltipText(const Q3DStudio::CString &inText); + Q3DStudio::CString GetTooltipText(); + + void EnsureVisible(CRct inRect); + void EnsureVisible(); + + void OnParentChanged(CControl *inControl); + + void NotifyParentNeedsLayout(); + void MarkChildrenNeedLayout(); + void MarkNeedsLayout(); + // Tell this control that one of its children need to be layed out. + void SetLayout(CPt inSize, CPt inPosition); + void LayoutChildren(); + void EnsureLayout(); + + private: + static std::shared_ptr CreateControlData(CControl &inControl); + void ReleaseControl(); // set the control to null, remove our graph representation + }; +} +} + +#endif diff --git a/src/Authoring/Studio/Controls/ControlGraph.cpp b/src/Authoring/Studio/Controls/ControlGraph.cpp new file mode 100644 index 00000000..912bd1a0 --- /dev/null +++ b/src/Authoring/Studio/Controls/ControlGraph.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** 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 "ControlGraph.h" +#include "GraphImpl.h" +#include "foundation/Qt3DSAssert.h" +#include "Control.h" +#include "ControlData.h" + +using namespace std; +using namespace Q3DStudio; +using namespace Q3DStudio::Graph; +using namespace Q3DStudio::Control; +using Q3DStudio::CString; + +namespace { +typedef SGraphImpl> TGraphType; + +TGraphType g_ControlGraph; +} + +namespace Q3DStudio { +namespace Control { + namespace ControlGraph { + + void AddNode(std::shared_ptr inData) + { + g_ControlGraph.AddRoot(inData->GetControl()); + g_ControlGraph.SetData(inData->GetControl(), inData); + } + + void RemoveNode(CControl &inData) { g_ControlGraph.RemoveChild(&inData, true); } + + void AddChild(CControl &inParent, CControl &inChild, CControl *inNextSibling) + { + std::shared_ptr oldParent = GetParent(inChild); + TGraphType::TNodePtr theParent(g_ControlGraph.GetImpl(&inParent)); + + // It actually happens that sometimes inChild gets added with a sibling + // but the sibling hasn't actually been added yet. + if (inNextSibling != nullptr) { + TGraphType::TNodePtr theSibling(g_ControlGraph.GetImpl(inNextSibling)); + if (theSibling->m_Parent == theParent) + g_ControlGraph.MoveBefore(&inChild, inNextSibling); + else + g_ControlGraph.AddChild(&inParent, &inChild, SGraphPosition::SEnd()); + } else + g_ControlGraph.AddChild(&inParent, &inChild, SGraphPosition::SEnd()); + + if (!oldParent || oldParent->GetControl() != &inParent) { + inChild.OnParentChanged(&inParent); + if (oldParent) + oldParent->ChildrenChanged(); + } + inChild.Invalidate(); + inParent.ChildrenChanged(); + } + // inParent is supplied for error checking purposes. + void RemoveChild(CControl &inParent, CControl &inChild) + { + inChild.OnParentChanged(nullptr); + g_ControlGraph.RemoveChild(&inParent, &inChild, false); + inChild.Invalidate(); + inParent.ChildrenChanged(); + } + void RemoveAllChildren(CControl &inParent) + { + TGraphType::TNodePtr theNode(g_ControlGraph.GetImpl(&inParent)); + if (theNode == nullptr) + return; + while (theNode->m_Children.empty() == false) { + theNode->m_Children.back()->m_Data->OnParentChanged(nullptr); + theNode->m_Children.back()->m_Data->NotifyParentNeedsLayout(); + g_ControlGraph.RemoveChild(&inParent, theNode->m_Children.back()->m_GraphableID, + false); + } + inParent.ChildrenChanged(); + } + void MoveTo(CControl &inParent, CControl &inChild, const Graph::SGraphPosition &inPosition) + { + std::shared_ptr theOldParent(GetParent(inChild)); + g_ControlGraph.MoveTo(&inParent, &inChild, inPosition); + if (!theOldParent || theOldParent->GetControl() != &inParent) + inChild.OnParentChanged(&inParent); + inChild.NotifyParentNeedsLayout(); + inParent.MarkChildrenNeedLayout(); + if (theOldParent) { + theOldParent->ChildrenChanged(); + } + inParent.ChildrenChanged(); + inChild.Invalidate(); + } + long GetNumChildren(CControl &inControl) + { + return g_ControlGraph.GetChildCount(&inControl); + } + + long GetChildIndex(CControl &inParent, CControl &inChild) + { + QT3DS_ASSERT(GetParent(inChild)->GetControl() == &inParent); + + SGraphPosition thePos = g_ControlGraph.GetNodePosition(&inChild); + return thePos.GetIndex(); + } + + std::shared_ptr GetChild(CControl &inParent, long inIndex) + { + TGraphType::TNodePtr theNode(g_ControlGraph.GetImpl(&inParent)); + if (theNode && inIndex < (long)theNode->m_Children.size() && inIndex > -1) + return theNode->m_Children[inIndex]->m_Data; + return std::shared_ptr(); + } + + std::shared_ptr GetParent(CControl &inControl) + { + TGraphType::TNodePtr theNode(g_ControlGraph.GetImpl(&inControl)); + if (theNode && theNode->m_Parent) + return theNode->m_Parent->m_Data; + return std::shared_ptr(); + } + + // Dummy struct to hide graph implementation + struct SDummyGraphNode : public TGraphType::TNodeType + { + SDummyGraphNode(CControl *const &inIdentifier, + const std::shared_ptr &inNodeData = + std::shared_ptr()) + : TGraphType::TNodeType(inIdentifier, inNodeData) + { + } + }; + + std::shared_ptr SIteratorBase::GetCurrent() + { + if (m_Children && m_Index < (long)m_Children->size()) + return (*m_Children)[m_Index]->m_Data; + + QT3DS_ASSERT(false); + return std::shared_ptr(); + } + + SReverseIterator GetRChildren(CControl &inControl) + { + TGraphType::TNodePtr theNode(g_ControlGraph.GetImpl(&inControl)); + if (theNode) + return SReverseIterator( + theNode->m_Data, + reinterpret_cast &>(theNode->m_Children)); + return SReverseIterator(); + } + + SIterator GetChildren(CControl &inControl) + { + TGraphType::TNodePtr theNode(g_ControlGraph.GetImpl(&inControl)); + if (theNode) + return SIterator(theNode->m_Data, reinterpret_cast &>( + theNode->m_Children)); + return SIterator(); + } + } +} +} diff --git a/src/Authoring/Studio/Controls/ControlGraph.h b/src/Authoring/Studio/Controls/ControlGraph.h new file mode 100644 index 00000000..0dfe2b30 --- /dev/null +++ b/src/Authoring/Studio/Controls/ControlGraph.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ +#pragma once +#ifndef CONTROLGRAPHH +#define CONTROLGRAPHH +#include "Multicaster.h" +#include "ControlGraphIterators.h" + +class CControl; +class CControlWindowListener; +class CChildFocusListener; +class CRenderer; + +namespace Q3DStudio { +namespace Graph { + + struct SGraphPosition; // GraphPosition.h" +} + +namespace Control { + class ControlData; + + namespace ControlGraph { + void AddNode(std::shared_ptr inData); + void RemoveNode(CControl &inData); + void AddChild(CControl &inParent, CControl &inChild, CControl *inNextSibling); + // inParent is supplied for error checking purposes. + void RemoveChild(CControl &inParent, CControl &inChild); + void RemoveAllChildren(CControl &inParent); + void MoveTo(CControl &inParent, CControl &inChild, const Graph::SGraphPosition &inPosition); + long GetNumChildren(CControl &inControl); + long GetChildIndex(CControl &inParent, CControl &inChild); + std::shared_ptr GetChild(CControl &inParent, long inIndex); + std::shared_ptr GetParent(CControl &inControl); + + SReverseIterator GetRChildren(CControl &inControl); + SIterator GetChildren(CControl &inControl); + }; +} +} + +#endif diff --git a/src/Authoring/Studio/Controls/ControlGraphIterators.h b/src/Authoring/Studio/Controls/ControlGraphIterators.h new file mode 100644 index 00000000..ae2ffcf6 --- /dev/null +++ b/src/Authoring/Studio/Controls/ControlGraphIterators.h @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ +#pragma once +#ifndef CONTROLGRAPHITERATORSH +#define CONTROLGRAPHITERATORSH +#include + +namespace Q3DStudio { +namespace Control { + class CControlData; + using std::vector; + + namespace ControlGraph { + struct SDummyGraphNode; + + struct SIteratorBase + { + protected: + std::shared_ptr m_ControlData; + vector *m_Children; + long m_Index; + + public: + SIteratorBase() + : m_Children(nullptr) + , m_Index(0) + { + } + + SIteratorBase(std::shared_ptr data, + vector &inChildren) + : m_ControlData(data) + , m_Children(&inChildren) + , m_Index(0) + { + } + + SIteratorBase(const SIteratorBase &inOther) + : m_ControlData(inOther.m_ControlData) + , m_Children(inOther.m_Children) + , m_Index(inOther.m_Index) + { + } + + SIteratorBase &operator=(const SIteratorBase &inOther) + { + if (this != &inOther) { + m_ControlData = inOther.m_ControlData; + m_Children = inOther.m_Children; + m_Index = inOther.m_Index; + } + return *this; + } + + bool operator==(const SIteratorBase &other) { return m_Index == other.m_Index; } + bool operator!=(const SIteratorBase &other) { return m_Index != other.m_Index; } + + std::shared_ptr GetCurrent(); + + std::shared_ptr operator->() { return GetCurrent(); } + std::shared_ptr operator*() { return GetCurrent(); } + }; + + struct SReverseIterator : SIteratorBase + { + SReverseIterator() {} + SReverseIterator(std::shared_ptr data, + vector &inChildren) + : SIteratorBase(data, inChildren) + { + m_Index = (long)inChildren.size() - 1; + } + SReverseIterator(const SReverseIterator &inOther) + : SIteratorBase(inOther) + { + } + SReverseIterator &operator=(const SReverseIterator &inOther) + { + SIteratorBase::operator=(inOther); + return *this; + } + + bool IsDone() { return m_Children == nullptr || m_Index < 0; } + bool HasNext() { return m_Children && m_Index > -1; } + SReverseIterator &operator++() + { + --m_Index; + return *this; + } + SReverseIterator &operator+=(long inAmount) + { + m_Index -= inAmount; + return *this; + } + }; + + struct SIterator : SIteratorBase + { + SIterator() {} + SIterator(std::shared_ptr data, vector &inChildren) + : SIteratorBase(data, inChildren) + { + } + SIterator(const SReverseIterator &inOther) + : SIteratorBase(inOther) + { + } + SIterator &operator=(const SIterator &inOther) + { + SIteratorBase::operator=(inOther); + return *this; + } + + bool IsDone() { return m_Children == nullptr || m_Index >= (long)m_Children->size(); } + bool HasNext() { return m_Children && m_Index < (long)m_Children->size(); } + SIterator operator++() + { + ++m_Index; + return *this; + } + SIterator &operator+=(long inAmount) + { + m_Index += inAmount; + return *this; + } + }; + } +} +} +#endif \ No newline at end of file diff --git a/src/Authoring/Studio/Controls/EditInPlace.h b/src/Authoring/Studio/Controls/EditInPlace.h new file mode 100644 index 00000000..f4497210 --- /dev/null +++ b/src/Authoring/Studio/Controls/EditInPlace.h @@ -0,0 +1,280 @@ +/**************************************************************************** +** +** Copyright (C) 2002 Anark Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_EDIT_IN_PLACE_H +#define INCLUDED_EDIT_IN_PLACE_H 1 + +#pragma once + +#include "Renderer.h" +#include "Pt.h" +#include "StudioPreferences.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; + +template +class CEditInPlace : public T +{ +public: + CEditInPlace(); + virtual ~CEditInPlace(); + + 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 OnLoseFocus() override; + void OnGainFocus() override; + void Draw(CRenderer *inRenderer) override; + void SetEditable(bool inIsEditable); + void SetEditMode(bool inEditMode); + void EnterText(bool inHighlight) override; + void Invalidate(bool inInvalidate = true) override; + bool GetEditMode(); + static long GetRightBuffer(); + +protected: + bool m_IsInEditMode; ///< If in edit mode, the user is currently editing the control + bool m_IsEditable; ///< Can only enter edit mode when the control is editable + +private: + static const long s_RightBuffer = 6; +}; + +template +CEditInPlace::CEditInPlace() + : T() + , m_IsInEditMode(false) + , m_IsEditable(true) +{ + T::SetReadOnly(true); + T::SetFillBackground(false); +} + +template +CEditInPlace::~CEditInPlace() +{ +} + +//============================================================================== +/** + * Handles the mouse double-click event. Enters the text into edit mode so that + * the user can change its value. + * @param inPoint location of the mouse + * @param inFlags modifier flags for the mouse + * @return true if this message should not be passed to any other children, otherwise false + */ +template +bool CEditInPlace::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_IsEditable && CStudioPreferences::IsSudoMode()) { + SetEditMode(true); + this->SetSelection(0, T::GetString().Length()); + return true; + } + return T::OnMouseDoubleClick(inPoint, inFlags); +} + +template +bool CEditInPlace::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (T::GetParent()->HasFocus(this) && !(inFlags & CHotKeys::MOUSE_RBUTTON)) + SetEditMode(true); + return T::OnMouseDown(inPoint, inFlags); +} + +//============================================================================== +/** + * Called when this control loses focus. Turns off edit mode and redraws the + * control. + */ +template +void CEditInPlace::OnLoseFocus() +{ + T::OnLoseFocus(); + SetEditMode(false); + Invalidate(); +} + +//============================================================================== +/** + * Handles most of the drawing, with some help from the parent class. + * @param inRenderer Renderer to draw to + */ +template +void CEditInPlace::Draw(CRenderer *inRenderer) +{ + CRct theRect = CRct(T::GetSize()); // CRct( CPt( 0, 0 ), CPt( CalculateCharWidths( inRenderer ) + + // s_RightBuffer, GetSize( ).y ) ); + CColor theOutlineColor = CColor(0, 0, 0); + + T::SetAbsoluteSize(theRect.size); + + bool theFillFlag = T::m_FillBackground; + + if (theFillFlag && !m_IsInEditMode) { + T::SetFillBackground(false); + inRenderer->FillSolidRect(theRect, T::m_BackgroundColorNoFocus); + } + + if (m_IsInEditMode) + T::SetTextColor(CColor(0, 0, 0)); + + inRenderer->PushClippingRect(theRect); + T::Draw(inRenderer); + inRenderer->PopClippingRect(); + + if (!m_IsInEditMode) + T::SetFillBackground(theFillFlag); + + if (m_IsInEditMode) + inRenderer->DrawRectOutline(theRect, theOutlineColor, theOutlineColor, theOutlineColor, + theOutlineColor); +} + +//============================================================================== +/** + * Enables or disables this control from being able to enter "Edit Mode" when + * SetEditMode() is called. + * @param inIsEditable true if you want the control to be editable when double-clicked, otherwise + * false + */ +template +void CEditInPlace::SetEditable(bool inIsEditable) +{ + m_IsEditable = inIsEditable; + + if (!m_IsEditable && m_IsInEditMode) + SetEditMode(false); +} + +//============================================================================== +/** + * Starts or stops "Edit Mode". While in Edit Mode, the user can change the + * text, move the caret, and highlight the text. An edit box is also drawn + * around the text. + * @param inEditMode true to turn on Edit Mode, false to turn off Edit Mode + */ +template +void CEditInPlace::SetEditMode(bool inEditMode) +{ + if (m_IsEditable) { + m_IsInEditMode = inEditMode; + T::SetFillBackground(!m_IsInEditMode); + T::SetReadOnly(!m_IsInEditMode); + if (!m_IsInEditMode) + T::FireCommitEvent(); + } +} + +//============================================================================== +/** + * Overriden from the parent to cause this control to lose focus when the Enter + * button is pressed on the keyboard. + * @param inHighlight true to highlight all of the text, false to just change the string + */ +template +void CEditInPlace::EnterText(bool inHighlight) +{ + T::EnterText(inHighlight); + OnLoseFocus(); +} + +//============================================================================== +/** + * Overriden to also invalidate/validate the parent. + * @param inInvalidate true to invalidate this control and the parent control + */ +/* +template +void CEditInPlace::Invalidate( bool inInvalidate ) +{ + if ( inInvalidate && GetParent() ) + GetParent()->Invalidate( inInvalidate ); + + CControl::Invalidate( inInvalidate ); +}*/ + +//============================================================================== +/** + * Override to avoid selecting all the text unless in edit mode. + */ +template +void CEditInPlace::OnGainFocus() +{ + if (m_IsInEditMode && m_IsEditable) + T::OnGainFocus(); +} + +template +bool CEditInPlace::GetEditMode() +{ + return m_IsInEditMode; +} + +template +long CEditInPlace::GetRightBuffer() +{ + return s_RightBuffer; +} + +template +bool CEditInPlace::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers) +{ + bool theReturn = false; + + if (m_IsInEditMode) { + T::DisplayContextMenu(inPoint); + theReturn = true; + } + + return theReturn; +} + +//============================================================================== +/** + * Overriden to also invalidate/validate the parent. + * @param inInvalidate true to invalidate this control and the parent control + */ +template +void CEditInPlace::Invalidate(bool inInvalidate) +{ + if (inInvalidate && T::GetParent()) + T::GetParent()->Invalidate(inInvalidate); + + T::Invalidate(inInvalidate); +} + +#endif // INCLUDED_EDIT_IN_PLACE_H diff --git a/src/Authoring/Studio/Controls/FloatEdit.cpp b/src/Authoring/Studio/Controls/FloatEdit.cpp new file mode 100644 index 00000000..e3dc9c2f --- /dev/null +++ b/src/Authoring/Studio/Controls/FloatEdit.cpp @@ -0,0 +1,524 @@ +/**************************************************************************** +** +** 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 "StringTokenizer.h" +#include "StringLoader.h" +//============================================================================== +// Include +//============================================================================== +#include "FloatEdit.h" +#include "MouseCursor.h" +#include "ResourceCache.h" +#include "StudioClipboard.h" +#include "ControlData.h" +#include "UICMath.h" + +#include +// using namespace Q3DStudio; <-- Do not do this here because it will conflict with CList and make +// the template generator go blah + +//============================================================================== +/** + * Constructor + */ +CFloatEdit::CFloatEdit() + : m_NumDecimalPlaces(3) + , m_FixedPlaces(-1) + , m_IsMouseDown(false) + , m_Min(-FLT_MAX) + , m_Max(FLT_MAX) + , m_EditMode(false) + , m_RevertListener(NULL) +{ + m_ControlData->SetMouseWheelEnabled(true); + // Set the default string + SetData(0.0f, false); + + SetReadOnly(true); + SetName("FloatEdit"); + + // TODO: Used only for timeline palette timebar. It is not editable, we do not need + // to register any events. Registering minus here will prevent it from working for zooming + // out in the timeline. + // TODO: This whole class will most likely be removed when timeline is converted to Qt. +// m_CommandHandler.RegisterKeyEvent( +// new CDynHotKeyConsumer(this, &CFloatEdit::AddCharNegative), 0, '-'); +// m_CommandHandler.RegisterKeyEvent( +// new CDynHotKeyConsumer(this, &CFloatEdit::AddCharPeriod), 0, '.'); +} + +//============================================================================== +/** + * Destructor + */ +CFloatEdit::~CFloatEdit() +{ +} + +void CFloatEdit::AddCharNegative() +{ + Q3DStudio::CString theMinusString = ::LoadResourceString(IDS_CONTROLS_FLOAT_MINUS); + unsigned int theMinus = theMinusString[0]; + + InsertChar(theMinus); +} + +void CFloatEdit::AddCharPeriod() +{ + Q3DStudio::CString thePeriodString = ::LoadResourceString(IDS_CONTROLS_FLOAT_PERIOD); + unsigned int thePeriod = thePeriodString[0]; + + InsertChar(thePeriod); +} + +void CFloatEdit::FormatString() +{ + Q3DStudio::CString theFormatString; + if (m_FixedPlaces == -1) + theFormatString.Format(_UIC("%%.%df"), m_NumDecimalPlaces); + else + theFormatString.Format(_UIC("%%0%d.%df"), m_FixedPlaces, m_NumDecimalPlaces); + + m_ValueString.Format(theFormatString, m_Value); +} + +//============================================================================== +/** + * Converts the internal (float) data of this control into a string that can be + * displayed. The parent class (CTextEdit) calls this function when it needs + * to redraw the control and the text within it. + * + * @return the string to be displayed. + */ +Q3DStudio::CString CFloatEdit::GetString() +{ + return m_ValueString; +} + +//============================================================================== +/** + * Sets the internal data of this control the specified value and marks the + * control as dirty so that it gets redrawn during the next free cycle. + * + * @param inValue the new value for this control + * @param inFireEvent true to fire a property change event + */ +void CFloatEdit::SetData(float inValue, bool inFireEvent /* = true */) +{ + m_Value = inValue; + + FormatString(); + SetDisplayString(GetString(), inFireEvent); + if (inFireEvent) + SetDirty(true); +} + +//============================================================================== +/** + * Attempts to set the internal data of this control to the specified string. + * + * @param inData a string containing the new data + */ +void CFloatEdit::SetData(const Q3DStudio::CString &inData, bool inFireEvent /*= true*/) +{ + m_Value = static_cast(::atof(inData.GetCharStar())); + + FormatString(); + // The string needs to be set precisely here, otherwise + // we end up truncating - and . from the floats + SetDisplayString(inData, inFireEvent); + SetDirty(true); +} + +//============================================================================== +/** + * Determines if the specified character can be inserted into the string. This + * control only accepts numbers, decimals, and minus signs. Further, a minus + * sign may only be inserted at the front of the string if there is not already + * one in the string and a decimal may only be inserted if there is not one in + * the string already. + * + * @param inCheckString the string that is to be checked (in case a lenght requirement is exceeded) + * @param inChar the character that was pressed + * @param inPosition character index where we are attempting to insert inChar into inCheckString + * @return true if this control can accept the character into the string, otherwise false + */ +bool CFloatEdit::CanAcceptChar(const Q3DStudio::CString &inCheckString, unsigned int inChar, + unsigned int inPosition) +{ + bool theRetVal = false; + Q3DStudio::CString thePeriodString = ::LoadResourceString(IDS_CONTROLS_FLOAT_PERIOD); + Q3DStudio::CString theMinusString = ::LoadResourceString(IDS_CONTROLS_FLOAT_MINUS); + + unsigned int thePeriod = thePeriodString[0]; + unsigned int theMinus = theMinusString[0]; + + if ((CTextEdit::CanAcceptChar(inCheckString, inChar, inPosition) && inCheckString.Length() < 10) + || inChar == thePeriod || inChar == theMinus) { + if (inChar >= '0' && inChar <= '9') + theRetVal = true; + if (!theRetVal) { + if (thePeriod == inChar) { + if (inCheckString.Find(char(thePeriod)) == Q3DStudio::CString::ENDOFSTRING) + theRetVal = true; + else { + theRetVal = false; + } + } else if (theMinus == inChar) { + if ((inCheckString.Find(char(theMinus)) == Q3DStudio::CString::ENDOFSTRING) + && (inPosition == 0)) + theRetVal = true; + } + } + } + return theRetVal; +} + +bool CFloatEdit::HandleSpecialChar(unsigned int inChar, Qt::KeyboardModifiers inFlags) +{ + bool isLargeStep = inFlags & CHotKeys::MODIFIER_SHIFT ? true : false; + bool isSmallStep = inFlags & CHotKeys::MODIFIER_CONTROL ? true : false; + + bool wasHandled = false; + switch (inChar) { + case Qt::Key_Up: + if (isLargeStep) + SetFloatValue(m_Value + 10.0f); + else if (isSmallStep) + SetFloatValue(static_cast(m_Value + 0.1f)); + else + SetFloatValue(static_cast(m_Value + 1.0f)); + wasHandled = true; + break; + + case Qt::Key_Down: + if (isLargeStep) + SetFloatValue(static_cast(m_Value - 10.0f)); + else if (isSmallStep) + SetFloatValue(static_cast(m_Value - 0.1f)); + else + SetFloatValue(m_Value - 1.0f); + wasHandled = true; + break; + + case Qt::Key_Enter: + ExitEditMode(); + wasHandled = true; + CTextEdit::OnLoseFocus(); + break; + + case Qt::Key_Escape: + if (m_RevertListener) + m_RevertListener->OnDiscardChanges(this); + ExitEditMode(); + wasHandled = true; + CTextEdit::OnLoseFocus(); + break; + + /* + case CHotKeys::KEY_SUBTRACT: + case CHotKeys::KEY_SUBTRACT_OEM: + case CHotKeys::KEY_PERIOD_OEM: + wasHandled = true; + break; + */ + } + + if (!wasHandled) + wasHandled = CTextEdit::HandleSpecialChar(inChar, inFlags); + + return wasHandled; +} + +float CFloatEdit::GetData() +{ + return m_Value; +} + +float CFloatEdit::GetDisplayData() +{ + float theFloat = static_cast(::atof(GetDisplayString().GetCharStar())); + return theFloat; +} + +void CFloatEdit::OnLoseFocus() +{ + ExitEditMode(); + CTextEdit::OnLoseFocus(); +} + +void CFloatEdit::OnGainFocus() +{ + if (!m_IsMouseDown && IsEnabled()) + SetReadOnly(false); + CTextEdit::OnGainFocus(); +} + +bool CFloatEdit::CanGainFocus() +{ + return true; +} + +void CFloatEdit::ExitEditMode() +{ + m_EditMode = false; + SetReadOnly(true); +} + +void CFloatEdit::EnterEditMode() +{ + m_EditMode = true; + SetReadOnly(false); +} + +//============================================================================== +/** + * Handles the dynamic dragging of float values. + */ +void CFloatEdit::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_IsMouseDown && !m_EditMode) { + // If we haven't started handling selecting or dragging figure out which one to do + if (!m_Trapping) { + // If moved outside of the safety zone start dragging the value. + if (::labs(inPoint.y - m_MouseStartPos.y) > 2) { + m_Trapping = true; +// In Mac there's no infinite mouse, so don't hide it. + setCursorIfNotSet(CMouseCursor::CURSOR_BLANK); + } + } + // If in trapping mode then do the value drag processing. + if (m_Trapping) { + float theDiff = static_cast(m_MouseStartPos.y - inPoint.y); + + if (inFlags & CHotKeys::MODIFIER_CONTROL) + theDiff *= 0.1f; + else if (inFlags & CHotKeys::MODIFIER_SHIFT) + theDiff *= 10.0f; + + SetFloatValue(theDiff + m_StartDragVal); + + CPt theMouseLoc = CControl::ClientToScreen(m_MouseStartPos); + getCursor().setPos(theMouseLoc.x, theMouseLoc.y); + + m_StartDragVal = GetData(); + } + } else + CTextEdit::OnMouseMove(inPoint, inFlags); +} + +void CFloatEdit::SetFloatValue(float inValue) +{ + // If the min and max are both zero, special case, don't bother capping the value to the + // min/max. + if (m_Min != 0 || m_Max != 0) { + if (inValue > m_Max) + inValue = m_Max; + else if (inValue < m_Min) + inValue = m_Min; + } + + SetData(inValue); + ReloadData(); + Q3DStudio::CString theNewValue = GetString(); + SetData(theNewValue); +} + +//============================================================================== +/** + * Handler to start mouse dragging actions on this. + */ +bool CFloatEdit::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (IsEnabled()) { + if (!CControl::OnMouseDown(inPoint, inFlags)) { + if (m_EditMode) + CTextEdit::OnMouseDown(inPoint, inFlags); + + m_IsMouseDown = true; + m_Trapping = false; + m_StartDragVal = GetData(); + + m_MouseStartPos = inPoint; + } + } + + return true; +} + +//============================================================================== +/** + * Handler to finish the mouse dragging actions. + */ +void CFloatEdit::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_IsMouseDown && !m_Trapping && m_IsReadOnly) { + SetReadOnly(false); + SelectAllText(); + EnterEditMode(); + } + + CTextEdit::OnMouseUp(inPoint, inFlags); + + resetCursor(); + m_IsMouseDown = false; + + if (m_Trapping) + FireFocusEvent(true); +} + +//============================================================================== +/** + * Set the minimum value allowed in this edit field. + */ +void CFloatEdit::SetMin(float inMin) +{ + m_Min = inMin; +} + +//============================================================================== +/** + * Set the maximum value allowed in this field. + */ +void CFloatEdit::SetMax(float inMax) +{ + m_Max = inMax; +} + +//============================================================================== +/** + * Handle mouse wheel messages to allow scrolling of the values. + */ +bool CFloatEdit::OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inPoint); + bool theRet = false; + if (GetParent() && GetParent()->HasFocus(this)) { + float theDiff = 1.0f; + if (inFlags & CHotKeys::MODIFIER_CONTROL) + theDiff = 0.1f; + else if (inFlags & CHotKeys::MODIFIER_SHIFT) + theDiff = 10.0f; + + if (inAmount < 0) + theDiff *= -1.0f; + + SetFloatValue(GetData() + theDiff); + + theRet = true; + } + return theRet; +} + +//============================================================================== +/** + * Set the number of decimal places to be displayed in this. + */ +void CFloatEdit::SetNumDecimalPlaces(short inNumDecimalPlaces) +{ + m_NumDecimalPlaces = inNumDecimalPlaces; + FormatString(); +} + +//============================================================================== +/** + * Set the number of fill places before the start of the number to fill if the number + * is too short. This defaults to -1 which means none. + */ +void CFloatEdit::SetFixedPlaces(short inFixedPlaces) +{ + m_FixedPlaces = inFixedPlaces; +} + +//============================================================================== +/** + * Ensure that the text from clipboard can be pasted into this control + */ +bool CFloatEdit::CanPaste() +{ + bool theValid = false; + + const auto text = Q3DStudio::CString::fromQString(CStudioClipboard::GetTextFromClipboard()); + if (m_Caret.show) { + Q3DStudio::CString theNewString(m_DisplayString); + long theCaret = m_Caret.position; + + if (HasSelectedText()) { + theNewString.Delete(GetSelectionLeft(), GetSelectionRight() - GetSelectionLeft()); + theCaret = Q3DStudio::MIN(GetSelectionLeft(), GetSelectionRight()); + } + theNewString.Insert(theCaret, text); + theValid = Validate(theNewString); + } else { + theValid = Validate(text); + } + + return theValid; +} + +//============================================================================== +/** + * Returns true if the given string can be pasted into the control + */ +bool CFloatEdit::Validate(const Q3DStudio::CString &inString) +{ + Q3DStudio::CString theCheckString(""); + Q3DStudio::CString theTemp; + bool theRetVal = true; + long theIter; + + for (theIter = 0; theIter < inString.Length(); ++theIter) { + theTemp = inString.Extract(theIter, 1); + + if (!CanAcceptChar(theCheckString, theTemp[0], theIter)) { + theRetVal = false; + break; + } else + theCheckString += inString.Extract(theIter, 1); + } + + return theRetVal; +} + +//============================================================================== +/** + * Refreshes the display string from the internal data + */ +void CFloatEdit::RefreshDisplayFromData() +{ + SetDisplayString(GetString()); + Invalidate(); +} diff --git a/src/Authoring/Studio/Controls/FloatEdit.h b/src/Authoring/Studio/Controls/FloatEdit.h new file mode 100644 index 00000000..4e29283b --- /dev/null +++ b/src/Authoring/Studio/Controls/FloatEdit.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** 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_FLOAT_EDIT_H +#define INCLUDED_FLOAT_EDIT_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "TextEdit.h" + +#include + +GENERIC_FUNCTOR_1(CRevertListener, OnDiscardChanges, CControl *); + +//============================================================================== +// Forwards +//============================================================================== +class CMouseCursor; + +class CFloatEdit : public CTextEdit +{ +protected: + float m_Value; ///< + short m_NumDecimalPlaces; ///< + short m_FixedPlaces; ///< + bool m_IsMouseDown; ///< + bool m_Trapping; ///< + float m_StartDragVal; ///< + float m_Min; ///< + float m_Max; ///< + bool m_EditMode; ///< + Q3DStudio::CString m_ValueString; ///< + CPt m_MouseStartPos; ///< Used to reset the mouse pos when dragging values. + CRevertListener *m_RevertListener; ///< Used when user presses escape. + +public: + CFloatEdit(); + virtual ~CFloatEdit(); + + Q3DStudio::CString GetString() override; + virtual void SetData(float inValue, bool inFireEvent = true); + void SetData(const Q3DStudio::CString &inData, bool inFireEvent = true) override; + bool CanAcceptChar(const Q3DStudio::CString &inCheckString, unsigned int inChar, + unsigned int inPosition) override; + bool CanPaste() 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; + bool OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags) override; + + virtual void SetMin(float inMin); + virtual void SetMax(float inMax); + + void OnLoseFocus() override; + void OnGainFocus() override; + bool CanGainFocus() override; + + float GetData(); + float GetDisplayData(); + + void SetNumDecimalPlaces(short inNumDecimalPlaces); + void SetFixedPlaces(short inFixedPlaces); + void RefreshDisplayFromData() override; + + virtual void SetRevertListener(CRevertListener *inListener) { m_RevertListener = inListener; } + +protected: + bool HandleSpecialChar(unsigned int inChar, Qt::KeyboardModifiers inFlags) override; + + void SetFloatValue(float inValue); + bool Validate(const Q3DStudio::CString &inString); + + void EnterEditMode(); + void ExitEditMode(); + + void FormatString(); + + void AddCharNegative(); + void AddCharPeriod(); +}; + +#endif // INCLUDED_FLOAT_EDIT_H diff --git a/src/Authoring/Studio/Controls/FlowLayout.cpp b/src/Authoring/Studio/Controls/FlowLayout.cpp new file mode 100644 index 00000000..9864321d --- /dev/null +++ b/src/Authoring/Studio/Controls/FlowLayout.cpp @@ -0,0 +1,1009 @@ +/**************************************************************************** +** +** 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 "FlowLayout.h" +#include "Renderer.h" +#include "MasterP.h" +#include "ControlData.h" +#include "CoreUtils.h" +#include "UICMath.h" +// using namespace Q3DStudio; <-- Do not do this here because it will conflict with CList and make +// the template generator go blah + +using namespace Q3DStudio::Control; + +//============================================================================= +/** + * Checks to see if this has hit it's max X + */ +bool CanBeExpandedX(CControl *inControl) +{ + bool theRetVal = false; + CPt theSize = inControl->GetSize(); + CPt theMaxSize = inControl->GetMaximumSize(); + if (theSize.x < theMaxSize.x) { + theRetVal = true; + } + return theRetVal; +} + +//============================================================================= +/** + * Checks to see if this has hit it's max Y + */ +bool CanBeExpandedY(CControl *inControl) +{ + bool theRetVal = false; + CPt theSize = inControl->GetSize(); + CPt theMaxSize = inControl->GetMaximumSize(); + if (theSize.y < theMaxSize.y) { + theRetVal = true; + } + return theRetVal; +} + +IMPLEMENT_OBJECT_COUNTER(CFlowLayout) + +//============================================================================= +/** + * Constructs a new FlowLayout flowing vertically (down). + */ +CFlowLayout::CFlowLayout(CControl *inControl, bool inUseControl) + : m_FlowDirection(FLOW_VERTICAL) + , m_VerticalAlignment(ALIGN_TOP) + , m_HorizontalAlignment(ALIGN_LEFT) + , m_ResizingChildren(false) + , m_LeftMargin(0) + , m_RightMargin(0) + , m_TopMargin(0) + , m_BottomMargin(0) + , m_ChildGap(0) + , m_DebugFlag(false) + , m_AutoMin(true) + , m_SuspendRecalcLayout(false) +{ + ADDTO_OBJECT_COUNTER(CFlowLayout) + + m_BlankDisable = false; + m_HasUnusedSpace = false; + + if (inControl != nullptr) { + m_BlankControl = inControl; + } else if (inUseControl) { + m_BlankControl = new CBlankControl(); + } else { + m_BlankControl = nullptr; + } + + SetMaximumSize(CPt(LONG_MAX, LONG_MAX)); +} + +//============================================================================= +/** + * Destructor + */ +CFlowLayout::~CFlowLayout() +{ + delete m_BlankControl; + + REMOVEFROM_OBJECT_COUNTER(CFlowLayout) +} + +//============================================================================= +/** + * The left margin is the gap on the left side of the flow layout where no + * controls are drawn. The default left margin of a flow layout is zero. If + * you have a horizontal flow layout with left alignment, you can use the margin + * to push all the child controls over by a fixed amount. + * @param inMargin Width in pixels of the left margin + * @return the previous width of the left margin + */ +long CFlowLayout::SetLeftMargin(long inMargin) +{ + long theOldMargin = m_LeftMargin; + m_LeftMargin = inMargin; + ResetMinMaxPref(); + RecalcLayout(); + return theOldMargin; +} + +//============================================================================= +/** + * The left margin is the gap on the left side of the flow layout where no + * controls are drawn. The default left margin of a flow layout is zero. Only + * valid with a horizontal flow layout with left alignment. + * @return the gap on the left side of this flow, in pixels + */ +long CFlowLayout::GetLeftMargin() const +{ + return m_LeftMargin; +} + +long CFlowLayout::GetRightMargin() const +{ + return m_RightMargin; +} + +long CFlowLayout::GetTopMargin() const +{ + return m_TopMargin; +} + +long CFlowLayout::GetBottomMargin() const +{ + return m_BottomMargin; +} + +//============================================================================= +/** + * Disables the drawing of blank rectangles in blank areas on the screen + * @param NONE + * @return NONE + */ +void CFlowLayout::DisableBlank() +{ + m_BlankDisable = true; +} + +//============================================================================= +/** + * The right margin is the gap on the rgiht side of the flow layout where no + * controls are drawn. The default right margin of a flow layout is zero. If + * you have a horizontal flow layout with right alignment, you can use the margin + * to push all the child controls over by a fixed amount. + * @param inMargin Width in pixels of the right margin + * @return the previous width of the right margin + */ +long CFlowLayout::SetRightMargin(long inMargin) +{ + long theOldMargin = m_RightMargin; + m_RightMargin = inMargin; + ResetMinMaxPref(); + RecalcLayout(); + return theOldMargin; +} + +//============================================================================= +/** + * The top margin is the gap on the top of the flow layout where no controls + * are drawn. The default top margin of a flow layout is zero. If you have + * a vertical flow layout with top alignment, you can use the margin to push + * all the child controls down by a fixed amount. + * @param inMargin Height in pixels of the top margin + * @return the previous height of the top margin + */ +long CFlowLayout::SetTopMargin(long inMargin) +{ + long theOldMargin = m_TopMargin; + m_TopMargin = inMargin; + ResetMinMaxPref(); + RecalcLayout(); + return theOldMargin; +} + +//============================================================================= +/** + * The bottom margin is the gap on the bottom of the flow layout where no + * controls are drawn. The default bottom margin of a flow layout is zero. If + * you have a vertical flow layout with bottom alignment, you can use the margin + * to push all the child controls up by a fixed amount. + * @param inMargin Height in pixels of the bottom margin + * @return the previous height of the bottom margin + */ +long CFlowLayout::SetBottomMargin(long inMargin) +{ + long theOldMargin = m_BottomMargin; + m_BottomMargin = inMargin; + ResetMinMaxPref(); + RecalcLayout(); + return theOldMargin; +} + +//============================================================================= +/** + * This functions sets a fixed gap between children of the flow layout. + * @param inGap pixel gap between each child of the flow layout + * @return the previous pixel gap between children + */ +long CFlowLayout::SetGapBetweenChildren(long inGap) +{ + long theOldGap = m_ChildGap; + m_ChildGap = inGap; + ResetMinMaxPref(); + RecalcLayout(); + return theOldGap; +} + +//============================================================================= +/** + * Get the preferred size of this control. + * The preferred size is the sum of all the preferred sizes of all the children. + * @return the preferred size of this control. + */ +// CPt CFlowLayout::GetPreferredSize( ) +//{ +// return m_PreferredSize; +//} + +//============================================================================= +/** + * Get the minimum size of this control. + * The minimum size is the sum of all the minimum sizes of all the children in + * the flow direction, and the largest minimum size in the non-flow direction. + * @return the minimum size of this control. + */ +// CPt CFlowLayout::GetMinimumSize( ) +//{ +// return m_MinimumSize; +//} + +//============================================================================= +/** + * Get the maximum size of this control. + * The maximum size is the sum of all the maximum sizes of all the children in + * the flow direction, and the smallest maximum size in the non-flow direction. + * @return the maximum size of this control. + */ +// CPt CFlowLayout::GetMaximumSize( ) +//{ +// return m_MaximumSize; +//} + +//============================================================================= +/** + * Set the direction the components are flowing. + * Vertical means the components will be positioned one on top of the other, + * starting at the top and flowing down. + * Horizontal means the components will be positions side by side, starting on + * the left and flowing right. + * @param inFlowDirection the new flow direction. + */ +void CFlowLayout::SetFlowDirection(EFlowDirection inFlowDirection) +{ + if (inFlowDirection != m_FlowDirection) { + m_FlowDirection = inFlowDirection; + + RecalcLayout(); + } +} + +//============================================================================= +/** + * Add a child control to this control. + * This adds the child control to this and includes it in the layout. + * @param inControl the control to be added. + * @param inInsertBefore the location to insert the control, nullptr = end. + */ +void CFlowLayout::AddChild(CControl *inControl, CControl *inInsertBefore /*= nullptr*/) +{ + CControl::AddChild(inControl, inInsertBefore); + + if (GetParent() != nullptr) { + ResetMinMaxPref(); + GetParent()->OnChildSizeChanged(this); + } + + RecalcLayout(); +} + +//============================================================================= +/** + * Remove a child from this control. + * @param inControl the control to be removed. + */ +void CFlowLayout::RemoveChild(CControl *inControl) +{ + CControl::RemoveChild(inControl); + + if (GetParent() != nullptr) { + ResetMinMaxPref(); + GetParent()->OnChildSizeChanged(this); + } + + RecalcLayout(); +} + +/** + * Sets the flag on whether to suspend the recalculation of the layout. + * Recalc is expensive, especially when there are many children. + * if you need to add lots of children items to this control, do this: + * SuspendRecalcLayout( true ); AddLotsOFItems( ); SuspendRecalcLayout( false ); + * DoSomethingThatWillTriggerRecalcLayout( ); + * @param inSuspendFlag true would suspend recalc + * @see RecalcLayout + * @see CListBoxControl +*/ +void CFlowLayout::SuspendRecalcLayout(bool inSuspendFlag) +{ + m_SuspendRecalcLayout = inSuspendFlag; +} + +//============================================================================= +/** + * Recalculate the positions of all the child controls of this control. + * This does the work of all the layout of the children and figures out where + * everything belongs. + */ +void CFlowLayout::RecalcLayout() +{ + UICPROFILE(RecalcLayout); + + // if you need to add lots of children items to this control, do this: + // SuspendRecalcLayout( true ); AddLotsOFItems( ); SuspendRecalcLayout( false ); + // DoSomethingThatWillTriggerRecalcLayout( ); + if (m_SuspendRecalcLayout) + return; + + m_ResizingChildren = true; + + CPt thePosition(0, 0); + CPt theCurSize = GetSize(); + long theNumExpandableY = 0; + long theNumExpandableX = 0; + m_HasUnusedSpace = false; + + if ((m_FlowDirection == FLOW_HORIZONTAL && m_HorizontalAlignment != ALIGN_RIGHT) + || (m_FlowDirection == FLOW_VERTICAL && m_VerticalAlignment != ALIGN_BOTTOM)) { + thePosition.x = m_LeftMargin; + thePosition.y = m_TopMargin; + ControlGraph::SIterator thePos = GetChildren(); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = *thePos; + RecalcChild(theChild->GetControl(), thePosition, theNumExpandableX, theNumExpandableY); + + if (m_FlowDirection == FLOW_HORIZONTAL) + thePosition += CPt(m_ChildGap, 0); + else + thePosition += CPt(0, m_ChildGap); + } + } else { + // thePosition.x = m_RightMargin; + // thePosition.y = m_BottomMargin; + ControlGraph::SReverseIterator thePos = GetReverseChildren(); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = *thePos; + RecalcChild(theChild->GetControl(), thePosition, theNumExpandableX, theNumExpandableY); + + if (m_FlowDirection == FLOW_HORIZONTAL) + thePosition -= CPt(m_ChildGap, 0); + else + thePosition -= CPt(0, m_ChildGap); + } + } + + // If there is extra space and there are items able to expand still + if (thePosition.y < theCurSize.y && m_FlowDirection == FLOW_VERTICAL) { + if (theNumExpandableY > 0) + ResizeExpandableControlsY((theCurSize.y - thePosition.y), theNumExpandableY); + else + m_HasUnusedSpace = true; + + // SDJ: See below + // ResetChildPositions( ); + } else if (thePosition.x < theCurSize.x && m_FlowDirection == FLOW_HORIZONTAL) { + if (theNumExpandableX > 0) + ResizeExpandableControlsX((theCurSize.x - thePosition.x), theNumExpandableX); + else + m_HasUnusedSpace = true; + + // SDJ: See below + // ResetChildPositions( ); + } + + // SDJ: There is a case where the top margin is not properly calculated when + // neither of the above conditions is met. Calling ResetChildPositions fixes + // this, but might be ineffiecient. If you attempt to fix this, replace the + // commented out calls to ResetChildPositions above. + ResetChildPositions(); + + m_ResizingChildren = false; + + Invalidate(); +} + +//============================================================================= +/** + * XXX + */ +void CFlowLayout::RecalcChild(CControl *inChild, CPt &ioPosition, long &ioNumExpandableX, + long &ioNumExpandableY) +{ + CPt theTotalPrefSizes = GetTotalPreferredSizes(); + CPt theCurSize = GetSize(); + CPt theChildSize = theCurSize; + + theCurSize.x -= m_RightMargin; + theCurSize.y -= m_BottomMargin; + + if (inChild->IsVisible()) { + inChild->ResetMinMaxPref(); + CPt thePrefSize = inChild->GetPreferredSize(); + CPt theMinSize = inChild->GetMinimumSize(); + CPt theMaxSize = inChild->GetMaximumSize(); + + if (theMaxSize.x > theCurSize.x - ioPosition.x) + theMaxSize.x = theCurSize.x - ioPosition.x; + if (theMaxSize.x < 0) + theMaxSize.x = 0; + if (theMaxSize.y > theCurSize.y - ioPosition.y) + theMaxSize.y = theCurSize.y - ioPosition.y; + if (theMaxSize.y < 0) + theMaxSize.y = 0; + + if (m_FlowDirection == FLOW_VERTICAL) { + CPt theChildPosition; + theChildPosition.y = ioPosition.y; + theChildPosition.x = 0; + theChildSize.x = theCurSize.x; + ///* + // SDJ; Why is this commented out? + switch (m_HorizontalAlignment) { + case ALIGN_LEFT: + theChildPosition.x = 0; + break; + + case ALIGN_RIGHT: + theChildPosition.x = + (GetSize().x - (m_LeftMargin + m_RightMargin)) - inChild->GetSize().x; + break; + + case ALIGN_MIDDLE: + theChildPosition.x = (GetSize().x / 2) - (inChild->GetSize().x / 2); + break; + + case ALIGN_HORIZ_NEITHER: + // NO BREAK + default: + theChildPosition.x = inChild->GetPosition().x; + break; + } + //*/ + + inChild->SetPosition(theChildPosition); + + if (theTotalPrefSizes.y) { + float theModifier = ((float)thePrefSize.y) / ((float)theTotalPrefSizes.y); + // Check to see if they have hit their min or max + if (theMinSize.y > ::dtol(theCurSize.y * theModifier)) { + theChildSize.y = theMinSize.y; + ++ioNumExpandableY; + + } else if (theMaxSize.y < ::dtol(theCurSize.y * theModifier)) { + theChildSize.y = theMaxSize.y; + } else { + // This item can be expanded + ++ioNumExpandableY; + theChildSize.y = inChild->GetSize().y; + } + } + + // If the child cannot be expanded, maintain its current width + // if ( !CanBeExpandedX( inChild ) ) + // theChildSize.x = inChild->GetSize( ).x; + + theChildSize.x = Q3DStudio::MAX(theChildSize.x, theMinSize.x); + theChildSize.y = Q3DStudio::MAX(theChildSize.y, theMinSize.y); + + theChildSize.x = Q3DStudio::MIN(theChildSize.x, theMaxSize.x); + theChildSize.y = Q3DStudio::MIN(theChildSize.y, theMaxSize.y); + + inChild->SetSize(theChildSize); + ioPosition.y += theChildSize.y; + } else { + CPt theChildPosition; + theChildPosition.x = ioPosition.x; + + switch (m_VerticalAlignment) { + case ALIGN_TOP: + theChildPosition.y = m_TopMargin; + break; + + case ALIGN_BOTTOM: + theChildPosition.y = GetSize().y - inChild->GetSize().y; + break; + + case ALIGN_CENTER: + theChildPosition.y = (GetSize().y / 2) - (inChild->GetSize().y / 2); + break; + + case ALIGN_VERT_NEITHER: + // NO BREAK + default: + theChildPosition.y = inChild->GetPosition().y; + break; + } + + inChild->SetPosition(theChildPosition); + + if (theTotalPrefSizes.x) { + float theModifier = ((float)thePrefSize.x) / ((float)theTotalPrefSizes.x); + // Check to see if they have hit their min or max + if (theMinSize.x > ::dtol(theCurSize.x * theModifier)) { + theChildSize.x = theMinSize.x; + ++ioNumExpandableX; + + } else if (theMaxSize.x < ::dtol(theCurSize.x * theModifier)) { + theChildSize.x = theMaxSize.x; + } else { + // This item can be expanded + theChildSize.x = ::dtol((theCurSize.x * theModifier)); + ++ioNumExpandableX; + } + } + + // If the child cannot by expanded, maintain the same height + if (!CanBeExpandedY(inChild)) + theChildSize.y = inChild->GetSize().y; + + theChildSize.x = Q3DStudio::MAX(theChildSize.x, theMinSize.x); + theChildSize.y = Q3DStudio::MAX(theChildSize.y, theMinSize.y); + + theChildSize.x = Q3DStudio::MIN(theChildSize.x, theMaxSize.x); + theChildSize.y = Q3DStudio::MIN(theChildSize.y, theMaxSize.y); + + inChild->SetSize(theChildSize); + ioPosition.x += theChildSize.x; + } + } +} + +//============================================================================== +/** + * Resets all child positions accd to their size + */ +void CFlowLayout::ResetChildPositions() +{ + if ((m_FlowDirection == FLOW_HORIZONTAL && m_HorizontalAlignment != ALIGN_RIGHT) + || (m_FlowDirection == FLOW_VERTICAL && m_VerticalAlignment != ALIGN_BOTTOM)) { + CPt thePosition(m_LeftMargin, m_TopMargin); + ControlGraph::SIterator thePos = GetChildren(); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + if (theChild->IsVisible()) { + CPt theChildSize = theChild->GetSize(); + if (m_FlowDirection == FLOW_VERTICAL) { + thePosition.x = theChild->GetPosition().x + m_LeftMargin; + theChild->SetPosition(thePosition); + thePosition.y = thePosition.y + theChildSize.y + m_ChildGap; + } else { + thePosition.y = theChild->GetPosition().y + m_TopMargin; + theChild->SetPosition(thePosition); + thePosition.x = thePosition.x + theChildSize.x + m_ChildGap; + } + } + } + + if (m_HasUnusedSpace && m_BlankControl) { + CPt theBlankPosition; + if (m_FlowDirection == FLOW_HORIZONTAL) { + theBlankPosition.x = thePosition.x; + theBlankPosition.y = 0; + } else { + theBlankPosition.x = 0; + theBlankPosition.y = thePosition.y; + } + m_BlankControl->SetPosition(theBlankPosition); + m_BlankControl->SetSize(GetSize() - theBlankPosition); + } + } else { + CPt thePosition(GetSize() - CPt(m_RightMargin, m_BottomMargin)); + ControlGraph::SReverseIterator thePos = GetReverseChildren(); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + if (theChild->IsVisible()) { + CPt theChildSize = theChild->GetSize(); + if (m_FlowDirection == FLOW_VERTICAL) { + thePosition.x = theChild->GetPosition().x - m_RightMargin; + thePosition.y = thePosition.y - theChildSize.y - m_ChildGap; + theChild->SetPosition(thePosition); + } else { + thePosition.y = theChild->GetPosition().y - m_BottomMargin; + thePosition.x = thePosition.x - theChildSize.x - m_ChildGap; + theChild->SetPosition(thePosition); + } + } + } + + if (m_HasUnusedSpace && m_BlankControl) { + CPt theBlankSize; + if (m_FlowDirection == FLOW_HORIZONTAL) { + theBlankSize.x = thePosition.x; + theBlankSize.y = GetSize().y; + } else { + theBlankSize.x = GetSize().x; + theBlankSize.y = thePosition.y; + } + m_BlankControl->SetPosition(CPt(0, 0)); + m_BlankControl->SetSize(theBlankSize); + } + } +} + +//============================================================================== +/** + * Resizes any expandable Controls in the Y Dir + * + * @param inExtraSpace the Amount left + * @param inNumExpandable used to calc percentages + */ +void CFlowLayout::ResizeExpandableControlsY(long inExtraSpace, long inNumExpandable) +{ + m_HasUnusedSpace = false; + long theSpaceDistributed = 0; + if (inExtraSpace / inNumExpandable < 1) { + this->DistributeRemaining(inExtraSpace); + } else { + ControlGraph::SIterator thePos = GetChildren(); + long theNumExpandable = 0; + + // Loop through teh children for items that can expand + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + + // If this item can be expanded then expand accd to new percent + if (CanBeExpandedY(theChild->GetControl()) && theChild->IsVisible()) { + CPt theMaxSize = theChild->GetMaximumSize(); + CPt theChildSize = theChild->GetSize(); + float theModifier = (float)1 / inNumExpandable; + if (theMaxSize.y < ::dtol((inExtraSpace * theModifier) + theChildSize.y)) { + theSpaceDistributed += theMaxSize.y - theChildSize.y; + theChildSize.y = theMaxSize.y; + } else { + theSpaceDistributed += ::dtol((inExtraSpace * theModifier)); + theChildSize.y += ::dtol((inExtraSpace * theModifier)); + ++theNumExpandable; + } + + theChild->SetSize(theChildSize); + } + } + + // If there is extra space and there are items able to expand still + if ((inExtraSpace - theSpaceDistributed) > 0) { + if (theNumExpandable > 0) { + this->ResizeExpandableControlsY((inExtraSpace - theSpaceDistributed), + theNumExpandable); + } else { + m_HasUnusedSpace = true; + } + } + } +} + +//============================================================================== +/** + * Resizes any expandable Controls in the X Dir + * + * @param inExtraSpace the Amount left + * @param inNumExpandable used to calc percentages + */ +void CFlowLayout::ResizeExpandableControlsX(long inExtraSpace, long inNumExpandable) +{ + m_HasUnusedSpace = false; + long theSpaceDistributed = 0; + if (inExtraSpace / inNumExpandable < 1) { + this->DistributeRemaining(inExtraSpace); + } else { + long theNumExpandable = 0; + ControlGraph::SIterator thePos = GetChildren(); + // Loop through teh children for items that can expand + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + + // If this item can be expanded then expand accd to new percent + if (CanBeExpandedX(theChild->GetControl()) && theChild->IsVisible()) { + CPt theMaxSize = theChild->GetMaximumSize(); + CPt theChildSize = theChild->GetSize(); + float theModifier = (float)1 / inNumExpandable; + if (theMaxSize.x < ::dtol((inExtraSpace * theModifier) + theChildSize.x)) { + theSpaceDistributed += theMaxSize.x - theChildSize.x; + theChildSize.x = theMaxSize.x; + } else { + theSpaceDistributed += ::dtol((inExtraSpace * theModifier)); + theChildSize.x += ::dtol((inExtraSpace * theModifier)); + ++theNumExpandable; + } + + theChild->SetSize(theChildSize); + } + } + + // If there is extra space and there are items able to expand still + if ((inExtraSpace - theSpaceDistributed) > 0) { + if (theNumExpandable > 0) { + this->ResizeExpandableControlsX((inExtraSpace - theSpaceDistributed), + theNumExpandable); + } else { + m_HasUnusedSpace = true; + } + } + } +} + +//============================================================================== +/** + * Distributes remaining size to items that can be expanded. + * this should only be called when theNumExpandable items > the extra space + */ +void CFlowLayout::DistributeRemaining(long inExtraSpace) +{ + long theNumToDistribute = inExtraSpace; + if (m_FlowDirection == FLOW_VERTICAL) { + ControlGraph::SIterator thePos = GetChildren(); + // Loop through teh children for items that can expand + for (; thePos.HasNext() && theNumToDistribute > 0; ++thePos) { + std::shared_ptr theChild = (*thePos); + + // If this item can be expanded then expand accd to new percent + if (CanBeExpandedY(theChild->GetControl()) && theChild->IsVisible()) { + CPt theChildSize = theChild->GetSize(); + theChildSize.y++; + theChild->SetSize(theChildSize.x, theChildSize.y); + theNumToDistribute--; + } + } + } else { + ControlGraph::SIterator thePos = GetChildren(); + // Loop through teh children for items that can expand + for (; thePos.HasNext() && theNumToDistribute > 0; ++thePos) { + std::shared_ptr theChild = (*thePos); + + // If this item can be expanded then expand accd to new percent + if (CanBeExpandedX(theChild->GetControl()) && theChild->IsVisible()) { + CPt theChildSize = theChild->GetSize(); + theChildSize.x++; + theChild->SetSize(theChildSize.x, theChildSize.y); + theNumToDistribute--; + } + } + } +} + +//============================================================================== +/** + * Gets the total prefered sizes of the children + */ +CPt CFlowLayout::GetTotalPreferredSizes() +{ + CPt theTotalPrefSizes(0, 0); + + ControlGraph::SIterator thePos = GetChildren(); + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + if (theChild->IsVisible()) { + theTotalPrefSizes += theChild->GetPreferredSize(); + } + } + + return theTotalPrefSizes; +} + +//============================================================================== +/** + * sets the size and does a recalc + */ +void CFlowLayout::SetSize(CPt inSize) +{ + if (inSize != GetSize()) { + CControl::SetSize(inSize); + + RecalcLayout(); + } +} + +void CFlowLayout::SetLayout(CPt inSize, CPt inPosition) +{ + CControl::SetLayout(inSize, inPosition); + + RecalcLayout(); +} +//============================================================================== +/** + * override to force a recalc when the parent is changed + */ +void CFlowLayout::OnParentChanged(CControl *inParent) +{ + CControl::OnParentChanged(inParent); + RecalcLayout(); +} + +//============================================================================== +/** + * Sets this object's alignment + */ +void CFlowLayout::SetAlignment(EVerticalAlignment inVertical, EHorizontalAlignment inHorizontal) +{ + m_VerticalAlignment = inVertical; + m_HorizontalAlignment = inHorizontal; + + RecalcLayout(); +} + +//============================================================================== +/** + * Overloaded draw function. Draws the extra control if it is needed + */ +void CFlowLayout::Draw(CRenderer *inRenderer) +{ + // If there is unused space in this control, then use the blank control + if (m_HasUnusedSpace && m_BlankControl) { + if (m_BlankControl->IsVisible()) { + inRenderer->PushTranslation(m_BlankControl->GetPosition()); + if (!m_BlankDisable) + m_BlankControl->Draw(inRenderer); + inRenderer->PopTranslation(); + } + } +} + +//============================================================================== +/** + * called when a child's size changes + */ +void CFlowLayout::OnChildSizeChanged(CControl *inChild) +{ + Q_UNUSED(inChild); + + if (!m_ResizingChildren) { + ResetMinMaxPref(); + + if (GetParent() != nullptr) + GetParent()->OnChildSizeChanged(this); + + RecalcLayout(); + } +} + +//============================================================================== +/** + * Called to calc the min/max/and pre size of this layout. NOTE: this function + * no longer adjusts the max size of the flow layout. The max size is not dictated + * by the size of the children, so it can be set independently with a call to + * SetMaximumSize(). + */ +void CFlowLayout::ResetMinMaxPref() +{ + if (m_AutoMin) { + CPt thePreferredSize(0, 0); + CPt theMinimumSize(0, 0); + + thePreferredSize = theMinimumSize; + + // Keep track of the largest, minimum size of all the children for use later + CPt theBiggestChildMinSize(0, 0); + + // Go through all the children and find their maximum sizes. + ControlGraph::SIterator thePos = GetChildren(); + + for (; thePos.HasNext(); ++thePos) { + std::shared_ptr theChild = (*thePos); + if (theChild->IsVisible()) { + theChild->ResetMinMaxPref(); + CPt theChildPrefSize = theChild->GetPreferredSize(); + CPt theChildMinSize = theChild->GetMinimumSize(); + + // use the sum of the children in the flow direction and the smallest size + // in the non-flow direction. + if (m_FlowDirection == FLOW_VERTICAL) { + thePreferredSize.y += theChildPrefSize.y; + + theMinimumSize.y += theChildMinSize.y; + + if (theChildMinSize.x > theBiggestChildMinSize.x) + theBiggestChildMinSize = theChildMinSize; + } else { + thePreferredSize.x += theChildPrefSize.x; + + theMinimumSize.x += theChildMinSize.x; + + if (theChildMinSize.y > theBiggestChildMinSize.y) + theBiggestChildMinSize = theChildMinSize; + } + } + } + + // If this is a vertical flow + if (m_FlowDirection == FLOW_VERTICAL) { + // The width is determined by minimum size of the largest child + theMinimumSize.x = theBiggestChildMinSize.x; + + // If the flow is aligned to top, the top margin must be added to the minimum height + if (m_VerticalAlignment == ALIGN_TOP) + theMinimumSize.y += m_TopMargin; + // If the flow is aligned to bottom, the bottom margin must be added to the minimum + // height + else if (m_VerticalAlignment == ALIGN_BOTTOM) + theMinimumSize.y += m_BottomMargin; + + theMinimumSize.y += (m_ChildGap * GetChildCount()); + } + // If this is a horzontal flow + else { + // The height is determined by minimum size of the largest child + theMinimumSize.y = theBiggestChildMinSize.y; + + // If the flow is left aligned, the left margin must be added to the minimum width + if (m_HorizontalAlignment == ALIGN_LEFT) + theMinimumSize.x += m_LeftMargin; + // If the flow is right aligned, the right margin must be added to the minimum width + else if (m_HorizontalAlignment == ALIGN_RIGHT) + theMinimumSize.x += m_RightMargin; + + theMinimumSize.x += (m_ChildGap * GetChildCount()); + } + + thePreferredSize.x = max(thePreferredSize.x, theMinimumSize.x); + thePreferredSize.y = max(thePreferredSize.y, theMinimumSize.y); + + SetMinimumSize(theMinimumSize); + SetPreferredSize(thePreferredSize); + } +} + +//============================================================================= +/** + * Override the default in case the blank control was hit + * @param inPoint where the mouse was clicked, in local coordinates. + * @param inFlags Modifier keys that are down at time of event. Can be any + * @return true if the mouse event is processed. + */ +bool CFlowLayout::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theRetVal = CControl::OnMouseDown(inPoint, inFlags); + if (!theRetVal) { + if (m_BlankControl && m_BlankControl->HitTest(inPoint)) + GrabFocus(nullptr); + } + return theRetVal; +} + +//============================================================================= +/** + * Override the default in case the blank control was hit + * @param inPoint where the mouse was clicked, in local coordinates. + * @param inFlags Modifier keys that are down at time of event. Can be any + * @return true if the mouse event is processed. + */ +bool CFlowLayout::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theRetVal = CControl::OnMouseRDown(inPoint, inFlags); + if (!theRetVal) { + if (m_BlankControl && m_BlankControl->HitTest(inPoint)) + GrabFocus(nullptr); + } + return theRetVal; +} diff --git a/src/Authoring/Studio/Controls/FlowLayout.h b/src/Authoring/Studio/Controls/FlowLayout.h new file mode 100644 index 00000000..1f7523a1 --- /dev/null +++ b/src/Authoring/Studio/Controls/FlowLayout.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** 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_FLOW_LAYOUT_H +#define INCLUDED_FLOW_LAYOUT_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" +#include "BlankControl.h" + +//============================================================================== +// Classes +//============================================================================== + +//============================================================================== +/** +* @class CFlowLayout +* @brief CHRIS.EDWARDS needs to enter a brief description here. +* +* CHRIS.EDWARDS needs to enter a long description here. +*/ +class CFlowLayout : public CControl +{ +public: + enum EFlowDirection { + FLOW_VERTICAL, + FLOW_HORIZONTAL, + }; + + enum EVerticalAlignment { + ALIGN_TOP, + ALIGN_BOTTOM, + ALIGN_CENTER, + ALIGN_VERT_NEITHER, + }; + + enum EHorizontalAlignment { + ALIGN_LEFT, + ALIGN_RIGHT, + ALIGN_MIDDLE, + ALIGN_HORIZ_NEITHER, + }; + + CFlowLayout(CControl *inControl = nullptr, bool inUseControl = true); + virtual ~CFlowLayout(); + + DEFINE_OBJECT_COUNTER(CFlowLayout) + + void SetSize(CPt inSize) override; + void SetLayout(CPt inSize, CPt inPosition) override; + void OnParentChanged(CControl *inParent) override; + + void SetAlignment(EVerticalAlignment inVertical, EHorizontalAlignment inHorizontal); + long SetLeftMargin(long inMargin); + long GetLeftMargin() const; + long SetRightMargin(long inMargin); + long GetRightMargin() const; + long SetTopMargin(long inMargin); + long GetTopMargin() const; + long SetBottomMargin(long inMargin); + long GetBottomMargin() const; + long SetGapBetweenChildren(long inGap); + void SetDebug(bool inFlag) { m_DebugFlag = inFlag; } + void SetAutoMin(bool inFlag) { m_AutoMin = inFlag; } + + virtual void SetFlowDirection(EFlowDirection inFlowDirection); + void AddChild(CControl *inControl, CControl *inInsertBefore = nullptr) override; + void RemoveChild(CControl *inControl) override; + void Draw(CRenderer *inRenderer) override; + virtual void DisableBlank(); + void OnChildSizeChanged(CControl *inControl) override; + + virtual void RecalcLayout(); + void SuspendRecalcLayout(bool inSuspendFlag); + void ResetMinMaxPref() override; + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + +protected: + CPt GetTotalPreferredSizes(); + void ResizeExpandableControlsY(long inExtraSpace, long inNumExpandable); + void ResizeExpandableControlsX(long inExtraSpace, long inNumExpandable); + void ResetChildPositions(); + void DistributeRemaining(long inExtraSpace); + void RecalcChild(CControl *inChild, CPt &ioPosition, long &ioNumExpandableX, + long &ioNumExpandableY); + + bool m_HasUnusedSpace; + bool m_BlankDisable; + EFlowDirection m_FlowDirection; + EVerticalAlignment m_VerticalAlignment; + EHorizontalAlignment m_HorizontalAlignment; + bool m_ResizingChildren; + long m_LeftMargin; ///< gap at left of this control + long m_RightMargin; ///< gap at right of this control + long m_TopMargin; ///< gap at top of this control + long m_BottomMargin; ///< gap at bottom of this control + long m_ChildGap; ///< gap between each child control when laying out everything + bool m_DebugFlag; + bool m_AutoMin; + + bool m_SuspendRecalcLayout; ///< flag to suspend recalculation of the layout; slow down is + ///noticeable if this control has many children + +private: + CControl *m_BlankControl; ///< used when all items are at their max and there si still space +}; + +#endif // INCLUDED_FLOW_LAYOUT_H diff --git a/src/Authoring/Studio/Controls/GenericComboDropDown.h b/src/Authoring/Studio/Controls/GenericComboDropDown.h new file mode 100644 index 00000000..cd95b3a2 --- /dev/null +++ b/src/Authoring/Studio/Controls/GenericComboDropDown.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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_GENERIC_COMBO_DROP_DOWN_H +#define INCLUDED_GENERIC_COMBO_DROP_DOWN_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include "GenericEdit.h" +#include "ComboTextBox.h" + +#include + +//============================================================================== +// Forwards +//============================================================================== +class CButtonControl; +class CButtonUpListener; + +//============================================================================== +/** + * Combo-box GUI element. Allows user to choose from a list of strings, and the + * selected string is displayed in a box. + */ +class CGenericComboDropDown : public CGenericEdit, public IChangeDataListener +{ +public: + CGenericComboDropDown(const bool inUseFloat = false); + virtual ~CGenericComboDropDown(); + + void OnDropDownSelect(); + void OnButtonUp(CControl *inButton); + bool CanGainFocus() override; + void AddItem(const Q3DStudio::CString &inString, bool inEnable = true); + void RemoveAllItems(); + void SelectItem(long inIndex, bool inFireChangeEvent = true); + long GetSelectedItem(); + long GetItemCount(); + Q3DStudio::CString GetItemText(long inIndex); + Q3DStudio::CString GetCurrentText(); + + virtual long DoDropDownMenu(); + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseWheel(CPt inPoint, long inAmount, Qt::KeyboardModifiers inFlags) override; + bool OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inFlags) override; + void LayoutChildren() override { CGenericEdit::LayoutChildren(); } + + // IChangeDataListener + void OnChangeData(const Q3DStudio::CString &inOldString, + const Q3DStudio::CString &inNewString) override; + +protected: + virtual void ChangeSelection(long inNewSelection); + virtual void OffsetSelection(long inAmount); + void SetDisplayText(const Q3DStudio::CString &inString, bool inFireChangeEvent = true); + void UpdateReadOnly(bool inReadOnlyFlag); + + long m_SelectedItem; + Q3DStudio::CString m_CurrentText; + CComboTextBox *m_TextBox; ///< ComboTextBox (StringEdit derivative) that processes text data + CButtonControl *m_Button; + QMenu m_DropDownMenu; ///< Context menu used to display a list of options for the control + QActionGroup m_actionGroup; + bool m_ReverseOffset; ///< True if we want the mousewheel to scroll the other direction in the + ///list;useful for numerical lists like +}; + +#endif // INCLUDED_GENERIC_COMBO_DROP_DOWN_H diff --git a/src/Authoring/Studio/Controls/GenericEdit.h b/src/Authoring/Studio/Controls/GenericEdit.h new file mode 100644 index 00000000..5af96a6b --- /dev/null +++ b/src/Authoring/Studio/Controls/GenericEdit.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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_GENERIC_EDIT_H +#define INCLUDED_GENERIC_EDIT_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include "LazyFlow.h" +#include "Multicaster.h" +#include "CColor.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; + +//============================================================================== +// Functors +//============================================================================== +/// Function to be called when the edit control changes +GENERIC_FUNCTOR(CGenericEditCommitListener, OnCommitData); +GENERIC_FUNCTOR(CGenericEditChangeListener, OnChangeData); +GENERIC_FUNCTOR(CGenericEditRevertListener, OnRevertData); + +//============================================================================== +/** + * Base class for most edit controls. Provides functions for adding/removing/ + * notifying listeners when the control's value changes. Implements some + * common functionality across all edit controls. + */ +class CGenericEdit : public Q3DStudio::Control::CRuntimeLazyFlow +{ +public: + CGenericEdit(); + virtual ~CGenericEdit(); + + void AddCommitListener(CGenericEditCommitListener *inListener); + void RemoveCommitListener(CGenericEditCommitListener *inListener); + void FireCommitDataEvent(); + + void AddChangeListener(CGenericEditChangeListener *inListener); + void RemoveChangeListener(CGenericEditChangeListener *inListener); + void FireChangeDataEvent(); + + void AddRevertListener(CGenericEditRevertListener *inListener); + void RemoveRevertListener(CGenericEditRevertListener *inListener); + void FireRevertDataEvent(); + + void SetFillBackground(bool inFill); + void SetBackgroundColor(const ::CColor &inColor); + + // CControl + void Draw(CRenderer *inRenderer); + +protected: + CMulticaster m_CommitListeners; + CMulticaster m_ChangeListeners; + CMulticaster m_RevertListeners; + bool m_FillBackground; + ::CColor m_BackgroundColor; +}; + +#endif // INCLUDED_GENERIC_EDIT_H diff --git a/src/Authoring/Studio/Controls/InsertionLine.cpp b/src/Authoring/Studio/Controls/InsertionLine.cpp new file mode 100644 index 00000000..5edbcd93 --- /dev/null +++ b/src/Authoring/Studio/Controls/InsertionLine.cpp @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** 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 "InsertionLine.h" +#include "Renderer.h" +#include "ResourceCache.h" +#include "StudioUtils.h" +#include "CColor.h" +#include "CoreUtils.h" + +//============================================================================= +/** + * Constructor + */ +CInsertionLine::CInsertionLine() + : m_LineWidth(0) + , m_LineHeight(2) + , m_LineColor(CColor(0, 0, 0)) +{ + SetVisible(false); + + m_InsertLeftImage = CResourceCache::GetInstance()->GetBitmap("Insert-Rearrange-Left.png"); + m_InsertRightImage = CResourceCache::GetInstance()->GetBitmap("Insert-Rearrange-Right.png"); + + const auto theLeftSize = m_InsertLeftImage.size(); + const auto theRightSize = m_InsertRightImage.size(); + + if (theLeftSize.height() >= theRightSize.width()) { + SetSize(CPt(theLeftSize.width() + theRightSize.width(), theLeftSize.height())); + SetMaximumSize(CPt(LONG_MAX, theLeftSize.height())); + } else { + SetSize(CPt(theLeftSize.width() + theRightSize.width(), theRightSize.height())); + SetMaximumSize(CPt(LONG_MAX, theLeftSize.height())); + } +} + +//============================================================================= +/** + * Destructor + */ +CInsertionLine::~CInsertionLine() +{ +} + +//============================================================================= +/** + * Sets the position of the line. Overridden since the line is technically + * drawn in the middle of the area specified as the size of this control, so + * we have to adjust the point accordingly. If you specify that the line should + * be drawn at inPoint = ( 100, 100 ), the line will be drawn there, but the + * actual control will be positioned at y = 100 - m_LineHeight. + * @param inPoint starting point of the line to be drawn + */ +void CInsertionLine::SetPosition(CPt inPoint) +{ + inPoint.y -= m_LineHeight; + COverlayControl::SetPosition(inPoint); +} + +//============================================================================= +/** + * Sets the width of the horizontal line. The arrows on the ends will + * automatically overlap this line. Thus the control will be exactly as wide + * as you specify here. You should call this method instead of SetSize. + * @param inWidth The new width of the line + */ +void CInsertionLine::SetLineWidth(long inWidth) +{ + m_LineWidth = inWidth; + + SetSize(CPt(m_LineWidth, GetSize().y)); +} + +//============================================================================= +/** + * Draws the insertion line at the current position. + * @param inRenderer Renderer to draw to + */ +void CInsertionLine::Draw(CRenderer *inRenderer) +{ + // Actual insertion line + CPt theTotalSize = GetSize(); + inRenderer->FillSolidRect( + CRct(CPt(0, ::dtol(theTotalSize.y / 2.0f) - ::dtol(m_LineHeight / 2.0f)), + CPt(m_LineWidth, m_LineHeight)), + m_LineColor); + + // Left arrow (draws on top of the left side of the line) + inRenderer->DrawBitmap(QPoint(0, 0), m_InsertLeftImage); + + // Right arrow (draws on top of the right side of the line) + const auto theRightSize = m_InsertRightImage.size(); + inRenderer->DrawBitmap(QPoint(theTotalSize.x - theRightSize.width(), 0), m_InsertRightImage); +} + +//============================================================================= +/** + * Check to see if inPoint is over this control or not. Overridden so that + * this overlay control does not interfere with drag-and-drop. + * @param inPoint not used + * @return false + */ +bool CInsertionLine::HitTest(const CPt &inPoint) const +{ + Q_UNUSED(inPoint); + + return false; +} diff --git a/src/Authoring/Studio/Controls/InsertionLine.h b/src/Authoring/Studio/Controls/InsertionLine.h new file mode 100644 index 00000000..60ec01bf --- /dev/null +++ b/src/Authoring/Studio/Controls/InsertionLine.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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_INSERTION_LINE_H +#define INCLUDED_INSERTION_LINE_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "OverlayControl.h" +#include "CColor.h" + +#include +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; + +//============================================================================= +/** + * Class for drawing a horizontal insertion line on top of other controls. + * Useful for indicating drag-and-drop locations. Example usage: Item is + * being inserted between Item1 and Item2. + * Item1 + * >----< + * Item2 + */ +class CInsertionLine : public COverlayControl +{ +public: + CInsertionLine(); + virtual ~CInsertionLine(); + virtual void SetPosition(CPt inPoint); + void SetLineWidth(long inWidth); + virtual void Draw(CRenderer *inRenderer); + virtual bool HitTest(const CPt &inPoint) const; + +protected: + long m_LineWidth; + long m_LineHeight; + CColor m_LineColor; + QPixmap m_InsertLeftImage; + QPixmap m_InsertRightImage; +}; +#endif // INCLUDED_INSERTION_LINE_H diff --git a/src/Authoring/Studio/Controls/InsertionOverlay.cpp b/src/Authoring/Studio/Controls/InsertionOverlay.cpp new file mode 100644 index 00000000..fc26f68c --- /dev/null +++ b/src/Authoring/Studio/Controls/InsertionOverlay.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** 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 "InsertionOverlay.h" +#include "Renderer.h" +#include "ResourceCache.h" + +//============================================================================= +/** + * Constructor + */ +CInsertionOverlay::CInsertionOverlay() + : m_Width(0) +{ + SetVisible(false); + + m_InsertLeftImage = CResourceCache::GetInstance()->GetBitmap("Insert-Left.png"); + m_InsertRightImage = CResourceCache::GetInstance()->GetBitmap("Insert-Right.png"); + + const auto theLeftSize = m_InsertLeftImage.size(); + const auto theRightSize = m_InsertRightImage.size(); + + if (theLeftSize.height() >= theRightSize.height()) + SetSize(CPt(theLeftSize.width() + theRightSize.width(), theLeftSize.height())); + else + SetSize(CPt(theLeftSize.width() + theRightSize.width(), theRightSize.height())); +} + +//============================================================================= +/** + * Destructor + */ +CInsertionOverlay::~CInsertionOverlay() +{ +} + +//============================================================================= +/** + * Sets the width of the control. The arrows are always drawn at the left + * and right side of the control, as defined by this width. + * @param inWidth total width of the control + */ +void CInsertionOverlay::SetWidth(long inWidth) +{ + m_Width = inWidth; + + SetSize(CPt(m_Width, GetSize().y)); +} + +//============================================================================= +/** + * Draws the insertion markers. + * Draws arrows at the left and right sides of the control, as defined by m_Width. + * @param inRenderer Renderer to draw to + */ +void CInsertionOverlay::Draw(CRenderer *inRenderer) +{ + // Left arrow + inRenderer->DrawBitmap(CPt(0, 0), m_InsertLeftImage); + + // Right arrow + const auto theRightSize = m_InsertRightImage.size(); + inRenderer->DrawBitmap(QPoint(m_Width - theRightSize.width(), 0), m_InsertRightImage); +} + +//============================================================================= +/** + * Check to see if inPoint is over this control or not. Overridden so that + * this overlay control does not interfere with drag-and-drop. + * @param inPoint not used + * @return false + */ +bool CInsertionOverlay::HitTest(const CPt &inPoint) const +{ + Q_UNUSED(inPoint); + + return false; +} diff --git a/src/Authoring/Studio/Controls/InsertionOverlay.h b/src/Authoring/Studio/Controls/InsertionOverlay.h new file mode 100644 index 00000000..0e43af3b --- /dev/null +++ b/src/Authoring/Studio/Controls/InsertionOverlay.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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_INSERTION_OVERLAY_H +#define INCLUDED_INSERTION_OVERLAY_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "OverlayControl.h" + +#include + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; + + +//============================================================================= +/** + * In drag-and-drop operations it's often desirable to indicate when you are + * dropping an item onto another item. This control gives that visual + * representation by drawing an arrow at either side. Example: Item2 is selected. + * + Item1 + * > + Item2 < + * + Item3 + */ +class CInsertionOverlay : public COverlayControl +{ +public: + CInsertionOverlay(); + virtual ~CInsertionOverlay(); + void SetWidth(long inWidth); + virtual void Draw(CRenderer *inRenderer); + virtual bool HitTest(const CPt &inPoint) const; + +protected: + long m_Width; + QPixmap m_InsertLeftImage; + QPixmap m_InsertRightImage; +}; +#endif // INCLUDED_INSERTION_OVERLAY_H diff --git a/src/Authoring/Studio/Controls/LazyFlow.cpp b/src/Authoring/Studio/Controls/LazyFlow.cpp new file mode 100644 index 00000000..8b8e74fe --- /dev/null +++ b/src/Authoring/Studio/Controls/LazyFlow.cpp @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** 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 "LazyFlow.h" +#include "ControlData.h" + +using namespace Q3DStudio::Control; + +template +struct SVisibleFilteredIterator +{ + TIteratorType m_BaseIterator; + SVisibleFilteredIterator(TIteratorType inIter) + : m_BaseIterator(inIter) + { + FindNextValidItem(); + } + void FindNextValidItem() + { + while (m_BaseIterator.IsDone() == false + && m_BaseIterator.GetCurrent()->IsVisible() == false) + ++m_BaseIterator; + } + + SVisibleFilteredIterator &operator++() + { + ++m_BaseIterator; + FindNextValidItem(); + return *this; + } + std::shared_ptr operator*() { return *m_BaseIterator; } + bool IsDone() { return m_BaseIterator.IsDone(); } +}; + +struct SaneMinMaxPref : public SSizeGroup +{ + SaneMinMaxPref(const SSizeGroup &inData) + : SSizeGroup(inData) + { + // ensure max and pref are greater than or equal to minimum + m_Pref.x = max(m_Pref.x, m_Min.x); + m_Pref.y = max(m_Pref.y, m_Min.y); + m_Max.x = max(m_Max.x, m_Min.x); + m_Max.y = max(m_Max.y, m_Min.y); + + // Ensure the maximum has valid information + if (m_Max.x == 0) + m_Max.x = m_Pref.x; + if (m_Max.y == 0) + m_Max.y = m_Pref.y; + + // Ensure preference is no greater than the maximum + m_Pref.x = min(m_Pref.x, m_Max.x); + m_Pref.y = min(m_Pref.y, m_Max.y); + } +}; + +CPt CLazyFlowBase::GetMinimumSize() +{ + MaybeRecalcMinMaxPerf(); + return CControl::GetMinimumSize(); +} +CPt CLazyFlowBase::GetPreferredSize() +{ + MaybeRecalcMinMaxPerf(); + return CControl::GetPreferredSize(); +} +CPt CLazyFlowBase::GetMaximumSize() +{ + MaybeRecalcMinMaxPerf(); + return CControl::GetMaximumSize(); +} + +void CLazyFlowBase::LayoutChildren() +{ + TControlSizeList theSizeList; + DistributeChildSizes(theSizeList); + PerformLayout(theSizeList); + Invalidate(); +} + +void CLazyFlowBase::MarkChildrenNeedLayout() +{ + m_MinMaxPreferredDirty = true; + CControl::MarkChildrenNeedLayout(); +} + +void CLazyFlowBase::NotifyParentNeedsLayout() +{ + if (m_CalculatingMinMaxPref == false) + CControl::NotifyParentNeedsLayout(); +} + +void CLazyFlowBase::SetLayout(CPt inSize, CPt inPosition) +{ + bool wasDirty = m_MinMaxPreferredDirty; + CControl::SetLayout(inSize, inPosition); + m_MinMaxPreferredDirty = wasDirty; +} + +long CLazyFlowBase::GetGapTotal() +{ + long theNumVisibleChildren = 0; + + // Ensure we don't count any gaps for children that are invisible + for (SVisibleFilteredIterator theIter = GetChildren(); + theIter.IsDone() == false; ++theIter, ++theNumVisibleChildren) { + } + + if (theNumVisibleChildren > 0) + return m_ChildGap * theNumVisibleChildren; + + return 0; +} + +void CLazyFlowBase::DistributeChildSizes(TControlSizeList &ioList) +{ + ILazyFlowLayoutSpecializer &theSpecializer(GetSpecializer()); + SSizeGroup theChildSizes(CalcChildrenMinMaxPref()); + CPt theMin(theChildSizes.m_Min); + CPt thePref(theChildSizes.m_Pref); + + CPt theSize = GetSize(); + long &theSizeSum(theSpecializer.GetSummedVariable(theSize)); + long &theSizeMax = theSpecializer.GetMaxedVariable(theSize); + + long theTotalInlineMargin = + ILazyFlowLayoutSpecializer::SafeSum(GetBeginMargin(), GetEndMargin()); + // long theTotalBesideMargin = ILazyFlowLayoutSpecializer::SafeSum( GetBeforeRowMargin(), + // GetAfterRowMargin() ); + long theGapTotal(GetGapTotal()); + // Remove child independent size information. + theSizeSum = theSizeSum - theGapTotal - theTotalInlineMargin; + theSizeMax = theSizeMax - GetBeforeRowMargin() - GetAfterRowMargin(); + + // sanitize the size after we remove the child indepedent size information + theSize.x = max(theMin.x, theSize.x); + theSize.y = max(theMin.y, theSize.y); + + // If we have more space than we can use. + if (theSizeSum >= theSpecializer.GetSummedVariable(thePref)) { + vector theResizeableChildren; + long theIndex = 0; + CPt theLayoutRect; + for (SVisibleFilteredIterator theIter = GetChildren(); + theIter.IsDone() == false; ++theIter, ++theIndex) { + std::shared_ptr theChildControl(*theIter); + SaneMinMaxPref saneSizes(GetChildSizes(*theIter)); + long theSaneMax(theSpecializer.GetMaxedVariable(saneSizes.m_Max)); + CPt newSize(theSpecializer.ToPoint(theSpecializer.GetSummedVariable(saneSizes.m_Pref), + min(theSizeMax, theSaneMax))); + theLayoutRect = theSpecializer.SumMax(theLayoutRect, newSize); + ioList.push_back(make_pair(theChildControl, newSize)); + if (theSpecializer.GetSummedVariable(saneSizes.m_Max) == LONG_MAX) + theResizeableChildren.push_back(theIndex); + } + + long theRectSum = theSpecializer.GetSummedVariable(theLayoutRect); + if (theResizeableChildren.size() && theSizeSum > theRectSum) { + long extra = (theSizeSum - theRectSum) / (long)theResizeableChildren.size(); + for (vector::iterator theIter = theResizeableChildren.begin(), + theEnd = theResizeableChildren.end(); + theIter != theEnd; ++theIter) { + pair, CPt> &theChildAndSize(ioList[*theIter]); + CPt theNewSize = theChildAndSize.second; + theNewSize = + theSpecializer.ToPoint(theSpecializer.GetSummedVariable(theNewSize) + extra, + theSpecializer.GetMaxedVariable(theNewSize)); + theChildAndSize.second = theNewSize; + } + } + } else { + long theMinSum = theSpecializer.GetSummedVariable(theMin); + long thePrefSum = theSpecializer.GetSummedVariable(thePref); + long minSizeX = max(theMinSum, theSizeSum); + // We know that we got less than the pref size. + long requestRange = thePrefSum - theMinSum; + long actualRange = minSizeX - theMinSum; + float ratio = 0.0f; + if (requestRange != 0) + ratio = (float)actualRange / (float)requestRange; + + // so we distribute the remaining to each object based on the ratio between + // its preferred size to its minimums size, thus reducing each object equally + // but on terms of the ratio between it's preferred size and minimum size. + for (SVisibleFilteredIterator theIter = GetChildren(); + theIter.IsDone() == false; ++theIter) { + SaneMinMaxPref saneSizes(GetChildSizes(*theIter)); + std::shared_ptr theChildControl(*theIter); + CPt childPref(saneSizes.m_Pref); + CPt childMin(saneSizes.m_Min); + long range = theSpecializer.GetSummedVariable(childPref) + - theSpecializer.GetSummedVariable(childMin); + long newRange = (long)((float)range * ratio + .5f); + long newMin = theSpecializer.GetSummedVariable(childMin); + CPt newSize = theSpecializer.ToPoint(newMin + newRange, theSizeMax); + ioList.push_back(make_pair(theChildControl, newSize)); + } + } +} + +void CLazyFlowBase::PerformLayout(TControlSizeList &ioList) +{ + ILazyFlowLayoutSpecializer &theSpecializer(GetSpecializer()); + CPt thePos(theSpecializer.ToPoint(GetBeginMargin(), GetBeforeRowMargin())); + long &theSummedVar = theSpecializer.GetSummedVariable(thePos); + + for (TControlSizeList::iterator iter = ioList.begin(), end = ioList.end(); iter != end; + ++iter) { + iter->first->SetLayout(iter->second, thePos); + // Bump the position out to the next object + theSummedVar += theSpecializer.GetSummedVariable(iter->second) + m_ChildGap; + } +} + +// Ignoring margins, calculate the min,max, and preferred sizes of the aggregate of our children +SSizeGroup CLazyFlowBase::CalcChildrenMinMaxPref() +{ + ILazyFlowLayoutSpecializer &theSpecializer(GetSpecializer()); + SSizeGroup retval; + for (SVisibleFilteredIterator theIter = GetChildren(); + theIter.IsDone() == false; ++theIter) { + SaneMinMaxPref saneSizes(GetChildSizes(*theIter)); + retval.m_Min = theSpecializer.SumMax(retval.m_Min, saneSizes.m_Min); + retval.m_Max = theSpecializer.SumMax(retval.m_Max, saneSizes.m_Max); + retval.m_Pref = theSpecializer.SumMax(retval.m_Pref, saneSizes.m_Pref); + } + return retval; +} + +void CLazyFlowBase::RecalcMinMaxPref() +{ + ILazyFlowLayoutSpecializer &theSpecializer(GetSpecializer()); + // Vertical means that we take the max of the x widths + // and sum the y heights; + // ensuring that LONG_MAX always sums to LONG_MAX + long theRowMargin = + ILazyFlowLayoutSpecializer::SafeSum(GetBeforeRowMargin(), GetAfterRowMargin()); + CPt theMin(theSpecializer.ToPoint(GetBeginMargin() + GetEndMargin(), theRowMargin)); + CPt theMax(theMin); + CPt thePref(theMin); + SSizeGroup theChildSizes(CalcChildrenMinMaxPref()); + theMin = theSpecializer.SumMax(theChildSizes.m_Min, theMin); + theMax = theSpecializer.SumMax(theChildSizes.m_Max, theMax); + thePref = theSpecializer.SumMax(theChildSizes.m_Pref, thePref); + + long theGapTotal(GetGapTotal()); + theMin = theSpecializer.ToPoint( + ILazyFlowLayoutSpecializer::SafeSum(theSpecializer.GetSummedVariable(theMin), theGapTotal), + ILazyFlowLayoutSpecializer::SafeSum(theSpecializer.GetMaxedVariable(theMin), theRowMargin)); + + thePref = theSpecializer.ToPoint( + ILazyFlowLayoutSpecializer::SafeSum(theSpecializer.GetSummedVariable(thePref), theGapTotal), + ILazyFlowLayoutSpecializer::SafeSum(theSpecializer.GetMaxedVariable(thePref), + theRowMargin)); + + theMax = theSpecializer.ToPoint( + ILazyFlowLayoutSpecializer::SafeSum(theSpecializer.GetSummedVariable(theMax), theGapTotal), + ILazyFlowLayoutSpecializer::SafeSum(theSpecializer.GetMaxedVariable(theMax), theRowMargin)); + + // Let's ensure we keep sane min,max,etc. + thePref.x = max(thePref.x, theMin.x); + thePref.y = max(thePref.y, theMin.y); + theMax.x = max(theMax.x, theMin.x); + theMax.y = max(theMax.y, theMin.y); + + SetMinimumSize(theMin); + SetPreferredSize(thePref); + SetMaximumSize(theMax); +} + +void CLazyFlowBase::MaybeRecalcMinMaxPerf() const +{ + if (m_MinMaxPreferredDirty) { + m_MinMaxPreferredDirty = false; + if (m_AutoMinMaxPref) { + m_CalculatingMinMaxPref = true; + CLazyFlowBase &flow(const_cast(*this)); + flow.RecalcMinMaxPref(); + m_CalculatingMinMaxPref = false; + } + } +} + +SSizeGroup CLazyFlowBase::GetChildSizes(std::shared_ptr inControl) +{ + SSizeGroup theGroup; + theGroup.m_Min = inControl->GetMinimumSize(); + theGroup.m_Max = inControl->GetMaximumSize(); + theGroup.m_Pref = inControl->GetPreferredSize(); + return theGroup; +} diff --git a/src/Authoring/Studio/Controls/LazyFlow.h b/src/Authoring/Studio/Controls/LazyFlow.h new file mode 100644 index 00000000..c5fb7fd3 --- /dev/null +++ b/src/Authoring/Studio/Controls/LazyFlow.h @@ -0,0 +1,267 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#pragma once +#ifndef LAZYFLOWH +#define LAZYFLOWH +#include "Control.h" + +#ifdef WIN32 +#include +#endif + +namespace Q3DStudio { +namespace Control { + + // Specializers used to specialize the layout algorithm in the X or Y direction. + // You could, in fact, specialzie the algorithm in any arbitrary direction including + // 3d where components are sumed in the chosen direction and maxed in any other + // orthogonal non-chosen directions. + + // Specializes the general layout algorithm in the x or y direction. + struct ILazyFlowLayoutSpecializer + { + protected: + virtual ~ILazyFlowLayoutSpecializer() {} + + public: + static inline long SafeSum(long lhs, long rhs) + { + if (lhs == LONG_MAX || rhs == LONG_MAX) + return LONG_MAX; + return lhs + rhs; + } + // These functions allow us to apply the lazy flow layout algorithm to + // either horizontal or vertical layouts. + // Sum the variable in the direction we are going, and max any other variables + CPt SumMax(const CPt &inCurrentSum, const CPt &inOther) + { + long curSum = GetSummedVariable(inCurrentSum); + long nextSum = GetSummedVariable(inOther); + long resultSum = SafeSum(curSum, nextSum); +#ifdef WIN32 + // windows.h redefines max + long resultMax = max(GetMaxedVariable(inCurrentSum), GetMaxedVariable(inOther)); +#else + long resultMax = std::max(GetMaxedVariable(inCurrentSum), GetMaxedVariable(inOther)); +#endif + return ToPoint(resultSum, resultMax); + } + // Return the summed variable + virtual long &GetSummedVariable(CPt &inPt) = 0; + const long &GetSummedVariable(const CPt &inPt) + { + return GetSummedVariable(const_cast(inPt)); + } + // return the maxed variable + virtual long &GetMaxedVariable(CPt &inPt) = 0; + const long &GetMaxedVariable(const CPt &inPt) + { + return GetMaxedVariable(const_cast(inPt)); + } + // Create a new point from the combination of a summed variable and a maxed variable. + virtual CPt ToPoint(long inSummedVariable, long inMaxedVariable) = 0; + }; + + struct SVerticalLayoutSpecializer : public ILazyFlowLayoutSpecializer + { + long &GetSummedVariable(CPt &inPt) override { return inPt.y; } + long &GetMaxedVariable(CPt &inPt) override { return inPt.x; } + CPt ToPoint(long inSummedVariable, long inMaxedVariable) override + { + return CPt(inMaxedVariable, inSummedVariable); + } + }; + + struct SHorizontalLayoutSpecializer : public ILazyFlowLayoutSpecializer + { + long &GetSummedVariable(CPt &inPt) override { return inPt.x; } + long &GetMaxedVariable(CPt &inPt) override { return inPt.y; } + CPt ToPoint(long inSummedVariable, long inMaxedVariable) override + { + return CPt(inSummedVariable, inMaxedVariable); + } + }; + + struct SSizeGroup + { + CPt m_Min; + CPt m_Max; + CPt m_Pref; + }; + + class CLazyFlowBase : public CControl + { + mutable bool m_MinMaxPreferredDirty; + mutable bool m_CalculatingMinMaxPref; + bool m_AutoMinMaxPref; + CPt m_BeginMargin; + CPt m_EndMargin; + + public: + typedef vector, CPt>> TControlSizeList; + + CLazyFlowBase() + : m_MinMaxPreferredDirty(true) + , m_CalculatingMinMaxPref(false) + , m_AutoMinMaxPref(true) + , m_ChildGap(0) + { + } + + CPt GetMinimumSize() override; + CPt GetPreferredSize() override; + CPt GetMaximumSize() override; + + virtual void SetGapBetweenChildren(long inGap) + { + m_ChildGap = inGap; + MarkChildrenNeedLayout(); + } + virtual long GetGapBetweenChildren() const { return m_ChildGap; } + + // Also sets min max preferred dirty. + void LayoutChildren() override; + void MarkChildrenNeedLayout() override; + void NotifyParentNeedsLayout() override; + void SetLayout(CPt inSize, CPt inPosition) override; + + virtual void SetAutoMinMaxPref(bool inAuto) { m_AutoMinMaxPref = inAuto; } + bool GetAutoMinMaxPref() const { return m_AutoMinMaxPref; } + + // Legacy with FlowLayout. + virtual void SetAutoMin(bool inAuto) { m_AutoMinMaxPref = inAuto; } + + virtual void SetTopMargin(long inPixels) + { + m_BeginMargin.y = inPixels; + MarkChildrenNeedLayout(); + } + virtual long GetTopMargin() const { return m_BeginMargin.y; } + + virtual void SetLeftMargin(long inPixels) + { + m_BeginMargin.x = inPixels; + MarkChildrenNeedLayout(); + } + virtual long GetLeftMargin() const { return m_BeginMargin.x; } + + virtual void SetBottomMargin(long inPixels) + { + m_EndMargin.y = inPixels; + MarkChildrenNeedLayout(); + } + virtual long GetBottomMargin() const { return m_EndMargin.y; } + + virtual void SetRightMargin(long inPixels) + { + m_EndMargin.x = inPixels; + MarkChildrenNeedLayout(); + } + virtual long GetRightMargin() const { return m_EndMargin.x; } + + protected: + void SetMinMaxPrefDirty() { m_MinMaxPreferredDirty = true; } + virtual ILazyFlowLayoutSpecializer &GetSpecializer() = 0; + + long m_ChildGap; + long GetGapTotal(); + // Margins are begin/end meaning before any children, after any children + long GetBeginMargin() { return GetSpecializer().GetSummedVariable(m_BeginMargin); } + long GetEndMargin() { return GetSpecializer().GetSummedVariable(m_EndMargin); } + // And then margines that are beside the row of children, either before the row or after it. + long GetBeforeRowMargin() { return GetSpecializer().GetMaxedVariable(m_BeginMargin); } + long GetAfterRowMargin() { return GetSpecializer().GetMaxedVariable(m_EndMargin); } + + // I only implement these algorithms once, and I use a specializer to make them apply + // to either a left-to-right or a top-to-bottom layout. + void DistributeChildSizes(TControlSizeList &ioList); + void PerformLayout(TControlSizeList &ioList); + SSizeGroup CalcChildrenMinMaxPref(); + + virtual SSizeGroup GetChildSizes(std::shared_ptr inControl); + + void RecalcMinMaxPref(); + void MaybeRecalcMinMaxPerf() const; + }; + + template + class TLazyFlowBase : public CLazyFlowBase + { + TSpecializerType m_Specializer; + + public: + ILazyFlowLayoutSpecializer &GetSpecializer() override { return m_Specializer; } + }; + + struct SVerticalLazyFlow : public TLazyFlowBase + { + }; + + struct SHorizontalLazyFlow : public TLazyFlowBase + { + }; + + class CRuntimeLazyFlow : public CLazyFlowBase + { + public: + enum EFlowDirection { + FLOW_VERTICAL, + FLOW_HORIZONTAL, + }; + + private: + SHorizontalLayoutSpecializer m_HorizontalSpecifier; + SVerticalLayoutSpecializer m_VerticalSpecifier; + EFlowDirection m_FlowDirection; + + public: + CRuntimeLazyFlow() + : m_FlowDirection(FLOW_VERTICAL) + { + } + + virtual void SetFlowDirection(EFlowDirection inFlowDirection) + { + m_FlowDirection = inFlowDirection; + MarkChildrenNeedLayout(); + } + + protected: + ILazyFlowLayoutSpecializer &GetSpecializer() override + { + if (m_FlowDirection == FLOW_VERTICAL) + return m_VerticalSpecifier; + return m_HorizontalSpecifier; + } + }; +} +} + +#endif diff --git a/src/Authoring/Studio/Controls/ListBoxItem.cpp b/src/Authoring/Studio/Controls/ListBoxItem.cpp new file mode 100644 index 00000000..885d8f87 --- /dev/null +++ b/src/Authoring/Studio/Controls/ListBoxItem.cpp @@ -0,0 +1,277 @@ +/**************************************************************************** +** +** 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 "ListBoxItem.h" +#include "Renderer.h" +#include "HotKeys.h" +#include "SystemPreferences.h" +#include "StudioPreferences.h" + +IMPLEMENT_OBJECT_COUNTER(CListBoxItem) + +//============================================================================== +/** + * Constructor + */ +CListBoxItem::CListBoxItem() + : m_Selected(false) + , m_BorderColor(CStudioPreferences::GetControlRectSideLineColor()) + , m_BackgroundColorSelected(CSystemPreferences::GetSelectedItemColor()) + , m_BackgroundColorUnselected(CColor(255, 255, 255)) +{ + ADDTO_OBJECT_COUNTER(CListBoxItem) + + // this reserves the minimum height for the ListBoxItem in the ListBox first + SetAbsoluteSize(CPt(0, CStudioPreferences::GetDefaultTextEditSize())); +} + +//============================================================================== +/** + * Destructor + */ +CListBoxItem::~CListBoxItem() +{ + REMOVEFROM_OBJECT_COUNTER(CListBoxItem) +} + +//============================================================================== +/** + * Draws the bounding rectangle and white edit box for the List Box Item class. + * + * @param inRenderer The renderer that is responsible for drawing this Item. + */ +void CListBoxItem::Draw(CRenderer *inRenderer) +{ + const auto rect = QRect(QPoint(0, 0), GetSize()); + inRenderer->PushClippingRect(rect); + + // Fill the interior of the ListBoxItem + CColor theFillColor = m_BackgroundColorUnselected; + + // If this ListBox is selected + if (m_Selected) + theFillColor = m_BackgroundColorSelected; + + inRenderer->FillSolidRect(rect, theFillColor); + + /* + CRct theRect = GetSize(); + CPt theLowerRight( theRect.position.x + theRect.size.x - 1, theRect.position.y + theRect.size.y + - 1 ); + CPt theLowerLeft( theRect.position.x, theLowerRight.y ); + + // draw the bottom line for this item; + // the top will be drawn by the prev item, otherwise it's the bounding box for the ListBox + inRenderer->PushPen( m_BorderColor, 1 ); + inRenderer->MoveTo( theLowerLeft ); + inRenderer->LineTo( theLowerRight ); + inRenderer->PopPen(); + */ + + inRenderer->PopClippingRect(); +} + +//============================================================================= +/** + * Handles Mouse down events on this CListBoxItem. When a Mouse Click occurs + * on this ListBoxItem, fire off a SelectionEvent, to let the parent + * CListBoxControl know that this is selected, and to perform neccesary selection + * actions, e.g. Single Selection, or Multiple Selection. + * + * @param inPoint where the mouse was clicked, in local coordinates. + * @param inFlags Modifier keys that are down at time of event. Can be any + * combination of the following: MODIFIER_CONTROL | MODIFIER_SHIFT | + * MODIFIER_ALT | MOUSE_LBUTTON | MOUSE_RBUTTON | MOUSE_MBUTTON + */ +bool CListBoxItem::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theIsHandled = CControl::OnMouseDown(inPoint, inFlags); + m_SelectionListeners.FireEvent(&CListBoxSelectionListener::OnSelectItem, this, inFlags); + return theIsHandled; +} + +//============================================================================== +/** + * Overridden to help recalc the minimum size of the item + */ +void CListBoxItem::OnParentChanged(CControl *inParent) +{ + CControl::OnParentChanged(inParent); + RecalcMinimumSize(); +} + +//============================================================================== +/** + * Overridden to help recalc the minimum size of the item + */ +void CListBoxItem::SetMinimumSize(CPt inSize) +{ + CControl::SetMinimumSize(inSize); + RecalcMinimumSize(); +} + +//============================================================================== +/** + * Set the minimum width of the item based on the size of the parent + */ +void CListBoxItem::RecalcMinimumSize() +{ + if (GetParent()) { + CPt theSize = CControl::GetMinimumSize(); + CPt theParentSize = GetParent()->GetSize(); + + // If the minimum width of the item is less than the + // current width of the parent, set the size to be the + // width of the parent + if (theParentSize.x > (theSize.x - GetPosition().x)) + theSize.x = theParentSize.x - GetPosition().x; + + CControl::SetMinimumSize(theSize); + } +} + +//============================================================================== +/** + * Sets this ListBoxItem to be selected or unselected. + * + * @param inSelected True if this CListBoxItem is selected. + */ +void CListBoxItem::SetSelectedState(bool inSelected) +{ + m_Selected = inSelected; + Invalidate(); +} + +//============================================================================== +/** + * Returns true if this ListBoxItem is selected. + * + * @return true if this CListBoxItem is selected. + */ +bool CListBoxItem::IsSelected() const +{ + return m_Selected; +} + +//============================================================================== +/** + * Sets the color of this control's border. Defines the color of the bounding + * rectangle. + * + * @param inColor the Color of this control's border. + */ +void CListBoxItem::SetBorderColor(const CColor &inColor) +{ + m_BorderColor = inColor; +} + +//============================================================================== +/** + * Returns the color of this control's border. + * + * @return the color of the border of this control. + */ +CColor CListBoxItem::GetBorderColor() const +{ + return m_BorderColor; +} + +//============================================================================== +/** + * Sets the background color for the ListBoxItem when it is selected. + * + * @param inColor the background color for the ListBoxItem when it is selected. + */ +void CListBoxItem::SetBGColorSelected(const CColor &inColor) +{ + m_BackgroundColorSelected = inColor; +} + +//============================================================================== +/** + * Returns the background color for the ListBoxItem when it is selected. + * + * @return the background color for the ListBoxItem when it is selected. + */ +CColor CListBoxItem::GetBGColorSelected() const +{ + return m_BackgroundColorSelected; +} + +//============================================================================== +/** + * Sets the background color for the ListBoxItem when it is not selected. + * + * @param inColor the background color for the ListBoxItem when it is not selected. + */ +void CListBoxItem::SetBGColorUnselected(const CColor &inColor) +{ + m_BackgroundColorUnselected = inColor; +} + +//============================================================================== +/** + * Returns the background color for the ListBoxItem when it is not selected. + * + * @return the background color for the ListBoxItem when it is not selected. + */ +CColor CListBoxItem::GetBGColorUnselected() const +{ + return m_BackgroundColorUnselected; +} + +//============================================================================== +/** + * Add a SelectionListener to this control's list of SelectionListeners. + * + * @param inListener The SelectionListener to add to the list of SelectionListeners + */ +void CListBoxItem::AddSelectionListener(CListBoxSelectionListener *inListener) +{ + m_SelectionListeners.AddListener(inListener); +} + +//============================================================================== +/** + * Remove a SelectionListener from this control's list of SelectionListeners. + * + * @param inListener The SelectionListener to remove from the list of SelectionListeners + */ +void CListBoxItem::RemoveSelectionListener(CListBoxSelectionListener *inListener) +{ + m_SelectionListeners.RemoveListener(inListener); +} diff --git a/src/Authoring/Studio/Controls/ListBoxItem.h b/src/Authoring/Studio/Controls/ListBoxItem.h new file mode 100644 index 00000000..26e1ecb9 --- /dev/null +++ b/src/Authoring/Studio/Controls/ListBoxItem.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** 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_LIST_BOX_ITEM_H +#define INCLUDED_LIST_BOX_ITEM_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" +#include "FlowLayout.h" +#include "Multicaster.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; +class CListBoxItem; + +//============================================================================== +// Functor +//============================================================================== +GENERIC_FUNCTOR_2(CListBoxSelectionListener, OnSelectItem, CListBoxItem *, long); + +//============================================================================== +/** + * abstract CListBoxItem base class that all other ListBoxItem classes + * must inherit from. e.g. CListBoxStringItem, CActionListBoxItem + */ +class CListBoxItem : public CControl +{ +public: + CListBoxItem(); + virtual ~CListBoxItem(); + + DEFINE_OBJECT_COUNTER(CListBoxItem) + + virtual Q3DStudio::CString GetString() = 0; ///< returns the string representation of this item + + void Draw(CRenderer *inRenderer) override; + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnParentChanged(CControl *inParent) override; + void SetMinimumSize(CPt inSize) override; + + virtual void SetSelectedState(bool inSelected); + virtual void RecalcMinimumSize(); + bool IsSelected() const; + + // Color Accessors / Mutators + void SetBorderColor(const CColor &inColor); + CColor GetBorderColor() const; + void SetBGColorSelected(const CColor &inColor); + CColor GetBGColorSelected() const; + void SetBGColorUnselected(const CColor &inColor); + CColor GetBGColorUnselected() const; + + // SelectionListener methods + void AddSelectionListener(CListBoxSelectionListener *inListener); + void RemoveSelectionListener(CListBoxSelectionListener *inListener); + +protected: + bool m_Selected; + CColor m_BorderColor; + QColor m_BackgroundColorSelected; + CColor m_BackgroundColorUnselected; + CMulticaster + m_SelectionListeners; ///< Usually only just the ListBoxControl owning this item +}; + +#endif // INCLUDED_LIST_BOX_ITEM_H diff --git a/src/Authoring/Studio/Controls/ListBoxStringItem.cpp b/src/Authoring/Studio/Controls/ListBoxStringItem.cpp new file mode 100644 index 00000000..d8efe02b --- /dev/null +++ b/src/Authoring/Studio/Controls/ListBoxStringItem.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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 +//============================================================================== +#include "ListBoxStringItem.h" +#include "Renderer.h" +#include "SystemPreferences.h" + +//============================================================================== +/** + * Constructor + * + * A ListBoxStringItem contains an immutable StringEdit, extending the base + * class ListBoxItem to give basic String display and containing funtionality. + * TODO: Need to implement some way to set the alignment of the text. + * Right now, setting the alignment makes the drawing of the control + * all dirty. That's why it's taken out, for now. + * + * @param inString the String which this ListBoxStringItem is to hold + */ +CListBoxStringItem::CListBoxStringItem() + : m_TextColor(0, 0, 0) + , m_SelectedTextColor(CSystemPreferences::GetSelectedTextColor()) +{ + m_StringEdit.SetReadOnly(true); + m_StringEdit.AllowAutoSize(true); + m_StringEdit.SetAlignment(CTextEdit::LEFT); + m_StringEdit.SetFillBackground(false); + m_StringEdit.SetTextColor(m_TextColor); + AddChild(&m_StringEdit); +} + +//============================================================================== +/** + * Destructor + */ +CListBoxStringItem::~CListBoxStringItem() +{ +} + +//============================================================================== +/** + * @return the String that this ListBoxStringItem contains + */ +void CListBoxStringItem::SetString(const Q3DStudio::CString &inString) +{ + m_StringEdit.SetData(inString, false); + + SetMinimumSize(m_StringEdit.GetSize()); + SetSize(m_StringEdit.GetSize()); +} + +//============================================================================== +/** + * @return the String that this ListBoxStringItem contains + */ +Q3DStudio::CString CListBoxStringItem::GetString() +{ + return m_StringEdit.GetString(); +} + +//============================================================================= +/** + * Overridden so that we can change the color of the text based upon selection. + * @param inSelected true to select this item, false to deselect it + */ +void CListBoxStringItem::SetSelectedState(bool inSelected) +{ + CListBoxItem::SetSelectedState(inSelected); + + if (inSelected) + m_StringEdit.SetTextColor(m_SelectedTextColor); + else + m_StringEdit.SetTextColor(m_TextColor); +} diff --git a/src/Authoring/Studio/Controls/ListBoxStringItem.h b/src/Authoring/Studio/Controls/ListBoxStringItem.h new file mode 100644 index 00000000..e950d494 --- /dev/null +++ b/src/Authoring/Studio/Controls/ListBoxStringItem.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_LIST_BOX_STRING_ITEM_H +#define INCLUDED_LIST_BOX_STRING_ITEM_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +#include "ListBoxItem.h" +#include "StringEdit.h" + +//============================================================================== +// Forwards +//============================================================================== + +//============================================================================== +/** + * CListBoxStringItem contains an immutable StringEdit, extending the base + * class ListBoxItem to give basic String displaying and storage. + */ +class CListBoxStringItem : public CListBoxItem +{ +public: + CListBoxStringItem(); + virtual ~CListBoxStringItem(); + + virtual void SetString(const Q3DStudio::CString &inString); + virtual Q3DStudio::CString GetString(); ///< returns the string representation of this item + + virtual void SetSelectedState(bool inSelected); ///< Overridden so that we can change the color + ///of the text based upon selection + +protected: + CStringEdit m_StringEdit; + CColor m_TextColor; + CColor m_SelectedTextColor; +}; + +#endif // INCLUDED_LIST_BOX_STRING_ITEM_H \ No newline at end of file diff --git a/src/Authoring/Studio/Controls/ListLayout.cpp b/src/Authoring/Studio/Controls/ListLayout.cpp new file mode 100644 index 00000000..912cec13 --- /dev/null +++ b/src/Authoring/Studio/Controls/ListLayout.cpp @@ -0,0 +1,185 @@ +/**************************************************************************** +** +** 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 "ListLayout.h" +#include "MasterP.h" +#include "ControlData.h" + +using namespace Q3DStudio; +using namespace Q3DStudio::Control; + +CListLayout::CListLayout(bool inAlignChildrenLength /*= false */) + : m_IsResizing(false) + , m_AlignChildrenLength(inAlignChildrenLength) +{ +} + +CListLayout::~CListLayout() +{ +} + +//============================================================================= +/** + * Add a child to this control. + * Overrides to make the layout get recalculated as well. + * @param inChild the child to be added. + * @param inInsertBefore the location to be added. + * @see CControl::AddChild. + */ +void CListLayout::AddChild(CControl *inChild, CControl *inInsertBefore /*= nullptr*/) +{ + CControl::AddChild(inChild, inInsertBefore); + + RecalcLayout(); +} + +//============================================================================= +/** + * Remove a child from this control. + * Overrides to make the layout get recalculated as well. + * @param inChild the child to be removed. + * @see CControl::RemoveChild. + */ +void CListLayout::RemoveChild(CControl *inChild) +{ + CControl::RemoveChild(inChild); + RecalcLayout(); +} + +//============================================================================= +/** + * Set the size of this control. + * Overrides CControl::SetSize to propagate down to children too. + * @param inSize the new size. + */ +void CListLayout::SetSize(CPt inSize) +{ + if (inSize.x != GetSize().x) { + m_IsResizing = true; + + // Go through all the children and set their sizes too + ControlGraph::SIterator theChildren = GetChildren(); + for (; theChildren.HasNext(); ++theChildren) { + std::shared_ptr theChild = (*theChildren); + if (theChild->IsVisible()) { + // Only care about the width, keep the height the same. + theChild->SetSize(inSize.x, theChild->GetSize().y); + } + } + m_IsResizing = false; + } + + CControl::SetSize(inSize); +} + +//============================================================================= +/** + * Recalculate the layout of all the sub controls. + * This will resize this control appropriately and reposition all the children. + */ +void CListLayout::RecalcLayout() +{ + m_IsResizing = true; + + long theHeight = 0; + CPt theCurrentPos(0, 0); + long theMinLen = 0; + + ControlGraph::SIterator theChildren = GetChildren(); + if (m_AlignChildrenLength) { + // Go through the first time to determine what is the minimum length for the children + for (; theChildren.HasNext(); ++theChildren) { + std::shared_ptr theChild = (*theChildren); + // Only handle visible children + if (theChild->IsVisible()) { + CPt theMinimumSize(theChild->GetMinimumSize()); + if (theMinimumSize.x > theMinLen) + theMinLen = theMinimumSize.x; + } + } + // reset this + theChildren = GetChildren(); + } + + // Go through all the children and set their position, as well as the minimum length if required + // to + for (; theChildren.HasNext(); ++theChildren) { + std::shared_ptr theChild = (*theChildren); + // Only handle visible children + if (theChild->IsVisible()) { + CPt theChildSize = theChild->GetSize(); + theHeight += theChildSize.y; + + if (m_AlignChildrenLength) + theChild->SetSize(CPt(theMinLen, theChildSize.y)); + else { // this would be the only loop to get the minimum length + CPt theMinimumSize(theChild->GetMinimumSize()); + if (theMinimumSize.x > theMinLen) + theMinLen = theMinimumSize.x; + } + + // Update the position + theChild->SetPosition(theCurrentPos); + theCurrentPos.y += theChildSize.y; + } + } + + SetMinimumSize(CPt(theMinLen, theHeight)); + SetMaximumSize(CPt(LONG_MAX, theHeight)); + + SetSize(CPt(theMinLen, theHeight)); + + m_IsResizing = false; +} + +//============================================================================= +/** + * Notification to this control that one of the child controls has changed size. + * @param inControl the control that changed size. + */ +void CListLayout::OnChildSizeChanged(CControl *inControl) +{ + Q_UNUSED(inControl); + + // If we are not actively resizing then redo the layout. + if (!m_IsResizing) { + UICPROFILE(OnChildSizeChanged); + + RecalcLayout(); + } +} + +#ifdef _DEBUG +bool CListLayout::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + return CControl::OnMouseDown(inPoint, inFlags); +} +#endif \ No newline at end of file diff --git a/src/Authoring/Studio/Controls/ListLayout.h b/src/Authoring/Studio/Controls/ListLayout.h new file mode 100644 index 00000000..3b1d7768 --- /dev/null +++ b/src/Authoring/Studio/Controls/ListLayout.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_LIST_LAYOUT_H +#define INCLUDED_LIST_LAYOUT_H 1 + +#pragma once + +#include "Control.h" + +class CListLayout : public CControl +{ +public: + CListLayout(bool inAlignChildrenLength = false); + virtual ~CListLayout(); + + void SetSize(CPt inSize) override; + + void AddChild(CControl *inChild, CControl *inInsertBefore = nullptr) override; + void RemoveChild(CControl *inChild) override; + + void OnChildSizeChanged(CControl *inControl) override; + + void RecalcLayout(); + +#ifdef _DEBUG + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; +#endif + +protected: + bool m_IsResizing; + bool m_AlignChildrenLength; ///< True when all children in this list should align up +}; +#endif // INCLUDED_LIST_LAYOUT_H diff --git a/src/Authoring/Studio/Controls/NameEdit.cpp b/src/Authoring/Studio/Controls/NameEdit.cpp new file mode 100644 index 00000000..b8cface6 --- /dev/null +++ b/src/Authoring/Studio/Controls/NameEdit.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** 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 "NameEdit.h" +#include "INamable.h" + +//============================================================================= +/** + * Constructor + * @param inPropertyProvider interface that will provide properties by name + * (such as a CAsset object). Can be nullptr. + */ +CNameEdit::CNameEdit(INamable *inNamable) + : m_Namable(inNamable) + , m_IsSettingData(false) + , m_LastMoustDown(0, 0) + , m_LastFocused(true) + , m_CanEdit(false) +{ + ASSERT(m_Namable); // if you don't have a namable, use CTextEditInPlace instead. + + SetData(m_Namable->GetName(), false); + AddCommitListener(this); + AllowAutoSize(true); +} + +//============================================================================= +/** + * Destructor + */ +CNameEdit::~CNameEdit() +{ + RemoveCommitListener(this); +} + +//============================================================================= +/** + * Called when a CTextEdit control's data is changed. In this case, the name + * field is being changed, so the new value is pushed down to Client. + * @param inControl the control that had it's data changed + */ +void CNameEdit::OnSetData(CControl *inControl) +{ + if (!m_IsSettingData && inControl == this && m_Namable) { + if (m_Namable->GetName() != GetString()) { + m_IsSettingData = true; + m_Namable->SetName(GetString()); + m_IsSettingData = false; + + // Refresh what it is in m_Nameable, because the UI data is already changed and the + // underlying data model may not agree ( ie not accepting empty or renaming isn't + // allowed ) + // Ideally UI shouldn't change, it should informing the data model through some kind of + // transaction (like how blackfish does it) + SetData(m_Namable->GetName(), false); + } + } +} + +//============================================================================= +/** + * Called when something on an asset changes, making it dirty. Resets the name + * displayed by this control, in case it was the name that changed on the asset. + */ +void CNameEdit::OnDirty() +{ + SetData(m_Namable->GetName()); + RefreshDisplayFromData(); +} + +bool CNameEdit::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + m_LastMoustDown = inPoint; + m_CanEdit = !m_LastFocused; + + return CTextEditInPlace::OnMouseDown(inPoint, inFlags); +} + +void CNameEdit::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (IsInFocus() && !m_IsInEditMode && !(inFlags & CHotKeys::MOUSE_RBUTTON)) { + if (m_CanEdit && m_LastMoustDown == inPoint) { + SetEditMode(true); + SelectAllText(); + } + } else { + CTextEditInPlace::OnMouseUp(inPoint, inFlags); + } + + m_CanEdit = false; +} + +void CNameEdit::OnGainFocus() +{ + CTextEditInPlace::OnGainFocus(); + m_LastFocused = false; +} + +void CNameEdit::OnLoseFocus() +{ + m_LastFocused = true; + CTextEditInPlace::OnLoseFocus(); +} diff --git a/src/Authoring/Studio/Controls/NameEdit.h b/src/Authoring/Studio/Controls/NameEdit.h new file mode 100644 index 00000000..cf54bb35 --- /dev/null +++ b/src/Authoring/Studio/Controls/NameEdit.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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_NAME_EDIT +#define INCLUDED_NAME_EDIT 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "TextEditInPlace.h" + +class INamable; + +//============================================================================= +/** + * @class CNameEdit Edit control for statically displaying a "name" property. + * Double-clicking on the text enables you to edit it. Changes to the underlying + * name property are automatically handled by this control. + */ +class CNameEdit : public CTextEditInPlace, public CCommitDataListener +{ +public: + CNameEdit(INamable *inNamable); + virtual ~CNameEdit(); + void OnSetData(CControl *inControl) override; + virtual void OnDirty(); + + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnGainFocus() override; + void OnLoseFocus() override; + +protected: + INamable *m_Namable; + bool m_IsSettingData; + + CPt m_LastMoustDown; + bool m_LastFocused; + bool m_CanEdit; +}; + +#endif // INCLUDED_NAME_EDIT diff --git a/src/Authoring/Studio/Controls/OverlayControl.cpp b/src/Authoring/Studio/Controls/OverlayControl.cpp new file mode 100644 index 00000000..cca9b402 --- /dev/null +++ b/src/Authoring/Studio/Controls/OverlayControl.cpp @@ -0,0 +1,240 @@ +/**************************************************************************** +** +** 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 "OverlayControl.h" +#include "Renderer.h" + +IMPLEMENT_OBJECT_COUNTER(COverlayControl) + +//============================================================================= +/** + * Create a new OverlayControl. + */ +COverlayControl::COverlayControl() + : m_HasSizeChanged(false) + , m_WasVisible(false) + , m_Alpha(255) +{ + ADDTO_OBJECT_COUNTER(COverlayControl) +} + +COverlayControl::~COverlayControl() +{ + REMOVEFROM_OBJECT_COUNTER(COverlayControl) +} + +//============================================================================= +/** + * Notification from the parent control that it is going to begin drawing children. + * This is used to erase this component before the children are drawn. + * @param inRenderer the renderer that is being drawn to. + */ +void COverlayControl::BeginDrawChildren(CRenderer *inRenderer) +{ + const auto size = GetParent()->GetSize(); + QRect theClippingRect(0, 0, size.x, size.y); + +// doing this = lockup on MacX. +// not doing this = playhead redraw errors on Windows +#ifdef WIN32 + inRenderer->PushClippingRect(theClippingRect); +#endif + // If we don't have a renderer then create one. + if (IsVisible() && m_BufferedRenderer == NULL) { + m_BufferedRenderer = new CBufferedRenderer(QSize(size.x, size.y)); + } + + else if (m_HasSizeChanged && m_BufferedRenderer != NULL) { + CRct theRect(m_PreviousSize); + theRect.Offset(-m_PositionOffset + GetPosition()); + + // Overwrite the current contents, clearing this object's drawing. + inRenderer->BitBltFrom(theRect, m_BufferedRenderer, 0, 0); + + m_HasSizeChanged = false; + + m_BufferedRenderer = new CBufferedRenderer(QSize(size.x, size.y)); + } + + else { + if ((IsVisible() || m_WasVisible) && m_BufferedRenderer != NULL) { + // If this moved since the last begin draw then take in that offset too. + CRct theRect(GetSize()); + theRect.Offset(-m_PositionOffset + GetPosition()); + + // Overwrite the current contents, clearing this object's drawing. + inRenderer->BitBltFrom(theRect, m_BufferedRenderer, 0, 0); + + if (m_WasVisible) + m_BufferedRenderer = nullptr; + + m_WasVisible = false; + } + } + + m_PositionOffset.x = 0; + m_PositionOffset.y = 0; + +#ifdef WIN32 + inRenderer->PopClippingRect(); +#endif +} + +//============================================================================= +/** + * Overrides OnDraw to perform custom drawing logic. + * This basically needs to draw all the time regardless of invalidation. + * The dirty rect will be properly updated if this is dirty. + * @param inRenderer the renderer to draw to. + * @param inDirtyRect the resulting dirty rect from drawing. + * @param inIgnoreValidation true if this should draw everything. + */ +void COverlayControl::OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation) +{ + CRct theClippingRect(-GetPosition(), GetParent()->GetSize()); + inRenderer->PushClippingRect(theClippingRect); + + if (IsVisible() && m_BufferedRenderer != nullptr) { + // Copy the current contents of the background. + m_BufferedRenderer->BitBltFrom(CRct(GetSize()), inRenderer, 0, 0); + + bool isInvalidated = IsInvalidated(); + + if (isInvalidated || inIgnoreValidation) { + // If this is invalidated then update the dirty rect appropriately + CRct theBoundingBox = inRenderer->GetClippingRect(); + + CRct theRect(GetSize()); + theRect.And(theBoundingBox); + theRect.Offset(inRenderer->GetTranslation()); + inDirtyRect.Or(theRect); + } + + // if ( m_Alpha != 255 ) + //{ + // DrawAlpha( inRenderer ); + //} + // else + { + // Always draw this component to the renderer, regardless of whether it's dirty or not. + Draw(inRenderer); + } + + Invalidate(false); + } + CControl::OnDraw(inRenderer, inDirtyRect, inIgnoreValidation); + + inRenderer->PopClippingRect(); +} + +//============================================================================= +/** + * Handles drawing this control as being transparent. + * @param inRenderer the renderer to draw to. + */ +void COverlayControl::DrawAlpha(CRenderer * /*inRenderer*/) +{ + /* // Copy the contents of the current background, this will make it so only the areas + // that are drawn to are actually blended + BUFFEREDRENDERERTYPE theIntermediate( m_BufferedRenderer, + m_BufferedRenderer->GetClippingRect() ); + Draw( &theIntermediate ); + + // Do the transparent draw. + theIntermediate.TransparentBltTo( inRenderer, m_Alpha );*/ +} + +//============================================================================= +/** + * Logs the changes in position so that it can properly reset the background. + * @param inPosition the new position. + */ +void COverlayControl::SetPosition(CPt inPosition) +{ + if (inPosition != GetPosition()) { + // Offset the position, make it relative just in case multiple changes occur per cycle. + m_PositionOffset += inPosition - GetPosition(); + + CControl::SetPosition(inPosition); + } +} + +//============================================================================= +/** + * Override of SetSize so that the renderer can be ditched. + * @param inSize the new size of this control. + */ +void COverlayControl::SetSize(CPt inSize) +{ + if (inSize != GetSize()) { + // Record how big this was so the previous drawing can be erased. + if (!m_HasSizeChanged && m_BufferedRenderer != nullptr) { + m_HasSizeChanged = true; + m_PreviousSize = GetSize(); + } + + CControl::SetSize(inSize); + } +} + +//============================================================================= +/** + * Set whether or not this control is visible. + * Override to handle final clearing of this control when not visible. + * @param inIsVisible true if this is to be visible. + */ +void COverlayControl::SetVisible(bool inIsVisible) +{ + if (!inIsVisible && IsVisible()) { + m_WasVisible = true; + } + CControl::SetVisible(inIsVisible); +} + +//============================================================================= +/** + * Set the alpha blend of this control. + * This defaults to 255 which is opaque, if it is anything other than 255 then + * this control will be drawn with transparency. + * @param inAlpha the new opacity, 255 = opaque, 0 = transparent. + */ +void COverlayControl::SetAlpha(short inAlpha) +{ + m_Alpha = inAlpha; +} + +bool COverlayControl::IsChildInvalidated() const +{ + return true; +} diff --git a/src/Authoring/Studio/Controls/OverlayControl.h b/src/Authoring/Studio/Controls/OverlayControl.h new file mode 100644 index 00000000..9ad622f8 --- /dev/null +++ b/src/Authoring/Studio/Controls/OverlayControl.h @@ -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 +//============================================================================= +#ifndef INCLUDED_OVERLAY_CONTROL_H +#define INCLUDED_OVERLAY_CONTROL_H 1 + +#pragma once + +//============================================================================= +// Includes +//============================================================================= +#include "Control.h" + +//============================================================================= +// Forwards +//============================================================================= + +#include "BufferedRenderer.h" +#include "UICObjectCounter.h" + +//============================================================================= +/** + * Overlay control provides a way to a control on top of another and move it + * around. The drawing is handled so that you do not need to invalidate the + * bottom control and you don't get trails to forming on the bottom control. + * This is accomplished through the use of a buffered renderer. + */ +class COverlayControl : public CControl +{ +public: + COverlayControl(); + virtual ~COverlayControl(); + + DEFINE_OBJECT_COUNTER(COverlayControl) + + virtual void SetSize(CPt inSize); + virtual void SetPosition(CPt inPosition); + virtual void OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation = false); + virtual void BeginDrawChildren(CRenderer *inRenderer); + virtual void SetVisible(bool inIsVisible); + void SetAlpha(short inAlpha); + virtual bool IsChildInvalidated() const; + +protected: + void DrawAlpha(CRenderer *inRenderer); + + CPt m_PositionOffset; + Q3DStudio::CAutoMemPtr m_BufferedRenderer; + bool m_HasSizeChanged; + CPt m_PreviousSize; + bool m_WasVisible; + short m_Alpha; +}; +#endif // INCLUDED_OVERLAY_CONTROL_H diff --git a/src/Authoring/Studio/Controls/ProceduralButton.h b/src/Authoring/Studio/Controls/ProceduralButton.h new file mode 100644 index 00000000..47b39046 --- /dev/null +++ b/src/Authoring/Studio/Controls/ProceduralButton.h @@ -0,0 +1,569 @@ +/**************************************************************************** +** +** 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_PROCEDURAL_BUTTON_H +#define INCLUDED_PROCEDURAL_BUTTON_H 1 +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Renderer.h" +#include "ButtonControl.h" +#include "StudioPreferences.h" + +//============================================================================= +/** + * Template class for making procedural buttons. A procedural button has + * additional drawing options compared to a normal button. You must specify + * a derivative of CButtonControl as the class for the procedural button to + * extend. + */ +template +class CProceduralButton : public TButton +{ +public: + /// Fill color styles for procedurally drawn buttons + enum EFillStyle { + EFILLSTYLE_GRADIENT, ///< Button background is filled using a gradient + EFILLSTYLE_FLOOD, ///< Button background is filled in a solid color + EFILLSTYLE_NONE ///< Button background is not filled at all + }; + + /// Struct enabling you to specify whether or not to draw each border of the button individually + struct SBorderOptions + { + bool m_DrawLeft; ///< If true, you want the left border to be drawn + bool m_DrawTop; ///< If true, you want the top border to be drawn + bool m_DrawRight; ///< If true, you want the right border to be drawn + bool m_DrawBottom; ///< If true, you want the bottom border to be drawn + + /// Default Constructor - makes all borders be drawn + SBorderOptions() + { + m_DrawLeft = true; + m_DrawTop = true; + m_DrawRight = true; + m_DrawBottom = true; + } + + /// Constructor to initialize each member of the struct individually + SBorderOptions(bool inLeft, bool inTop, bool inRight, bool inBottom) + { + m_DrawLeft = inLeft; + m_DrawTop = inTop; + m_DrawRight = inRight; + m_DrawBottom = inBottom; + } + }; + +public: + CProceduralButton(); + virtual ~CProceduralButton(); + + void SetFillStyleUp(EFillStyle inStyle); + void SetFillStyleDown(EFillStyle inStyle); + void SetFillStyleDisabled(EFillStyle inStyle); + void SetFillStyleOver(EFillStyle inStyle); + void SetFillStyleAll(EFillStyle inStyle); + void SetFillColorUp(const CColor &inColor); + void SetFillColorDown(const CColor &inColor); + void SetFillColorDisabled(const CColor &inColor); + void SetFillColorOver(const CColor &inColor); + + void SetBorderVisibilityAll(const SBorderOptions &inBorderOptions); + void SetBorderVisiblityUp(const SBorderOptions &inBorderOptions); + void SetBorderVisiblityDown(const SBorderOptions &inBorderOptions); + void SetBorderVisiblityDisabled(const SBorderOptions &inBorderOptions); + void SetBorderVisiblityOver(const SBorderOptions &inBorderOptions); + + void SetLeftBorderColor(const CColor &inColor); + void SetTopBorderColor(const CColor &inColor); + void SetRightBorderColor(const CColor &inColor); + void SetBottomBorderColor(const CColor &inColor); + +protected: + virtual void Render(CRenderer *inRenderer); + void DrawBackground(CRenderer *inRenderer); + void DrawBorder(CRenderer *inRenderer); + EFillStyle GetCurrentFillStyle(); + CColor GetCurrentBackgroundColor(); + SBorderOptions GetCurrentBorderOptions(); + +protected: + EFillStyle m_UpFillStyle; + EFillStyle m_DownFillStyle; + EFillStyle m_DisabledFillStyle; + EFillStyle m_OverFillStyle; + CColor m_UpColor; + CColor m_DownColor; + CColor m_DisabledColor; + CColor m_OverColor; + CColor m_LeftBorderColor; + CColor m_TopBorderColor; + CColor m_RightBorderColor; + CColor m_BottomBorderColor; + SBorderOptions m_UpBorders; + SBorderOptions m_DownBorders; + SBorderOptions m_DisabledBorders; + SBorderOptions m_OverBorders; +}; + +//============================================================================== +// Template implemenations +//============================================================================== + +//============================================================================= +/** + * Constructor + */ +template +CProceduralButton::CProceduralButton() + : TButton() + , m_UpFillStyle(EFILLSTYLE_GRADIENT) + , m_DownFillStyle(EFILLSTYLE_GRADIENT) + , m_DisabledFillStyle(EFILLSTYLE_NONE) + , m_OverFillStyle(EFILLSTYLE_GRADIENT) + , m_UpColor(CStudioPreferences::GetBaseColor()) + , m_DownColor(CStudioPreferences::GetButtonDownColor()) + , m_DisabledColor(CStudioPreferences::GetBaseColor()) + , m_OverColor(CStudioPreferences::GetBaseColor()) + , m_LeftBorderColor(CStudioPreferences::GetButtonShadowColor()) + , m_TopBorderColor(CStudioPreferences::GetButtonShadowColor()) + , m_RightBorderColor(CStudioPreferences::GetButtonShadowColor()) + , m_BottomBorderColor(CStudioPreferences::GetButtonShadowColor()) +{ +} + +//============================================================================= +/** + * Destructor + */ +template +CProceduralButton::~CProceduralButton() +{ +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::SetFillStyleUp(EFillStyle inStyle) +{ + if (m_UpFillStyle != inStyle) { + m_UpFillStyle = inStyle; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::SetFillStyleDown(EFillStyle inStyle) +{ + if (m_DownFillStyle != inStyle) { + m_DownFillStyle = inStyle; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::SetFillStyleDisabled(EFillStyle inStyle) +{ + if (m_DisabledFillStyle != inStyle) { + m_DisabledFillStyle = inStyle; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::SetFillStyleOver(EFillStyle inStyle) +{ + if (m_OverFillStyle != inStyle) { + m_OverFillStyle = inStyle; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::SetFillStyleAll(EFillStyle inStyle) +{ + SetFillStyleUp(inStyle); + SetFillStyleDown(inStyle); + SetFillStyleDisabled(inStyle); + SetFillStyleOver(inStyle); +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::SetFillColorUp(const CColor &inColor) +{ + if (m_UpColor != inColor) { + m_UpColor = inColor; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::SetFillColorDown(const CColor &inColor) +{ + if (m_DownColor != inColor) { + m_DownColor = inColor; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::SetFillColorDisabled(const CColor &inColor) +{ + if (m_DisabledColor != inColor) { + m_DisabledColor = inColor; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::SetFillColorOver(const CColor &inColor) +{ + if (m_OverColor != inColor) { + m_OverColor = inColor; + TButton::Invalidate(); + } +} + +template +void CProceduralButton::SetBorderVisibilityAll(const SBorderOptions &inBorderOptions) +{ + SetBorderVisiblityUp(inBorderOptions); + SetBorderVisiblityDown(inBorderOptions); + SetBorderVisiblityDisabled(inBorderOptions); + SetBorderVisiblityOver(inBorderOptions); +} + +template +void CProceduralButton::SetBorderVisiblityUp(const SBorderOptions &inBorderOptions) +{ + m_UpBorders = inBorderOptions; +} + +template +void CProceduralButton::SetBorderVisiblityDown(const SBorderOptions &inBorderOptions) +{ + m_DownBorders = inBorderOptions; +} + +template +void CProceduralButton::SetBorderVisiblityDisabled(const SBorderOptions &inBorderOptions) +{ + m_DisabledBorders = inBorderOptions; +} + +template +void CProceduralButton::SetBorderVisiblityOver(const SBorderOptions &inBorderOptions) +{ + m_OverBorders = inBorderOptions; +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::SetLeftBorderColor(const CColor &inColor) +{ + if (m_LeftBorderColor != inColor) { + m_LeftBorderColor = inColor; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::SetTopBorderColor(const CColor &inColor) +{ + if (m_TopBorderColor != inColor) { + m_TopBorderColor = inColor; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::SetRightBorderColor(const CColor &inColor) +{ + if (m_RightBorderColor != inColor) { + m_RightBorderColor = inColor; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::SetBottomBorderColor(const CColor &inColor) +{ + if (m_BottomBorderColor != inColor) { + m_BottomBorderColor = inColor; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * xxx + */ +template +void CProceduralButton::Render(CRenderer *inRenderer) +{ + // Fill the background if desired + DrawBackground(inRenderer); + + // Draw the button icon + TButton::Render(inRenderer); + + // Draw the border + DrawBorder(inRenderer); +} + +//============================================================================= +/** + * Fills the background of this button with the appropriate color and style. + * The style is specified by calling "GetCurrentFillStyle" which may indicate + * not to fill the background at all. + * @param inRenderer the renderer to draw to + */ +template +void CProceduralButton::DrawBackground(CRenderer *inRenderer) +{ + CPt theSize = TButton::GetSize(); + + // Fill in the background color if necessary + EFillStyle theFillStyle = GetCurrentFillStyle(); + + switch (theFillStyle) { + // Perform a gradient fill (block of color that varies slightly along the y-axis) + case EFILLSTYLE_GRADIENT: { + // The gradient inverts if the button is currently in the down state + bool theInvertGradientFlag = (TButton::GetButtonState() == TButton::EBUTTONSTATE_DOWN) ? true : false; + inRenderer->DrawGradientBitmap(QRect(0, 0, theSize.x, theSize.y), GetCurrentBackgroundColor(), theInvertGradientFlag, + 0.75); + } break; + + // Fill the whole area with a block of solid color + case EFILLSTYLE_FLOOD: + inRenderer->FillSolidRect(QRect(0, 0, theSize.x, theSize.y), GetCurrentBackgroundColor()); + break; + + // Do not fill the background at all + case EFILLSTYLE_NONE: + // No break + default: + // No filling in of the background + break; + } +} + +//============================================================================= +/** + * Draws the borders around this button as specified in the border options for + * the current state of the button. You can turn border drawing on and off + * per side of the button, and you can also specify different colors for each + * side of the button. + * @param inRenderer renderer to draw to + */ +template +void CProceduralButton::DrawBorder(CRenderer *inRenderer) +{ + CPt theSize = TButton::GetSize(); + SBorderOptions theBorders = CProceduralButton::GetCurrentBorderOptions(); + + if (theBorders.m_DrawLeft) { + inRenderer->PushPen(m_LeftBorderColor); + inRenderer->MoveTo(CPt(0, theSize.y - 1)); + inRenderer->LineTo(CPt(0, 0)); + inRenderer->PopPen(); + } + + if (theBorders.m_DrawTop) { + inRenderer->PushPen(m_TopBorderColor); + inRenderer->MoveTo(CPt(0, 0)); + inRenderer->LineTo(CPt(theSize.x - 1, 0)); + inRenderer->PopPen(); + } + + if (theBorders.m_DrawRight) { + inRenderer->PushPen(m_RightBorderColor); + if (!theBorders.m_DrawTop) + inRenderer->MoveTo(CPt(theSize.x - 1, 0)); + else + inRenderer->MoveTo(CPt(theSize.x - 1, 1)); + inRenderer->LineTo(CPt(theSize.x - 1, theSize.y - 1)); + inRenderer->PopPen(); + } + + if (theBorders.m_DrawBottom) { + inRenderer->PushPen(m_BottomBorderColor); + inRenderer->MoveTo(CPt(theSize.x - 1, theSize.y - 1)); + if (!theBorders.m_DrawLeft) + inRenderer->LineTo(CPt(0, theSize.y - 1)); + else + inRenderer->LineTo(CPt(1, theSize.y - 1)); + inRenderer->PopPen(); + } +} + +//============================================================================= +/** + * @return the current fill style based upon state (up, down, mouse over, disabled) of the button + */ +template +typename CProceduralButton::EFillStyle +CProceduralButton::GetCurrentFillStyle() +{ + // Default to the up state + EFillStyle theFillStyle = m_UpFillStyle; + + typename TButton::EButtonState theState = TButton::GetButtonState(); + + // If the mouse is over the button, switch to the mouse over style + if (TButton::IsMouseOver()) + theFillStyle = m_OverFillStyle; + + // If the button is currently pressed, this cancels the up and over states, so return the down + // style + if (theState == TButton::EBUTTONSTATE_DOWN) + theFillStyle = m_DownFillStyle; + + // If this button is disabled just return the disabled style (overrides any other states) + if (!TButton::IsEnabled()) + theFillStyle = m_DisabledFillStyle; + + return theFillStyle; +} + +//============================================================================= +/** + * @return the current background color based upon state (up, down, mouse over, disabled) of the + * button + */ +template +::CColor CProceduralButton::GetCurrentBackgroundColor() +{ + // Default to the up color + ::CColor theColor = m_UpColor; + + typename TButton::EButtonState theState = TButton::GetButtonState(); + + // If the mouse is over the button, switch to the mouse over color + if (TButton::IsMouseOver()) + theColor = m_OverColor; + + // If the button is currently pressed, this cancels the up and over states, so return the down + // color + if (theState == TButton::EBUTTONSTATE_DOWN) + theColor = m_DownColor; + + // If this button is disabled just return the disabled color (overrides any other states) + if (!TButton::IsEnabled()) + theColor = m_DisabledColor; + + return theColor; +} + +//============================================================================= +/** + * @return the current border drawing options based upon state (up, down, mouse over, disabled) of + * the button + */ +template +typename CProceduralButton::SBorderOptions +CProceduralButton::GetCurrentBorderOptions() +{ + SBorderOptions theOptions = m_UpBorders; + typename TButton::EButtonState theState = TButton::GetButtonState(); + + // If the mouse is over the button, switch to the mouse over border options + if (TButton::IsMouseOver()) + theOptions = m_OverBorders; + + // If the button is currently pressed, this cancels the up and over states, so return the over + // border options + if (theState == TButton::EBUTTONSTATE_DOWN) + theOptions = m_DownBorders; + + // If this button is disabled just return the disabled border options (overrides any other + // states) + if (!TButton::IsEnabled()) + theOptions = m_DisabledBorders; + + return theOptions; +} + +#endif // INCLUDED_PROCEDURAL_BUTTON_H diff --git a/src/Authoring/Studio/Controls/Renderer.cpp b/src/Authoring/Studio/Controls/Renderer.cpp new file mode 100644 index 00000000..1a750196 --- /dev/null +++ b/src/Authoring/Studio/Controls/Renderer.cpp @@ -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$ +** +****************************************************************************/ + +#include "stdafx.h" + +#include "Renderer.h" + +#include +#include + +/** + * Draws the outline of a rectangle in the specified colors. + * + * @param inRect Rectangle to be outlined + * @param inTop Color of the top line + * @param inRight Color of the line on the right side + * @param inBottom Color of the line on the bottom + * @param inLeft Color of the line on the left side + */ +void CRenderer::DrawRectOutline(const QRect &inRect, const QColor &inTop, const QColor &inRight, + const QColor &inBottom, const QColor &inLeft) +{ + QPoint theUpperLeft(inRect.topLeft()); + QPoint theUpperRight(inRect.topRight()); + QPoint theLowerRight(inRect.bottomRight()); + QPoint theLowerLeft(inRect.bottomLeft()); + + // Top + PushPen(inTop, 1); + MoveTo(theUpperLeft.x(), theUpperLeft.y()); + LineTo(theUpperRight.x(), theUpperRight.y()); + PopPen(); + + // Right + PushPen(inRight, 1); + LineTo(theLowerRight.x(), theLowerRight.y()); + PopPen(); + + // Bottom + PushPen(inBottom, 1); + LineTo(theLowerLeft.x(), theLowerLeft.y()); + PopPen(); + + // Left + PushPen(inLeft, 1); + LineTo(theUpperLeft.x(), theUpperLeft.y()); + PopPen(); +} diff --git a/src/Authoring/Studio/Controls/Renderer.h b/src/Authoring/Studio/Controls/Renderer.h new file mode 100644 index 00000000..6feca4ed --- /dev/null +++ b/src/Authoring/Studio/Controls/Renderer.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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_RENDERER_H +#define INCLUDED_RENDERER_H 1 + +#pragma once + +#include +#include + +#include "CColor.h" + +QT_BEGIN_NAMESPACE +class QPainter; +class QPixmap; +class QRect; +class QSize; +class QString; +QT_END_NAMESPACE + +class CRenderer +{ + typedef std::vector TTranslationList; + +public: + virtual ~CRenderer() {} + + virtual QPainter* GetPainter() = 0; + virtual void FillSolidRect(const QRect &inCoordinates, const QColor &inColor) = 0; + virtual void MoveTo(const QPoint &inPoint) = 0; + virtual void MoveTo(long inX, long inY) = 0; + virtual void LineTo(const QPoint &inPoint) = 0; + virtual void LineTo(long inX, long inY) = 0; + + virtual void PushPen(const QColor &inColor, + int inWidth = 1) = 0; //, UINT inStyle = PS_SOLID ); + virtual void PopPen() = 0; + virtual void BitBltFrom(const QRect &inRect, CRenderer *inRenderer, long inXSrc, long inYSrc) = 0; + + virtual void DrawText(float inX, float inY, const QString &inText) = 0; + virtual void DrawText(float inX, float inY, const QString &inText, + const QRect &inBoundingRect, const QColor &inColor = Qt::black) = 0; + virtual void DrawBoldText(float inX, float inY, const QString &inText, + const QRect &inBoundingRect, const QColor &inColor = Qt::black) = 0; + + virtual QSize GetTextSize(const QString &inText) = 0; + + virtual void DrawBitmap(const QPoint &inPos, const QPixmap &inImage) = 0; + virtual void Draw3dRect(const QRect &inRect, const QColor &inTopLeftColor, + const QColor &inBottomRightColor) = 0; + virtual void DrawRectOutline(const QRect &inRect, const QColor &inTop, const QColor &inRight, + const QColor &inBottom, const QColor &inLeft); + virtual void DrawGradientBitmap(const QRect &inRct, const QColor &inBeginColor, bool inInverted, + double inScalingFactor = .99) = 0; + + virtual void DrawGradient(const QRect &inRect, const QColor &inBeginColor, + const QColor &inEndColor) = 0; + + virtual void PushTranslation(const QPoint &inTranslation) = 0; + virtual void PopTranslation() = 0; + virtual QPoint GetTranslation() = 0; + + virtual QRect GetClippingRect() = 0; + virtual void PushClippingRect(const QRect &inRect) = 0; + virtual void PushAbsoluteClippingRect(const QRect &inRect) = 0; + virtual void PopClippingRect() = 0; + + virtual QRect Scroll(const QPoint &inAmount, const QRect &inVisibleSize) = 0; + + virtual void FillHashed(const QRect &inRect, const QColor &inForeGroundColor) = 0; + + virtual QPixmap pixmap() const = 0; + +protected: + QPoint m_Translation; + TTranslationList m_Translations; +}; +#endif // INCLUDED_RENDERER_H diff --git a/src/Authoring/Studio/Controls/SIcon.cpp b/src/Authoring/Studio/Controls/SIcon.cpp new file mode 100644 index 00000000..5df99717 --- /dev/null +++ b/src/Authoring/Studio/Controls/SIcon.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** 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 "SIcon.h" +#include "Renderer.h" +#include "MasterP.h" +#include "ResourceCache.h" + +//============================================================================= +/** + * Create a new Icon with no image. + */ +CSIcon::CSIcon() +{ + SetAbsoluteSize(CPt(0, 0)); + SetImage(QPixmap()); +} + +//============================================================================= +/** + * Create a new Icon with the specified images loaded from the resource cache. + * @param inResName Name of the image to be loaded for the normal icon + * @param inDisabledResName Name of the image to be loaded for the icon when it's disabled + */ +CSIcon::CSIcon(const QString &inResName, const QString &inDisabledResName /*= ""*/) +{ + SetAbsoluteSize(CPt(0, 0)); + CResourceCache *theCache = CResourceCache::GetInstance(); + m_EnabledImage = theCache->GetBitmap(inResName); + m_DisabledImage = theCache->GetBitmap(inDisabledResName); + SetImage(m_EnabledImage); +} + +//============================================================================= +/** + * Create a new Icon with the specified image. + * Any pixels in the image with the transparent color will not be drawn. + * The size of this control will be set to the size of the image. + * @param inResource string specifying what image to draw. + * @param inDisabledResource string specifying what disabled image to draw + */ +CSIcon::CSIcon(const QPixmap &inResource, const QPixmap &inDisabledResource /*=NULL*/) + : m_DisabledImage(inDisabledResource) + , m_EnabledImage(inResource) +{ + SetAbsoluteSize(CPt(0, 0)); + SetImage(m_EnabledImage); +} + +//============================================================================= +/** + * Destructor + */ +CSIcon::~CSIcon() +{ +} + +//============================================================================= +/** + * Set the image that this icon is drawing as. + * Any pixels in the image with the transparent color will not be drawn. + * The size of this control will be set to the size of the image. + * @param inResource the resource ID if the new image to draw. + * @param inPreserveSize false to check and set size ( setting to true can reduce flickering in some + * cases ) + */ +void CSIcon::SetImage(const QPixmap &inResource, bool inPreserveSize) +{ + m_Image = inResource; + + if (!inPreserveSize) { + // If we successfully loaded the new image then modify the size. + if (!m_Image.isNull()) + SetAbsoluteSize(CPt(GetImageSize().width(), GetImageSize().height())); + else + SetAbsoluteSize(CPt(0, 0)); + } + Invalidate(); +} + +//============================================================================= +/** + * Set image to the one specified + * @param inResName Name of the image to be loaded for the normal icon + * @param inPreserveSize false to check and set size ( setting to true can reduce flickering in some + * cases ) + */ +void CSIcon::SetImage(const QString &inResName, bool inPreserveSize) +{ + CResourceCache *theCache = CResourceCache::GetInstance(); + SetImage(theCache->GetBitmap(inResName), inPreserveSize); +} + +//============================================================================= +/** + * Draw this image. + * @param inRenderer the renderer to draw to. + */ +void CSIcon::Draw(CRenderer *inRenderer) +{ + inRenderer->PushClippingRect(QRect(QPoint(0,0), GetSize())); + if (!m_Image.isNull()) { + inRenderer->DrawBitmap(CPt(0, 0), m_Image); + } + inRenderer->PopClippingRect(); +} + +//============================================================================= +/** + * Get the size of this image. + */ +QSize CSIcon::GetImageSize() +{ + return m_Image.size(); +} + +//============================================================================= +/** + * Enables or disables the parent and switches the image to be displayed for + * this icon to a disabled or enabled image. + */ +void CSIcon::SetParentEnabled(bool inIsEnabled) +{ + CControl::SetParentEnabled(inIsEnabled); + if (!IsEnabled()) { + SetImage(m_DisabledImage); + } else { + SetImage(m_EnabledImage); + } + Invalidate(); +} diff --git a/src/Authoring/Studio/Controls/SIcon.h b/src/Authoring/Studio/Controls/SIcon.h new file mode 100644 index 00000000..53201e01 --- /dev/null +++ b/src/Authoring/Studio/Controls/SIcon.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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_ICON_H +#define INCLUDED_ICON_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" + +#include + +//============================================================================== +// Forwards +//============================================================================== + +//============================================================================= +/** + * Class for drawing bitmapped icon controls to the renderer. + */ +class CSIcon : public CControl +{ +public: + CSIcon(); + CSIcon(const QString &inResName, const QString &inDisabledResName = QString()); + CSIcon(const QPixmap &inResource, const QPixmap &inDisabledResource = {}); + + virtual ~CSIcon(); + + void SetImage(const QPixmap &inResource, bool inPreserveSize = false); + void SetImage(const QString &inResName, bool inPreserveSize = false); + QSize GetImageSize(); + void SetParentEnabled(bool inParentEnabled) override; + + void Draw(CRenderer *inRenderer) override; + +protected: + QPixmap m_Image; + QPixmap m_DisabledImage; + QPixmap m_EnabledImage; +}; +#endif // INCLUDED_ICON_H diff --git a/src/Authoring/Studio/Controls/ScrollController.cpp b/src/Authoring/Studio/Controls/ScrollController.cpp new file mode 100644 index 00000000..8b1dd72f --- /dev/null +++ b/src/Authoring/Studio/Controls/ScrollController.cpp @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** 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 "ScrollController.h" +#include "Renderer.h" +#include "StudioPreferences.h" +#include "Scroller.h" +#include "Control.h" + +using namespace Q3DStudio; + +const long CScrollController::DEFAULT_SCROLL_AMOUNT = 20; + +//============================================================================= +/** + * Constructor + */ +CScrollController::CScrollController() + : m_Orientation(IScrollerBar::VERTICAL) + , m_ScrollerBar(NULL) + , m_Control(NULL) + , m_ScrollingForward(false) + , m_ScrollingBackward(false) +{ +} + +//============================================================================= +/** + * Destructor + */ +CScrollController::~CScrollController() +{ +} + +//============================================================================= +/** + * Sets the control. Used to get the check if the mouse is over the control. + */ +void CScrollController::SetControl(CControl *inControl) +{ + m_Control = inControl; +} + +//============================================================================= +/** + * Sets the scroller bar for this control. Used to get the thumb position in + * OnMouseDown. + */ +void CScrollController::SetScrollerBar(IScrollerBar *inScrollerBar) +{ + m_ScrollerBar = inScrollerBar; +} + +//============================================================================= +/** + * Tells this control which way to draw itself. + * @param inOrientation Direction of the scroller that is using this control + */ +void CScrollController::SetOrientation(IScrollerBar::EOrientation inOrientation) +{ + m_Orientation = inOrientation; +} + +//============================================================================= +/** + * Returns the amount to scroll + */ +long CScrollController::DetermineScrollAmount() +{ + return DEFAULT_SCROLL_AMOUNT; +} + +//============================================================================= +/** + * Call to scroll forwards. + * Forwards is right/down depending on orientation. + */ +void CScrollController::OnScrollForward(CControl *inButton) +{ + if (!m_ScrollingForward && inButton) { + m_ScrollingForward = true; + + Q3DStudio::CString theName = "CScrollController::OnScrollForward"; + if (m_Control) { + theName += "::%s"; + theName.Format(theName, static_cast(m_Control->GetName())); + } + + m_TimerConnection = ITickTock::GetInstance().AddTimer( + 100, true, std::bind(&CScrollController::OnTimer, this), theName); + } + + Q_UNUSED(inButton); + CPt theScrollDistance(0, 0); + long theScrollAmount = DetermineScrollAmount(); + + if (m_ScrollerBar->GetOrientation() == IScrollerBar::VERTICAL) { + theScrollDistance.y = theScrollAmount; + } else { + theScrollDistance.x = theScrollAmount; + } + + m_ScrollerBar->GetScroller()->SetVisiblePosition( + m_ScrollerBar->GetScroller()->GetVisiblePosition() + theScrollDistance); + m_ScrollerBar->RepositionThumb(); +} + +//============================================================================= +/** + * Call to scroll backwards. + * Backwards is left/up depending on orientation. + */ +void CScrollController::OnScrollBackward(CControl *inButton) +{ + if (!m_ScrollingBackward && inButton) { + m_ScrollingBackward = true; + + Q3DStudio::CString theName = "CScrollController::OnScrollBackward"; + if (m_Control) { + theName += "::%s"; + theName.Format(theName, static_cast(m_Control->GetName())); + } + + m_TimerConnection = ITickTock::GetInstance().AddTimer( + 100, true, std::bind(&CScrollController::OnTimer, this), theName); + } + + Q_UNUSED(inButton); + CPt theScrollDistance(0, 0); + long theScrollAmount = DetermineScrollAmount(); + + if (m_ScrollerBar->GetOrientation() == IScrollerBar::VERTICAL) { + theScrollDistance.y = theScrollAmount; + } else { + theScrollDistance.x = theScrollAmount; + } + + m_ScrollerBar->GetScroller()->SetVisiblePosition( + m_ScrollerBar->GetScroller()->GetVisiblePosition() - theScrollDistance); + m_ScrollerBar->RepositionThumb(); +} + +//============================================================================= +/** + * Cancels the scrolling. Removes the timer. + */ +void CScrollController::OnCancelScrolling(CControl *inButton) +{ + Q_UNUSED(inButton); + + m_ScrollingForward = false; + m_ScrollingBackward = false; + + m_TimerConnection = std::shared_ptr(); +} + +//============================================================================= +/** + * Overwritten TickTockProc thats called everytime the timer is activated. + */ +void CScrollController::OnTimer() +{ + if (m_ScrollingForward) { + // We want it to scroll only if the mouse is over the control + if (m_Control->IsMouseOver()) { + OnScrollForward(nullptr); + } + } else if (m_ScrollingBackward) { + // We want it to scroll only if the mouse is over the control + if (m_Control->IsMouseOver()) { + OnScrollBackward(nullptr); + } + } else // The timer should not be called if we are not scrolling forward nor backwards + { + ASSERT(false); + } +} diff --git a/src/Authoring/Studio/Controls/ScrollController.h b/src/Authoring/Studio/Controls/ScrollController.h new file mode 100644 index 00000000..9c9cdf41 --- /dev/null +++ b/src/Authoring/Studio/Controls/ScrollController.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$ +** +****************************************************************************/ + +#ifndef INCLUDED_SCROLL_CONTROLLER_H +#define INCLUDED_SCROLL_CONTROLLER_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "BlankControl.h" +#include "StudioPreferences.h" +#include "ITickTock.h" +#include "ScrollerBar.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; +class CControl; + +//============================================================================= +/** + * Extends the blank control to draw items specific to the scroller control. + */ +class CScrollController +{ +public: + static const long DEFAULT_SCROLL_AMOUNT; + + CScrollController(); + virtual ~CScrollController(); + void SetControl(CControl *inControl); + void SetScrollerBar(IScrollerBar *inScrollerBar); + void SetOrientation(IScrollerBar::EOrientation inOrientation); + + virtual void OnScrollForward(CControl *inControl = nullptr); + virtual void OnScrollBackward(CControl *inControl = nullptr); + virtual void OnCancelScrolling(CControl *inControl = nullptr); + +protected: + void OnTimer(); + + std::shared_ptr m_TimerConnection; + IScrollerBar::EOrientation m_Orientation; + IScrollerBar *m_ScrollerBar; + CControl *m_Control; + + bool m_ScrollingForward; + bool m_ScrollingBackward; + + virtual long DetermineScrollAmount(); +}; + +#endif // INCLUDED_SCROLL_CONTROLLER_H \ No newline at end of file diff --git a/src/Authoring/Studio/Controls/Scroller.cpp b/src/Authoring/Studio/Controls/Scroller.cpp new file mode 100644 index 00000000..9dd3d006 --- /dev/null +++ b/src/Authoring/Studio/Controls/Scroller.cpp @@ -0,0 +1,829 @@ +/**************************************************************************** +** +** 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 "Scroller.h" +#include "Renderer.h" +#include "ButtonControl.h" +#include "MasterP.h" +#include "UICDMSignals.h" +#include "ControlData.h" + +#include + +using namespace Q3DStudio; +const unsigned long ORIGINAL_DELAY_TIME = 200; +const unsigned long ORIGINAL_OFFSET_AMMOUNT = 205; +//============================================================================= +/** + * Creates a scroller. + * @param inCreateImmediately used by subclasses, true if using base class of CScroller + */ +CScroller::CScroller(bool inCreateImmediately /* = true */) + : m_VisibleSize(0, 0) + , m_VisiblePosition(0, 0) + , m_VerticalScrollMode(AS_NEEDED) + , m_HorizontalScrollMode(AS_NEEDED) + , m_ResizingChildren(false) + , m_IsMouseDown(false) + , m_OffsetAmmount(ORIGINAL_OFFSET_AMMOUNT) + , m_DelayTime(ORIGINAL_DELAY_TIME) +{ + if (inCreateImmediately) + Initialize(); + m_ControlData->SetMouseWheelEnabled(true); + + SetName("Scroller"); +} + +CScroller::~CScroller() +{ + delete m_VerticalBar; + delete m_HorizontalBar; +} + +//============================================================================= +/** + * Performed once and only once! + * Do not call if CScroller was called with the createImmediately flag as true. + */ +void CScroller::Initialize() +{ + m_VerticalBar = CreateVerticalBar(); + m_HorizontalBar = CreateHorizontalBar(); + + AddChild(m_VerticalBar); + AddChild(m_HorizontalBar); +} + +//============================================================================= +/** + * Virtual function to get the vertical scroll bar. + * This allows overriding so subclasses can subclass the ScrollerBar as well. + * The created bar will be deleted on the destruction of this class. + * @return the created scrollerbar. + */ +CScrollerBar *CScroller::CreateVerticalBar() +{ + CScrollerBar *theBar = new CScrollerBar(this); + theBar->SetOrientation(CScrollerBar::VERTICAL); + + return theBar; +} + +//============================================================================= +/** + * Virtual function to get the horizontal scroll bar. + * This allows overriding so subclasses can subclass the ScrollerBar as well. + * The created bar will be deleted on the destruction of this class. + * @return the created scrollerbar. + */ +CScrollerBar *CScroller::CreateHorizontalBar() +{ + CScrollerBar *theBar = new CScrollerBar(this); + theBar->SetOrientation(CScrollerBar::HORIZONTAL); + + return theBar; +} + +void CScroller::OnSizeChanged(CPt /*inSize*/) +{ + CPt theMaxPoint = GetMaxVisiblePosition(); + CPt theVisPoint = GetVisiblePosition(); + if (theVisPoint.x > theMaxPoint.x) + theVisPoint.x = theMaxPoint.x; + if (theVisPoint.y > theMaxPoint.y) + theVisPoint.y = theMaxPoint.y; + + SetVisiblePosition(theVisPoint); + RecalcLayout(); +} +//============================================================================= +/** + * Sets the size of the scroller. + * @param inSize the new size for this scroller. + */ +void CScroller::SetSize(CPt inSize) +{ + if (inSize != GetSize()) { + CControl::SetSize(inSize); + OnSizeChanged(inSize); + } +} + +void CScroller::SetLayout(CPt inSize, CPt inPosition) +{ + CControl::SetLayout(inSize, inPosition); + OnSizeChanged(inSize); +} + +//============================================================================= +/** + * Gets the minimum size that this scroller is allowed to be. + * This is calculated from the minimum size of the child control and the + * needed size of the scroll bars. + * @return the minimum size of this object. + */ +CPt CScroller::GetMinimumSize() +{ + CPt theSize(0, 0); + CControl *theChildControl = GetControl(); + if (theChildControl != nullptr) { + CPt theChildMin = theChildControl->GetMinimumSize(); + // If at zero the scroll bars are up then include them in the size. + if (theChildMin.x != 0) { + theSize += m_HorizontalBar->GetMinimumSize(); + } + if (theChildMin.y != 0) { + theSize += m_VerticalBar->GetMinimumSize(); + } + } + + return theSize; +} + +//============================================================================= +/** + * Get the maximum size of this scroller. + * This is just the maximum size of the child window, since the scroll bars + * will not be up when at max size. + * @return the maximum size of this control. + */ +CPt CScroller::GetMaximumSize() +{ + CPt theMaxSize; + CControl *theChildControl = GetControl(); + if (theChildControl != nullptr) + theMaxSize = theChildControl->GetMaximumSize(); + else + theMaxSize = CControl::GetMaximumSize(); + + return theMaxSize; +} + +//============================================================================= +/** + * Add a child control to this control. + * This is used to add a new child to this control. If there is already a + * component in the scrolling window then inControl will take the place of the + * previous control and the previous will be removed as a child of this. + * @param inControl the control to be added. + * @param inInsertBefore not used. + */ +void CScroller::AddChild(CControl *inControl, CControl *inInsertBefore /*= nullptr*/) +{ + Q_UNUSED(inInsertBefore); + + if (GetChildCount() > 3) + RemoveChild(GetChildren().GetCurrent()->GetControl()); + + if (GetChildCount() > 0) + CControl::AddChild(inControl, GetChildren().GetCurrent()->GetControl()); + else + CControl::AddChild(inControl); + + RecalcLayout(); +} + +//============================================================================= +/** + * Recalculate the layout of this object. + * This is used anytime this is changing size or needs to figure out where the + * controls go. This does all the work of setting the scrollerbar positions and + * the child window positions. + */ +void CScroller::RecalcLayout() +{ + UICPROFILE(RecalcLayout); + + m_ResizingChildren = true; + + CPt mySize = GetSize(); + m_VisibleSize = mySize; + + // If the side bar should be visible + if (IsVerticalVisible()) { + // Make sure the side bar is visible. + m_VerticalBar->SetVisible(true); + + // Set the side bars position + m_VerticalBar->SetPosition(CPt(mySize.x - m_VerticalBar->GetMinimumSize().x, 0)); + // the width of the vertical bar is subtracted from the visible area. + m_VisibleSize.x -= m_VerticalBar->GetMinimumSize().x; + + if (!IsVerticalScrolling()) + m_VerticalBar->SetEnabled(false); + else + m_VerticalBar->SetEnabled(true); + } else + m_VerticalBar->SetVisible(false); + + if (IsHorizontalVisible()) { + // Make sure the bottom bar is visible. + m_HorizontalBar->SetVisible(true); + + // Set the bottom bar's position. + m_HorizontalBar->SetPosition(CPt(0, mySize.y - m_HorizontalBar->GetMinimumSize().y)); + // the height of the horizontal bar is subtracted from the visible area. + m_VisibleSize.y -= m_HorizontalBar->GetMinimumSize().y; + + if (!IsHorizontalScrolling()) + m_HorizontalBar->SetEnabled(false); + else + m_HorizontalBar->SetEnabled(true); + } else + m_HorizontalBar->SetVisible(false); + + SetVisibleSize(m_VisibleSize); + SetVisiblePosition(GetVisiblePosition()); + + if (IsVerticalVisible()) + m_VerticalBar->SetSize(CPt(m_VerticalBar->GetMinimumSize().x, m_VisibleSize.y)); + if (IsHorizontalVisible()) + m_HorizontalBar->SetSize(CPt(m_VisibleSize.x, m_HorizontalBar->GetMinimumSize().y)); + + m_ResizingChildren = false; +} + +//============================================================================= +/** + * Set the size of the inner control that is visible. + * @param inSize the size of the inner control that is to be visible. + */ +void CScroller::SetVisibleSize(CPt inSize) +{ + m_VisibleSize = inSize; + + // If we have a child then set all of it's properties up. + CControl *theChild = GetControl(); + if (theChild) { + CPt theChildSize = m_VisibleSize; + CPt theMinSize = theChild->GetMinimumSize(); + + if (theMinSize.x < theChildSize.x) + theMinSize.x = theChildSize.x; + if (theMinSize.y < theChildSize.y) + theMinSize.y = theChildSize.y; + + // Set the sizes of the child to be either the size of the control or it's minimum size + if (theMinSize.x > theChildSize.x) + theChildSize.x = theMinSize.x; + if (theMinSize.y > theChildSize.y) + theChildSize.y = theMinSize.y; + + theChild->SetSize(theChildSize); + } +} + +//============================================================================= +/** + * Check to see is the vertical bar should be visible or not. + * @return true if the vertical bar should be visible. + */ +bool CScroller::IsVerticalVisible() +{ + if (m_VerticalScrollMode != NEVER) { + if (m_VerticalScrollMode == ALWAYS || IsVerticalScrolling()) { + return true; + } + } + return false; +} + +//============================================================================= +/** + * Check to see if the horizontal bar should be visible or not. + * @return true if the horizontal bar should be visible. + */ +bool CScroller::IsHorizontalVisible() +{ + if (m_HorizontalScrollMode != NEVER) { + if (m_HorizontalScrollMode == ALWAYS || IsHorizontalScrolling()) { + return true; + } + } + return false; +} + +//============================================================================= +/** + * Checks to see if the client view should be scrolled vertically or not. + * This does not mean that the scroll bar is visible or not, just that the client + * view can be scrolled vertically. + * @return true if the client min height larger than this height. + */ +bool CScroller::IsVerticalScrolling() +{ + CControl *theChild = GetControl(); + if (theChild != nullptr) { + CPt mySize = GetSize(); + if (m_HorizontalScrollMode == ALWAYS) + mySize.y -= m_HorizontalBar->GetSize().y; + + CPt theChildSize = theChild->GetMinimumSize(); + + if (theChildSize.y > mySize.y) + return true; + } + return false; +} + +//============================================================================= +/** + * Checks to see if the client view should be scrolled horizontally or not. + * This does not mean that the scroll bar is visible or not, just that the + * client view can be scrolled horizontally. + * @return true if the client min width is larget than this width. + */ +bool CScroller::IsHorizontalScrolling() +{ + CControl *theChild = GetControl(); + if (theChild != nullptr) { + CPt mySize = GetSize(); + if (m_VerticalScrollMode == ALWAYS) + mySize.x -= m_VerticalBar->GetSize().x; + + CPt theChildSize = theChild->GetMinimumSize(); + + if (theChildSize.x > mySize.x) + return true; + } + return false; +} + +//============================================================================= +/** + * Get the child control that this is wrapping. + * @return the child control, or nullptr if there is not one. + */ +CControl *CScroller::GetControl() +{ + if (GetChildCount() > 2) + return GetChildren().GetCurrent()->GetControl(); + return nullptr; +} + +//============================================================================= +/** + * Get the size of this control that the Client is actually visible in. + * This is not the size of the client, but the size of the area that the client + * is being drawn to. + * @return the visible area of the child control. + */ +CPt CScroller::GetVisibleSize() +{ + return m_VisibleSize; +} + +//============================================================================= +/** + * Get the size of the actual child control. + * This is the total size of the child, and is always at least the size of + * the visible size. + * @return the size of the child control. + */ +CPt CScroller::GetContaineeSize() +{ + UICPROFILE(GetContaineeSize); + + CControl *theControl = GetControl(); + CPt theSize; + if (theControl != nullptr) + theSize = theControl->GetSize(); + else + theSize = GetSize(); + + return theSize; +} + +//============================================================================= +/** + * Get the offset of the child control inside of this control. + * @return the offset location of the child. + */ +CPt CScroller::GetVisiblePosition() +{ + return m_VisiblePosition; +} + +//============================================================================= +/** + * Set the visible position of the child control. + * @param inVisiblePosition the visible position of the child control. + */ +void CScroller::SetVisiblePosition(CPt inVisiblePosition) +{ + if (inVisiblePosition.x < 0) + inVisiblePosition.x = 0; + + if (inVisiblePosition.y < 0) + inVisiblePosition.y = 0; + + CPt theMaxVisiblePosition = GetMaxVisiblePosition(); + + if (inVisiblePosition.x > theMaxVisiblePosition.x) + inVisiblePosition.x = theMaxVisiblePosition.x; + + if (inVisiblePosition.y > theMaxVisiblePosition.y) + inVisiblePosition.y = theMaxVisiblePosition.y; + + if (inVisiblePosition != m_VisiblePosition) { + CPt theScrolledAmount = m_VisiblePosition - inVisiblePosition; + m_ScrolledAmount += theScrolledAmount; + + m_VisiblePosition = inVisiblePosition; + + if (IsVerticalScrolling()) + m_VerticalBar->RepositionThumb(); + if (IsHorizontalScrolling()) + m_HorizontalBar->RepositionThumb(); + + m_ScrollListeners.FireEvent(&CScrollListener::OnScroll, this, theScrolledAmount); + } + + CControl *theChild = GetControl(); + if (theChild != nullptr) { + theChild->SetPosition(-m_VisiblePosition); + } +} + +//============================================================================= +/** + * Get the maximum allowable offset of the child control. + * This is where the child would be offset to if the scroll bars were at their + * far ends. + * @return the maximum visible position allowed. + */ +CPt CScroller::GetMaxVisiblePosition() +{ + CPt theMaxPoint(0, 0); + CPt mySize = GetSize(); + CControl *theChild = GetControl(); + + mySize.x -= IsVerticalVisible() ? m_VerticalBar->GetSize().x : 0; + mySize.y -= IsHorizontalVisible() ? m_HorizontalBar->GetSize().y : 0; + + if (theChild != nullptr) { + CPt theChildSize = theChild->GetSize(); + + if (theChildSize.x > mySize.x) + theMaxPoint.x = theChildSize.x - mySize.x; + + if (theChildSize.y > mySize.y) + theMaxPoint.y = theChildSize.y - mySize.y; + } + + return theMaxPoint; +} + +void CScroller::OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation) +{ + UICPROFILE(OnDraw); + + CRct theDirtyRect; + bool isInvalidated = IsInvalidated(); + + if (isInvalidated || inIgnoreValidation || m_VerticalBar->IsChildInvalidated() + || m_HorizontalBar->IsChildInvalidated()) { + if (isInvalidated || inIgnoreValidation) + DrawBackground(inRenderer); + Draw(inRenderer); + theDirtyRect.Or(CRct(GetSize())); + } + + CControl *theChild = GetControl(); + if (theChild != nullptr) { + // Create an off screen buffer to draw the child to, this makes it so the child will draw + // it's + // entire self to the offscreen section, then we'll only draw the visible part to the actual + // renderer + CRct theClippingRect = m_VisibleSize; + if (m_AddtlClippingRect.size.x != 0 && m_AddtlClippingRect.size.y != 0) + theClippingRect.And(m_AddtlClippingRect); + + inRenderer->PushClippingRect(theClippingRect); + inRenderer->PushTranslation(-m_VisiblePosition); + theChild->OnDraw(inRenderer, theDirtyRect, isInvalidated || inIgnoreValidation); + inRenderer->PopTranslation(); + inRenderer->PopClippingRect(); + + m_ScrolledAmount = CPt(0, 0); + } + + Invalidate(false); + + CRct theBoundingBox = inRenderer->GetClippingRect(); + theDirtyRect.And(theBoundingBox); + theDirtyRect.Offset(inRenderer->GetTranslation()); + inDirtyRect.Or(theDirtyRect); +} + +//============================================================================= +/** + * Overrides CControl::Draw to handle custom child buffering. + * This just allows the child to be drawn offset without actually letting it + * know that it's offset. + * @param inRenderer the renderer to draw to. + */ +void CScroller::Draw(CRenderer *inRenderer) +{ + UICPROFILE(Draw); + + CRct theDirtyRct; + // Only draw the side bar if it's visible + if (m_VerticalBar->IsVisible()) { + inRenderer->PushTranslation(m_VerticalBar->GetPosition()); + m_VerticalBar->OnDraw(inRenderer, theDirtyRct, true); + inRenderer->PopTranslation(); + } + + // only draw the bottom bar if it's visible + if (m_HorizontalBar->IsVisible()) { + inRenderer->PushTranslation(m_HorizontalBar->GetPosition()); + m_HorizontalBar->OnDraw(inRenderer, theDirtyRct, true); + inRenderer->PopTranslation(); + } +} + +//============================================================================= +/** + * Gets the horizontal scroll bar of this scroller. + * @return the horizontal scroll bar of this scroller. + */ +CScrollerBar *CScroller::GetHorizontalBar() +{ + return m_HorizontalBar; +} + +//============================================================================= +/** + * Gets the vertical scroll bar of this scroller. + * @return the vertical scroll bar of this scroller. + */ +CScrollerBar *CScroller::GetVerticalBar() +{ + return m_VerticalBar; +} + +//============================================================================= +/** + * Sets the vertical scroll mode of this scroller. + * This controls when the scroll bars will be visible and when thes will not be + * visible. + * @param inScrollMode the vertical scroll mode. + */ +void CScroller::SetVerticalScrollMode(EScrollMode inScrollMode) +{ + m_VerticalScrollMode = inScrollMode; +} + +//============================================================================= +/** + * Gets the vertical scroll mode of this scroller. + * This controls when the scroll bars will be visible and when they will not be + * visible. + * @return the vertical scroll mode. + */ +CScroller::EScrollMode CScroller::GetVerticalScrollMode() +{ + return m_VerticalScrollMode; +} + +//============================================================================= +/** + * Sets the horizontal scroll mode of this scroller. + * This controls when the scroll bars will be visible and when they will not be + * visible. + * @param inScrollMode the vertical scroll mode. + */ +void CScroller::SetHorizontalScrollMode(EScrollMode inScrollMode) +{ + m_HorizontalScrollMode = inScrollMode; +} + +//============================================================================= +/** + * Gets the horizontal scroll mode of this scroller. + * This controls when the scroll bars will be visible and when they will not be + * visible. + * @return the horizontal scroll mode. + */ +CScroller::EScrollMode CScroller::GetHorizontalScrollMode() +{ + return m_HorizontalScrollMode; +} + +void CScroller::OnChildSizeChanged(CControl *inControl) +{ + UICPROFILE(OnChildSizeChanged); + + CControl *theChild = GetControl(); + + if (inControl == theChild) { + CPt theChildSize = theChild->GetSize(); + CPt theMinSize = GetVisibleSize(); + if (theChildSize.x < theMinSize.x) { + theChild->SetMinimumSize(CPt(theMinSize.x, theChild->GetMinimumSize().y)); + theChildSize.x = theMinSize.x; + } + if (theChildSize.y < theMinSize.y) { + theChild->SetMinimumSize(CPt(theChild->GetMinimumSize().x, theMinSize.y)); + theChildSize.y = theMinSize.y; + } + + if (theChildSize != theChild->GetSize()) + theChild->SetSize(theChildSize); + else if (!m_ResizingChildren) { + RecalcLayout(); + Invalidate(); + } + } +} + +//============================================================================= +/** + * Add a listener to get notified when this control scrolls. + * @param inListener the listener to be notified when this scrolls. + */ +void CScroller::AddScrollListener(CScrollListener *inListener) +{ + m_ScrollListeners.AddListener(inListener); +} + +//============================================================================= +/** + * Remove a listener from the list of listeners to be notified when this scrolls. + * @param inListener the listener to be removed from the list of listeners. + */ +void CScroller::RemoveScrollListener(CScrollListener *inListener) +{ + m_ScrollListeners.RemoveListener(inListener); +} + +void CScroller::SetAdditionalClippingRect(CRct inAddtlClippingRect) +{ + m_AddtlClippingRect = inAddtlClippingRect; +} + +bool CScroller::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CPt theVertPoint = inPoint - m_VerticalBar->GetPosition(); + if (!m_VerticalBar->HitTest(inPoint) && !m_HorizontalBar->HitTest(inPoint)) { + m_IsMouseDown = true; + } + + return CControl::OnMouseDown(inPoint, inFlags); +} + +void CScroller::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (m_IsMouseDown) { + m_CurrentTickTock = std::shared_ptr(); + + CPt theOffset; + if ((inPoint.x < 0)) + theOffset.x = inPoint.x; + else if (inPoint.x > m_VisibleSize.x) + theOffset.x = inPoint.x - m_VisibleSize.x; + + // if ( ( inPoint.y < 0 && inPoint.y < m_PrevMousePoint.y ) || ( inPoint.y > + //m_VisibleSize.y && inPoint.y > m_PrevMousePoint.y ) ) + // theOffset.y = inPoint.y - m_PrevMousePoint.y; + + SetVisiblePosition(m_VisiblePosition + theOffset); + + if (theOffset.x != 0) { + m_ScrollingDir = theOffset; + m_MousePos = inPoint; + m_MouseFlags = inFlags; + m_CurrentTickTock = ITickTock::GetInstance().AddTimer( + m_DelayTime, true, std::bind(&CScroller::OnTimer, this), + "CScroller::OnMouseMove::" + GetName()); + // OnTimer( ); + } + } + + CControl::OnMouseMove(inPoint, inFlags); +} + +void CScroller::OnTimer() +{ + CPt theOffset; + const auto theBeginCurrentTime = QDateTime::currentMSecsSinceEpoch(); + if (m_ScrollingDir.x > 0) + theOffset.x = m_OffsetAmmount; + else if (m_ScrollingDir.x < 0) + theOffset.x = -m_OffsetAmmount; + + SetVisiblePosition(m_VisiblePosition + theOffset); + CControl::OnMouseMove(m_MousePos, m_MouseFlags); + const auto theEndCurrentTime = QDateTime::currentMSecsSinceEpoch(); + AdjustDelayTimeAccordingToOnTimerTime(theEndCurrentTime - theBeginCurrentTime); +} + +//============================================================================= +/** + * This function will adjust the delay time of the auto scroller depending on how long the timer + * took + * the numbers in here are pretty arbitrary and this should be redone at some point. + * @param inTime the amount of time that the timer took + */ +void CScroller::AdjustDelayTimeAccordingToOnTimerTime(unsigned long inTime) +{ + for (long theIndex = 2; theIndex < 6; theIndex++) { + if ((inTime)*theIndex > m_DelayTime) { + m_DelayTime = static_cast(m_DelayTime * 10 / theIndex); + m_OffsetAmmount = static_cast(m_OffsetAmmount * 10 / theIndex); + m_CurrentTickTock = ITickTock::GetInstance().AddTimer( + m_DelayTime, true, std::bind(&CScroller::OnTimer, this), + "CScroller::AdjustDelayTimeAccordingToOnTimerTime"); + break; + } + } +} + +void CScroller::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + m_IsMouseDown = false; + + CControl::OnMouseUp(inPoint, inFlags); + + m_CurrentTickTock = std::shared_ptr(); +} + +void CScroller::OnLoseFocus() +{ + m_IsMouseDown = false; + m_CurrentTickTock = std::shared_ptr(); + CControl::OnLoseFocus(); +} + +//============================================================================= +/** + * Handles mouse wheel messages to scroll the view. + */ +bool CScroller::OnMouseWheel(CPt inPoint, long inScrollAmount, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseWheel(inPoint, inScrollAmount, inFlags)) { + if (inScrollAmount < 0) + SetVisiblePosition(CPt(GetVisiblePosition().x, GetVisiblePosition().y + 60)); + else + SetVisiblePosition(CPt(GetVisiblePosition().x, GetVisiblePosition().y - 60)); + } + return true; +} + +//============================================================================= +/** + * Handles messages from children to scroll the view to appropriate loc. + */ +void CScroller::EnsureVisible(CRct inRect) +{ + CControl *theChild = GetControl(); + inRect.position -= theChild->GetPosition(); + + CPt theVisSize = GetVisibleSize(); + CPt theVisPos = GetVisiblePosition(); + + // Check to see if the top is off the top. + if (inRect.position.y < theVisPos.y) + theVisPos.y = inRect.position.y; + // Check to see if the bottom is off the bottom. + else if (inRect.position.y + inRect.size.y > theVisPos.y + theVisSize.y) + theVisPos.y = inRect.position.y + inRect.size.y - theVisSize.y; + + SetVisiblePosition(theVisPos); +} diff --git a/src/Authoring/Studio/Controls/Scroller.h b/src/Authoring/Studio/Controls/Scroller.h new file mode 100644 index 00000000..9cb39962 --- /dev/null +++ b/src/Authoring/Studio/Controls/Scroller.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** 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_SCROLLER_H +#define INCLUDED_SCROLLER_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" +#include "ScrollerBar.h" +#include "FlowLayout.h" +#include "GenericFunctor.h" +#include "Multicaster.h" +#include "ITickTock.h" + +//============================================================================== +// Forwards +//============================================================================== +class CButtonControl; + +GENERIC_FUNCTOR_2(CScrollListener, OnScroll, CScroller *, CPt); + +class IScroller +{ +protected: + virtual ~IScroller() {} +public: + virtual void SetVisiblePosition(CPt inVisiblePosition) = 0; + virtual CPt GetVisiblePosition() = 0; +}; + +//============================================================================= +/** + * Class for creating a scroller. + */ +class CScroller : public CControl, public IScroller +{ +public: + enum EScrollMode { + NEVER, + AS_NEEDED, + ALWAYS, + }; + + CScroller(bool inCreateImmediately = true); + virtual ~CScroller(); + + void Initialize(); + + void OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, + bool inIgnoreValidation /* = false */) override; + virtual void DrawBackground(CRenderer *) {} + void Draw(CRenderer *inRenderer) override; + + void SetSize(CPt inSize) override; + void SetLayout(CPt inSize, CPt inPosition) override; + CPt GetMinimumSize() override; + CPt GetMaximumSize() override; + + void AddChild(CControl *inControl, CControl *inInsertBefore = nullptr) override; + + CPt GetVisibleSize(); + CPt GetContaineeSize(); + + CPt GetVisiblePosition() override; + void SetVisiblePosition(CPt inVisiblePosition) override; + CPt GetMaxVisiblePosition(); + + CScrollerBar *GetHorizontalBar(); + CScrollerBar *GetVerticalBar(); + + void SetVerticalScrollMode(EScrollMode inScrollMode); + EScrollMode GetVerticalScrollMode(); + + void SetHorizontalScrollMode(EScrollMode inScrollMode); + EScrollMode GetHorizontalScrollMode(); + + virtual void RecalcLayout(); + void OnChildSizeChanged(CControl *inChild) override; + + void AddScrollListener(CScrollListener *inScrollListener); + void RemoveScrollListener(CScrollListener *inScrollListener); + + void SetAdditionalClippingRect(CRct inClippingRect); + + 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 inScrollAmount, Qt::KeyboardModifiers inFlags) override; + void EnsureVisible(CRct inRect) override; + + virtual void OnTimer(); + void OnLoseFocus() override; + void AdjustDelayTimeAccordingToOnTimerTime(unsigned long inTime); + +protected: + void OnSizeChanged(CPt inSize) override; + virtual bool IsVerticalVisible(); + virtual bool IsHorizontalVisible(); + virtual bool IsVerticalScrolling(); + virtual bool IsHorizontalScrolling(); + + virtual CScrollerBar *CreateVerticalBar(); + virtual CScrollerBar *CreateHorizontalBar(); + + virtual void SetVisibleSize(CPt inSize); + + virtual CControl *GetControl(); + + CScrollerBar *m_VerticalBar; + CScrollerBar *m_HorizontalBar; + + CPt m_VisibleSize; + CPt m_VisiblePosition; + CPt m_MaxVisiblePosition; + + CPt m_ScrolledAmount; + CPt m_ChildOffset; + + CRct m_AddtlClippingRect; + CPt m_ScrollingDir; + CPt m_MousePos; + Qt::KeyboardModifiers m_MouseFlags; + + EScrollMode m_VerticalScrollMode; + EScrollMode m_HorizontalScrollMode; + + bool m_ResizingChildren; + + CMulticaster m_ScrollListeners; + + bool m_IsMouseDown; + CPt m_PrevMousePoint; + + long m_OffsetAmmount; + unsigned long m_DelayTime; + std::shared_ptr m_CurrentTickTock; +}; +#endif // INCLUDED_SCROLLER_H diff --git a/src/Authoring/Studio/Controls/ScrollerBackground.cpp b/src/Authoring/Studio/Controls/ScrollerBackground.cpp new file mode 100644 index 00000000..fcfa5e7f --- /dev/null +++ b/src/Authoring/Studio/Controls/ScrollerBackground.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** 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 "ScrollerBackground.h" +#include "Renderer.h" +#include "StudioPreferences.h" +#include "Scroller.h" + +//============================================================================= +/** + * Constructor + */ +CScrollerBackground::CScrollerBackground(CColor inColor) + : CBlankControl(inColor) +{ + m_Orientation = CScrollerBar::HORIZONTAL; + m_ScrollerBar = nullptr; + m_Control = this; +} + +//============================================================================= +/** + * Destructor + */ +CScrollerBackground::~CScrollerBackground() +{ +} + +//============================================================================= +/** + * Overrides CBlankControl::Draw to handle scroller-specific drawing. + */ +void CScrollerBackground::Draw(CRenderer *inRenderer) +{ + CBlankControl::Draw(inRenderer); + + if (CScrollerBar::HORIZONTAL == m_Orientation) { + // Horizontal lines + inRenderer->PushPen(CStudioPreferences::GetScrollBGOutlineColor(), 1); + inRenderer->MoveTo(0, 0); + inRenderer->LineTo(GetSize().x, 0); + inRenderer->PopPen(); + inRenderer->PushPen(CStudioPreferences::GetScrollBGOutlineColor(), 1); + inRenderer->MoveTo(0, GetSize().y - 1); + inRenderer->LineTo(GetSize().x, GetSize().y - 1); + inRenderer->PopPen(); + } else { + // Vertical lines + inRenderer->PushPen(CStudioPreferences::GetScrollBGOutlineColor(), 1); + inRenderer->MoveTo(0, 0); + inRenderer->LineTo(0, GetSize().y - 1); + inRenderer->MoveTo(GetSize().x - 1, 0); + inRenderer->LineTo(GetSize().x - 1, GetSize().y - 1); + inRenderer->PopPen(); + } +} + +//============================================================================= +/** + * Handles mouse down events. Scrolls the thumb to the clicked position. + * @param inPoint location of the mouse click + * @param inFlags mouse event flags + */ +bool CScrollerBackground::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theHandledFlag = CBlankControl::OnMouseDown(inPoint, inFlags); + + if (!theHandledFlag && m_ScrollerBar) { + CPt theThumbPosition = m_ScrollerBar->GetThumb()->GetPosition(); + bool theScrollForwardFlag = false; + + if (CScrollerBar::HORIZONTAL == m_Orientation) { + if (inPoint.x > theThumbPosition.x) + theScrollForwardFlag = true; + } else { + if (inPoint.y > theThumbPosition.y) + theScrollForwardFlag = true; + } + + m_MousePos = inPoint; + + if (theScrollForwardFlag) + OnScrollForward(this); + else + OnScrollBackward(this); + + theHandledFlag = true; + } + + return theHandledFlag; +} + +//============================================================================= +/** + * Handles mouse up events + */ +void CScrollerBackground::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CBlankControl::OnMouseUp(inPoint, inFlags); + + OnCancelScrolling(); +} + +//============================================================================= +/** + * Returns the amount to scroll + */ +long CScrollerBackground::DetermineScrollAmount() +{ + long theDistance = 0; + CPt theThumbPosition = m_ScrollerBar->GetThumb()->GetPosition(); + CPt theThumbSize = m_ScrollerBar->GetThumb()->GetSize(); + + if (CScrollerBar::VERTICAL == m_Orientation) { + if ((m_ScrollingForward && (m_MousePos.y > theThumbPosition.y + theThumbSize.y)) + || (m_ScrollingBackward && (m_MousePos.y < theThumbPosition.y))) { + theDistance = theThumbSize.y; + } + } else // HORIZONTAL + { + if ((m_ScrollingForward && (m_MousePos.x > theThumbPosition.x + theThumbSize.x)) + || (m_ScrollingBackward && (m_MousePos.x < theThumbPosition.x))) { + theDistance = theThumbSize.x; + } + } + + return theDistance; +} + +//============================================================================= +/** + * Overwrite the MouseMove function. We want to take care of the scenario where + * it is in a scrolling state, then determine whether to scroll forwards or backwards + * depending on the mouse position relative to the scroller thumb. + */ +void CScrollerBackground::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + // Call the default mouseMove function + CControl::OnMouseMove(inPoint, inFlags); + + // We only want to do stuff if it is currently scrolling + if (m_ScrollingForward || m_ScrollingBackward) { + // save the mouse position + m_MousePos = inPoint; + + CPt theThumbPosition = m_ScrollerBar->GetThumb()->GetPosition(); + CPt theThumbSize = m_ScrollerBar->GetThumb()->GetSize(); + + if (CScrollerBar::VERTICAL == m_Orientation) { + if (m_MousePos.y > (theThumbPosition.y + theThumbSize.y)) { + m_ScrollingForward = true; + m_ScrollingBackward = false; + } else { + m_ScrollingForward = false; + m_ScrollingBackward = true; + } + } else // HORIZONTAL + { + if (m_MousePos.x > (theThumbPosition.x + theThumbSize.x)) { + m_ScrollingForward = true; + m_ScrollingBackward = false; + } else { + m_ScrollingForward = false; + m_ScrollingBackward = true; + } + } + } +} diff --git a/src/Authoring/Studio/Controls/ScrollerBackground.h b/src/Authoring/Studio/Controls/ScrollerBackground.h new file mode 100644 index 00000000..885d1c88 --- /dev/null +++ b/src/Authoring/Studio/Controls/ScrollerBackground.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** 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_SCROLLER_BACKGROUND_H +#define INCLUDED_SCROLLER_BACKGROUND_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "BlankControl.h" +#include "StudioPreferences.h" +#include "ScrollerBar.h" +#include "ScrollController.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; + +//============================================================================= +/** + * Extends the blank control to draw items specific to the scroller control. + */ +class CScrollerBackground : public CBlankControl, public CScrollController +{ +protected: + CPt m_MousePos; + +public: + CScrollerBackground(CColor inColor = CStudioPreferences::GetScrollBGColor()); + virtual ~CScrollerBackground(); + virtual void Draw(CRenderer *inRenderer); + virtual bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags); + +protected: + virtual long DetermineScrollAmount(); +}; + +#endif // INCLUDED_SCROLLER_BACKGROUND_H \ No newline at end of file diff --git a/src/Authoring/Studio/Controls/ScrollerBar.cpp b/src/Authoring/Studio/Controls/ScrollerBar.cpp new file mode 100644 index 00000000..b054fb6e --- /dev/null +++ b/src/Authoring/Studio/Controls/ScrollerBar.cpp @@ -0,0 +1,333 @@ +/**************************************************************************** +** +** 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 "ScrollerBar.h" +#include "Scroller.h" +#include "Renderer.h" +#include "ButtonControl.h" +#include "CoreUtils.h" +#include "ScrollerBackground.h" +#include "ScrollerThumb.h" +#include "StudioPreferences.h" +#include "Renderer.h" +#include "SystemPreferences.h" +#include "StudioUtils.h" +#include "ScrollerButtonControl.h" +#include "MasterP.h" + +//============================================================================== +// Static variables +//============================================================================== +const long CScrollerBar::DEFAULT_WIDTH = 16; +const CColor CScrollerBar::DEFAULT_COLOR = CColor(196, 194, 189); +const CColor CScrollerBar::SCROLLER_TOP = CColor(165, 162, 161); + +IMPLEMENT_OBJECT_COUNTER(CScrollerBar) + +//============================================================================= +/** + * Constructor + * @param inScroller the scroller on which this is operating. + * @param inCreateImmediately false for lazy construction, only for subclasses. + */ +CScrollerBar::CScrollerBar(CScroller *inScroller, bool inCreateImmediately /* = true */) +{ + ADDTO_OBJECT_COUNTER(CScrollerBar) + + m_Scroller = inScroller; + SetFlowDirection(FLOW_HORIZONTAL); + + if (inCreateImmediately) + Initialize(); +} + +//============================================================================= +/** + * Destructor + */ +CScrollerBar::~CScrollerBar() +{ + REMOVEFROM_OBJECT_COUNTER(CScrollerBar) +} + +//============================================================================= +/** + * Initialize this scroller bar. + * This is used for lazy construction of this object by subclasses. If a subclass + * specifies lazy construction in the constructor of this class then it must call + * this to put it into a valid state. + */ +void CScrollerBar::Initialize() +{ + m_ScrollerThumb = CreateThumb(); + + // First button + m_ButtonBackward = new CScrollerButtonControl(this, CScrollerButtonControl::BACKWARD); + + // Background + m_Background = new CScrollerBackground(CStudioPreferences::GetScrollBGColor()); + m_Background->SetScrollerBar(this); + m_Background->AddChild(m_ScrollerThumb); + + m_ScrollerThumb->SetPosition(CPt(0, 0)); + + // Second button (either right or bottom) + m_ButtonForward = new CScrollerButtonControl(this, CScrollerButtonControl::FORWARD); + + // Determine the placement of the scroll bar arrows based on the system preference + if (CSystemPreferences::AreScrollArrowsAdjacent()) { + // Scroll arrows go together at one end of the bar + AddChild(m_Background); + AddChild(m_ButtonBackward); + AddChild(m_ButtonForward); + } else { + // Scroll arrows go on each end of the scroll bar + AddChild(m_ButtonBackward); + AddChild(m_Background); + AddChild(m_ButtonForward); + } +} + +//============================================================================= +/** + * Virtual class to create the thumb class. + * This is used to allow sub-classes to specialize the scroller thumb that they + * are using. + * @return the thumb that was created. + */ +CControl *CScrollerBar::CreateThumb() +{ + return new CScrollerThumb(this); +} + +//============================================================================= +/** + * Set the orientation of this scroller bar. + * This determines which way this is scrolling. + */ +void CScrollerBar::SetOrientation(EOrientation inOrientation) +{ + m_Orientation = inOrientation; + m_Background->SetOrientation(inOrientation); + + if (m_Orientation == VERTICAL) { + // Vertical buttons + SetFlowDirection(FLOW_VERTICAL); + m_ButtonBackward->SetUpImage("scrollbar-arrows-up-normal.png"); + m_ButtonBackward->SetDownImage("scrollbar-arrows-up-depressed.png"); + m_ButtonBackward->SetDisabledImage("scrollbar-arrows-up-disabled.png"); + m_ButtonForward->SetUpImage("scrollbar-arrows-down-normal.png"); + m_ButtonForward->SetDownImage("scrollbar-arrows-down-depressed.png"); + m_ButtonForward->SetDisabledImage("scrollbar-arrows-down-disabled.png"); + } else { + // Horizontal buttons + SetFlowDirection(FLOW_HORIZONTAL); + m_ButtonBackward->SetUpImage("scrollbar-arrows-left-normal.png"); + m_ButtonBackward->SetDownImage("scrollbar-arrows-left-depressed.png"); + m_ButtonBackward->SetDisabledImage("scrollbar-arrows-left-disabled.png"); + m_ButtonForward->SetUpImage("scrollbar-arrows-right-normal.png"); + m_ButtonForward->SetDownImage("scrollbar-arrows-right-depressed.png"); + m_ButtonForward->SetDisabledImage("scrollbar-arrows-right-disabled.png"); + } +} + +//============================================================================= +/** + * Get the orientation of this scroller bar. + */ +CScrollerBar::EOrientation CScrollerBar::GetOrientation() +{ + return m_Orientation; +} + +//============================================================================= +/** + * Get the minimum size of this scroller bar. + * The minumum size is the width or height of both of it's buttons (depending + * on orientation. + * @return the minimum allowable size of this bar. + */ +CPt CScrollerBar::GetMinimumSize() +{ + if (GetOrientation() == VERTICAL) { + return CPt(DEFAULT_WIDTH, DEFAULT_WIDTH * 2); + } else { + return CPt(DEFAULT_WIDTH * 2, DEFAULT_WIDTH); + } +} + +//============================================================================= +/** + * Set the size of this scroller bar. + */ +void CScrollerBar::SetSize(CPt inSize) +{ + CFlowLayout::SetSize(inSize); + + RepositionThumb(); +} + +//============================================================================= +/** + * Recalculate the size and position of the thumb control. + */ +void CScrollerBar::RepositionThumb() +{ + long theBarLen; + + if (GetOrientation() == VERTICAL) { + float thePercentage = + (float)m_Scroller->GetVisibleSize().y / (float)m_Scroller->GetContaineeSize().y; + theBarLen = (long)(thePercentage * ((float)m_Background->GetSize().y)); + + if (theBarLen < CScrollerThumb::MIN_LENGTH) + theBarLen = CScrollerThumb::MIN_LENGTH; + + CPt theSize(GetMinimumSize().x, theBarLen); + + m_ScrollerThumb->SetSize(theSize); + + float theVisPosY = (float)(m_Scroller->GetVisiblePosition().y); + float theMaxPosY = (float)(m_Scroller->GetMaxVisiblePosition().y); + long thePosY = 0; + if (theMaxPosY != 0) + thePosY = ::dtol((theVisPosY / theMaxPosY) + * (m_Background->GetSize().y - m_ScrollerThumb->GetSize().y)); + + m_ScrollerThumb->SetPosition(CPt(0, thePosY)); + } else { + float thePercentage = + (float)m_Scroller->GetVisibleSize().x / (float)m_Scroller->GetContaineeSize().x; + theBarLen = ::dtol(thePercentage * ((float)m_Background->GetSize().x)); + if (theBarLen < CScrollerThumb::MIN_LENGTH) + theBarLen = CScrollerThumb::MIN_LENGTH; + + CPt theSize(theBarLen, GetMinimumSize().y); + + m_ScrollerThumb->SetSize(theSize); + + float theVisPosX = (float)(m_Scroller->GetVisiblePosition().x); + float theMaxPosX = (float)(m_Scroller->GetMaxVisiblePosition().x); + long thePosX = 0; + if (theMaxPosX != 0) + thePosX = ::dtol((theVisPosX / theMaxPosX) + * (m_Background->GetSize().x - m_ScrollerThumb->GetSize().x)); + + m_ScrollerThumb->SetPosition(CPt(thePosX, 0)); + } + + Invalidate(); +} + +IScroller *CScrollerBar::GetScroller() +{ + return m_Scroller; +}; + +//============================================================================= +/** + * Called by the ScrollerThumb to reposition itself. + * This is used to reposition the thumb, the positions here are used to derive + * the position of the visible window, so that this provides absolute positioning + * of the thumb. + * @param inPosition the new position of the thumb. + */ +void CScrollerBar::SetBarPosition(long inPosition) +{ + long theAvailableSpace; + if (GetOrientation() == HORIZONTAL) { + theAvailableSpace = m_Background->GetSize().x - m_ScrollerThumb->GetSize().x; + } else { + theAvailableSpace = m_Background->GetSize().y - m_ScrollerThumb->GetSize().y; + } + + if (inPosition > theAvailableSpace) + inPosition = theAvailableSpace; + if (inPosition < 0) + inPosition = 0; + + CPt theVisPos = m_Scroller->GetVisiblePosition(); + if (GetOrientation() == HORIZONTAL) { + m_ScrollerThumb->SetPosition(CPt(inPosition, 0)); + double theMaxPosX = (double)(m_Scroller->GetMaxVisiblePosition().x); + double theScrollDiff = (double)(m_Background->GetSize().x - m_ScrollerThumb->GetSize().x); + theVisPos.x = ::dtol((double)inPosition / theScrollDiff * theMaxPosX); + } else { + m_ScrollerThumb->SetPosition(CPt(0, inPosition)); + double theMaxPosY = (double)(m_Scroller->GetMaxVisiblePosition().y); + double theScrollDiff = (double)(m_Background->GetSize().y - m_ScrollerThumb->GetSize().y); + theVisPos.y = ::dtol((double)inPosition / theScrollDiff * theMaxPosY); + } + m_Scroller->SetVisiblePosition(theVisPos); + + RepositionThumb(); + + Invalidate(); +} + +//============================================================================= +/** + * Get the current position of the thumb. + * @return the current position of the thumb. + */ +long CScrollerBar::GetBarPosition() +{ + if (GetOrientation() == HORIZONTAL) + return m_ScrollerThumb->GetPosition().x; + else + return m_ScrollerThumb->GetPosition().y; +} + +//============================================================================= +/** + * Get the ScrollerThumb. + * @return the scroller thumb. + */ +CControl *CScrollerBar::GetThumb() +{ + return m_ScrollerThumb; +} + +//============================================================================= +/** + * Get the background of the thumb. + * @return the background of the thumb. + */ +CControl *CScrollerBar::GetThumbBackground() +{ + return m_Background; +} diff --git a/src/Authoring/Studio/Controls/ScrollerBar.h b/src/Authoring/Studio/Controls/ScrollerBar.h new file mode 100644 index 00000000..3a8527ef --- /dev/null +++ b/src/Authoring/Studio/Controls/ScrollerBar.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** 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_SCROLLER_BAR_H +#define INCLUDED_SCROLLER_BAR_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +#include "Control.h" +#include "FlowLayout.h" + +//============================================================================== +// Forwards +//============================================================================== + +class CScroller; +class CScrollerBar; +class CScrollerBackground; +class CRenderer; +class CScrollerButtonControl; + +class IScroller; + +class IScrollerBar +{ +protected: + virtual ~IScrollerBar() {} +public: + enum EOrientation { + VERTICAL, + HORIZONTAL, + }; + virtual EOrientation GetOrientation() = 0; + virtual void RepositionThumb() = 0; + virtual IScroller *GetScroller() = 0; + virtual void SetBarPosition(long inPosition) = 0; + virtual long GetBarPosition() = 0; + virtual CControl *GetThumb() = 0; +}; + +//============================================================================= +/** + * Class for creating a scrollerbar (contains a CScrollerThumb). + */ +class CScrollerBar : public CFlowLayout, public IScrollerBar +{ +public: + static const long DEFAULT_WIDTH; + static const ::CColor DEFAULT_COLOR; + static const ::CColor SCROLLER_TOP; + + CScrollerBar(CScroller *inScroller, bool inCreateImmediately = true); + virtual ~CScrollerBar(); + + DEFINE_OBJECT_COUNTER(CScrollerBar) + + void SetOrientation(EOrientation inOrientation); + EOrientation GetOrientation() override; + + CPt GetMinimumSize() override; + + void SetScrollerThumbPosition(long inPosition); + long GetScrollerThumbPosition(); + + void SetSize(CPt inSize) override; + + void SetBarPosition(long inPosition) override; + long GetBarPosition() override; + + CControl *GetThumb() override; + virtual CControl *GetThumbBackground(); + void RepositionThumb() override; + IScroller *GetScroller() override; + +protected: + virtual CControl *CreateThumb(); + void Initialize(); + Q3DStudio::CAutoMemPtr m_ButtonBackward; + Q3DStudio::CAutoMemPtr m_ButtonForward; + Q3DStudio::CAutoMemPtr m_ScrollerThumb; + Q3DStudio::CAutoMemPtr m_Background; + + EOrientation m_Orientation; + CScroller *m_Scroller; +}; + +#endif // INCLUDED_SCROLLER_BAR_H diff --git a/src/Authoring/Studio/Controls/ScrollerButtonControl.cpp b/src/Authoring/Studio/Controls/ScrollerButtonControl.cpp new file mode 100644 index 00000000..a04b8ff8 --- /dev/null +++ b/src/Authoring/Studio/Controls/ScrollerButtonControl.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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 "ScrollerButtonControl.h" +#include "Scroller.h" + +//============================================================================= +/** + * Constructor + * + * @param inToggleButton true if this is suppose to be a toggle button. Toggle + * buttons stay pressed when clicked on and have to be clicked again in order + * to release. Normal buttons return to the up state when the button is released. + */ +CScrollerButtonControl::CScrollerButtonControl(IScrollerBar *inScrollerBar, EDirection inDirection) + : m_Direction(inDirection) +{ + SetAbsoluteSize(CPt(CScrollerBar::DEFAULT_WIDTH, CScrollerBar::DEFAULT_WIDTH)); + SetScrollerBar(inScrollerBar); + m_Control = this; + + Initialize(); +} + +//============================================================================= +/** + * Destructor + */ +CScrollerButtonControl::~CScrollerButtonControl() +{ +} + +//============================================================================= +/** + * Destructor + */ +void CScrollerButtonControl::Initialize() { + // Add the button down listeners + if (m_Direction == FORWARD) { + SigButtonDown.connect(std::bind(&CScrollerButtonControl::OnScrollForward, + static_cast(this), std::placeholders::_1)); + } else { + SigButtonDown.connect(std::bind(&CScrollerButtonControl::OnScrollBackward, + static_cast(this), std::placeholders::_1)); + } + SigClicked.connect(std::bind(&CScrollerButtonControl::OnCancelScrolling, + static_cast(this), std::placeholders::_1)); +} + +//============================================================================= +/** + * Handles mouse up on the button. + */ +void CScrollerButtonControl::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CButtonControl::OnMouseUp(inPoint, inFlags); + + // If the mouse is not over this button, the base class will not fire an up event. + // However, we want to fire this event anyway so that the timer stops (otherwise, + // the next time you move your mouse over the button, it will start scrolling again). + if (!IsMouseOver()) + SigButtonUp(this); +} \ No newline at end of file diff --git a/src/Authoring/Studio/Controls/ScrollerButtonControl.h b/src/Authoring/Studio/Controls/ScrollerButtonControl.h new file mode 100644 index 00000000..a7763d8b --- /dev/null +++ b/src/Authoring/Studio/Controls/ScrollerButtonControl.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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_SCROLLER_BUTTON_CONTROL_H +#define INCLUDED_SCROLLER_BUTTON_CONTROL_H 1 + +//============================================================================== +// Includes +//============================================================================== + +#include "ButtonControl.h" +#include "ScrollerBar.h" +#include "ScrollController.h" + +//============================================================================== +// Forwards +//============================================================================== + +//============================================================================= +/** + * Subclassed button control that controls the scroller + */ +class CScrollerButtonControl : public CButtonControl, public CScrollController +{ +public: + enum EDirection { + FORWARD, + BACKWARD, + }; + +protected: + EDirection m_Direction; + +public: + CScrollerButtonControl(IScrollerBar *inScrollerBar, EDirection inDirection); + virtual ~CScrollerButtonControl(); + + virtual void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags); + + EDirection GetDirection() { return m_Direction; }; + +protected: + void Initialize(); +}; + +#endif // INCLUDED_SCROLLER_BUTTON_CONTROL_H diff --git a/src/Authoring/Studio/Controls/ScrollerThumb.cpp b/src/Authoring/Studio/Controls/ScrollerThumb.cpp new file mode 100644 index 00000000..a7fedbca --- /dev/null +++ b/src/Authoring/Studio/Controls/ScrollerThumb.cpp @@ -0,0 +1,197 @@ +/**************************************************************************** +** +** 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 "ScrollerThumb.h" +#include "ScrollerBar.h" +#include "Renderer.h" +#include "StudioPreferences.h" + +//============================================================================== +// Static variables +//============================================================================== +const long CScrollerThumb::MIN_LENGTH = 32; + +//============================================================================= +/** + * Constructor + * @param inScrollerBar the scroller bar this is operating on. + */ +CScrollerThumb::CScrollerThumb(IScrollerBar *inScrollerBar) + : m_MouseDown(false) +{ + m_ScrollerBar = inScrollerBar; +} + +//============================================================================= +/** + * Destructor + */ +CScrollerThumb::~CScrollerThumb() +{ +} + +//============================================================================= +/** + * Draw this scroller bar. + * @param inRenderer the renderer this is to draw to. + */ +void CScrollerThumb::Draw(CRenderer *inRenderer) +{ + if (IsEnabled()) { + CPt theSize = GetSize(); + CRct theRect(theSize); + + // Draw the thumb + inRenderer->FillSolidRect(theRect, CStudioPreferences::GetScrollThumbBGColor()); + // Draw the highlight + inRenderer->Draw3dRect(CRct(theRect.position.x + 1, theRect.position.y + 1, + theRect.size.x - 1, theRect.size.y - 1), + CStudioPreferences::GetScrollThumbHighlightColor(), + CStudioPreferences::GetScrollThumbBGColor()); + // Draw the black border + inRenderer->Draw3dRect(theRect, CStudioPreferences::GetScrollThumbShadowColor(), + CStudioPreferences::GetScrollThumbShadowColor()); + + // Draw the 3 lines in the middle of the control, depending on orientation + if (m_ScrollerBar->GetOrientation() == CScrollerBar::VERTICAL) { + // Draw the light lines + inRenderer->PushPen(CStudioPreferences::GetScrollThumbGripHighlightColor()); + inRenderer->MoveTo(CPt(theSize.x / 2 - 3, theSize.y / 2 - 5)); + inRenderer->LineTo(CPt(theSize.x / 2 + 2, theSize.y / 2 - 5)); + inRenderer->MoveTo(CPt(theSize.x / 2 - 3, theSize.y / 2 - 2)); + inRenderer->LineTo(CPt(theSize.x / 2 + 2, theSize.y / 2 - 2)); + inRenderer->MoveTo(CPt(theSize.x / 2 - 3, theSize.y / 2 + 1)); + inRenderer->LineTo(CPt(theSize.x / 2 + 2, theSize.y / 2 + 1)); + inRenderer->PopPen(); + // Draw the dark lines + inRenderer->PushPen(CStudioPreferences::GetScrollThumbGripShadowColor()); + inRenderer->MoveTo(CPt(theSize.x / 2 - 2, theSize.y / 2 - 4)); + inRenderer->LineTo(CPt(theSize.x / 2 + 3, theSize.y / 2 - 4)); + inRenderer->MoveTo(CPt(theSize.x / 2 - 2, theSize.y / 2 - 1)); + inRenderer->LineTo(CPt(theSize.x / 2 + 3, theSize.y / 2 - 1)); + inRenderer->MoveTo(CPt(theSize.x / 2 - 2, theSize.y / 2 + 2)); + inRenderer->LineTo(CPt(theSize.x / 2 + 3, theSize.y / 2 + 2)); + inRenderer->PopPen(); + } else { + // Draw the light lines + inRenderer->PushPen(CStudioPreferences::GetScrollThumbGripHighlightColor()); + inRenderer->MoveTo(CPt(theSize.x / 2 - 4, theSize.y / 2 - 3)); + inRenderer->LineTo(CPt(theSize.x / 2 - 4, theSize.y / 2 + 2)); + inRenderer->MoveTo(CPt(theSize.x / 2 - 1, theSize.y / 2 - 3)); + inRenderer->LineTo(CPt(theSize.x / 2 - 1, theSize.y / 2 + 2)); + inRenderer->MoveTo(CPt(theSize.x / 2 + 2, theSize.y / 2 - 3)); + inRenderer->LineTo(CPt(theSize.x / 2 + 2, theSize.y / 2 + 2)); + inRenderer->PopPen(); + + // Draw the dark lines + inRenderer->PushPen(CStudioPreferences::GetScrollThumbGripShadowColor()); + inRenderer->MoveTo(CPt(theSize.x / 2 - 3, theSize.y / 2 - 2)); + inRenderer->LineTo(CPt(theSize.x / 2 - 3, theSize.y / 2 + 3)); + inRenderer->MoveTo(CPt(theSize.x / 2, theSize.y / 2 - 2)); + inRenderer->LineTo(CPt(theSize.x / 2, theSize.y / 2 + 3)); + inRenderer->MoveTo(CPt(theSize.x / 2 + 3, theSize.y / 2 - 2)); + inRenderer->LineTo(CPt(theSize.x / 2 + 3, theSize.y / 2 + 3)); + inRenderer->PopPen(); + } + } +} + +//============================================================================= +/** + * Listener for the OnMouseDown to allow dragging. + * Begins dragging of the control. + */ +bool CScrollerThumb::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CControl::OnMouseDown(inPoint, inFlags)) { + m_MouseDown = true; + m_MouseDownPoint = inPoint; + + Invalidate(); + } + + return true; +} + +//============================================================================= +/** + * Ends dragging of the control. + */ +void CScrollerThumb::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseUp(inPoint, inFlags); + m_MouseDown = false; + + Invalidate(); +} + +//============================================================================= +/** + * Used for dragging the control. + */ +void CScrollerThumb::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseMove(inPoint, inFlags); + + // Only care if the mouse is down. + if (m_MouseDown) { + long theBarPos = m_ScrollerBar->GetBarPosition(); + + // Adjust the position based on which way we are being dragged. + if (m_ScrollerBar->GetOrientation() == CScrollerBar::VERTICAL) { + theBarPos += inPoint.y - m_MouseDownPoint.y; + } else { + theBarPos += inPoint.x - m_MouseDownPoint.x; + } + + // Update the position. + m_ScrollerBar->SetBarPosition(theBarPos); + } +} + +//============================================================================= +/** + * Get the minimum size that this scroller thumb is allowed to be. + * @return the minimum size that this scroller thumb is allowed to be. + */ +CPt CScrollerThumb::GetMinimumSize() +{ + if (m_ScrollerBar->GetOrientation() == CScrollerBar::HORIZONTAL) + return CPt(MIN_LENGTH, 0); + else + return CPt(0, MIN_LENGTH); +} diff --git a/src/Authoring/Studio/Controls/ScrollerThumb.h b/src/Authoring/Studio/Controls/ScrollerThumb.h new file mode 100644 index 00000000..c699c910 --- /dev/null +++ b/src/Authoring/Studio/Controls/ScrollerThumb.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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_SCROLLER_THUMB_H +#define INCLUDED_SCROLLER_THUMB_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" +#include "FlowLayout.h" + +//============================================================================== +// Forwards +//============================================================================== +class IScrollerBar; +class CRenderer; + +//============================================================================= +/** + * Class for creating the thumb portion of a scroller. + */ +class CScrollerThumb : public CControl +{ +public: + static const long MIN_LENGTH; + + CScrollerThumb(IScrollerBar *inScroller); + virtual ~CScrollerThumb(); + + virtual void Draw(CRenderer *inRenderer); + + virtual bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags); + virtual void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags); + + virtual CPt GetMinimumSize(); + +protected: + IScrollerBar *m_ScrollerBar; + bool m_MouseDown; + CPt m_MouseDownPoint; +}; + +#endif // INCLUDED_SCROLLER_THUMB_H \ No newline at end of file diff --git a/src/Authoring/Studio/Controls/SplashControl.cpp b/src/Authoring/Studio/Controls/SplashControl.cpp new file mode 100644 index 00000000..ea23f168 --- /dev/null +++ b/src/Authoring/Studio/Controls/SplashControl.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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 "SplashControl.h" +#include "Renderer.h" +#include "ResourceCache.h" +#include "StudioPreferences.h" +#include "OffscreenRenderer.h" +#include "StringLoader.h" +#include "StudioDefs.h" + +//============================================================================= +/** + * Constructor + */ +CSplashControl::CSplashControl() +{ + // Image + m_Image = CResourceCache::GetInstance()->GetBitmap("obsolete_placeholder.png"); + SetAbsoluteSize(m_Image.rect().bottomRight()); + + // First line of the copyright statement + m_CopyrightLine1.Format( + ::LoadResourceString(IDS_SPLASH_COPYRIGHT1), + static_cast(Q3DStudio::CString(STUDIO_COPYRIGHT_YEAR))); + + // Second line of the copyright statement + m_CopyrightLine2 = ::LoadResourceString(IDS_SPLASH_COPYRIGHT2); + + // Version text + m_VersionInfo.Format((::LoadResourceString(IDS_UIC_STUDIO_VERSION)), + static_cast(CStudioPreferences::GetVersionString())); + + // Calculate the number of pixels between each line of text + COffscreenRenderer theOffscreenRenderer(CRct(0, 0, 1, 1)); + auto size = theOffscreenRenderer.GetTextSize(m_CopyrightLine1.toQString()); + m_SpaceBetweenLines = size.height(); +} + +//============================================================================= +/** + * Destructor + */ +CSplashControl::~CSplashControl() +{ +} + +//============================================================================= +/** + * Draws the splash screen. + * @param inRenderer Renderer to draw to + */ +void CSplashControl::Draw(CRenderer *inRenderer) +{ + CRct theBounds(GetSize()); + CColor theTextColor(50, 50, 50); + long theVertOffset = GetSize().y / 2 - 14; ///< Last line of the copyright starts here + + // Splash screen bitmap + inRenderer->DrawBitmap(CPt(0, 0), m_Image); + + // Print the copyright text, starting at the last line and going up to the first line (just to + // make sure that we didn't move where the text ends) + inRenderer->DrawText(14, static_cast(theVertOffset), m_VersionInfo.toQString(), theBounds, + theTextColor); + theVertOffset -= m_SpaceBetweenLines; + inRenderer->DrawText(14, static_cast(theVertOffset), m_CopyrightLine2.toQString(), theBounds, + theTextColor); + theVertOffset -= m_SpaceBetweenLines; + inRenderer->DrawText(14, static_cast(theVertOffset), m_CopyrightLine1.toQString(), theBounds, + theTextColor); +} diff --git a/src/Authoring/Studio/Controls/SplashControl.h b/src/Authoring/Studio/Controls/SplashControl.h new file mode 100644 index 00000000..dbce104c --- /dev/null +++ b/src/Authoring/Studio/Controls/SplashControl.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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_SPLASH_CONTROL_H +#define INCLUDED_SPLASH_CONTROL_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Control.h" + + +#include +//============================================================================== +// Forwards +//============================================================================== + +//============================================================================= +/** + * Class responsible for drawing contents of a splash screen at program start-up. + */ +class CSplashControl : public CControl +{ +public: + CSplashControl(); + virtual ~CSplashControl(); + + void Draw(CRenderer *inRenderer) override; + +protected: + QPixmap m_Image; + Q3DStudio::CString m_CopyrightLine1; + Q3DStudio::CString m_CopyrightLine2; + Q3DStudio::CString m_VersionInfo; + long m_SpaceBetweenLines; ///< number of pixels between subsequent lines of the copyright + ///statement (calculated automatically) +}; + +#endif // INCLUDED_SPLASH_CONTROL_H \ No newline at end of file diff --git a/src/Authoring/Studio/Controls/SplitBar.cpp b/src/Authoring/Studio/Controls/SplitBar.cpp new file mode 100644 index 00000000..b37f60e9 --- /dev/null +++ b/src/Authoring/Studio/Controls/SplitBar.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" + +//============================================================================= +// Includes +//============================================================================= +#include "SplitBar.h" +#include "Renderer.h" +#include "ResourceCache.h" +#include "MouseCursor.h" +#include "StudioPreferences.h" +#include "HotKeys.h" + +#include +//============================================================================= +// Static Variables +//============================================================================= +const long CSplitBar::DEFAULT_WIDTH = 5; + +//============================================================================= +/** + * Constructor + */ +CSplitBar::CSplitBar(CSplitterBase *inSplitter, const long inWidth /*=DEFAULT_WIDTH*/) + : m_Splitter(inSplitter) + , m_Width(inWidth) + , m_MouseDown(false) +{ + +} + +//============================================================================= +/** + * Destructor + */ +CSplitBar::~CSplitBar() +{ +} + +//============================================================================= +/** + * Handles mouse down events, starts the dragging. + * @param inPoint where the mouse was clicked. + * @param inFlags the state of the mouse. + */ +bool CSplitBar::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseDown(inPoint, inFlags); + + m_MouseDown = true; + m_MouseDownPoint = inPoint; + + Invalidate(); + + return true; +} + +//============================================================================= +/** + * Handles mouse up events, stops the dragging. + * @param inPoint where the mouse was let up. + * @param inFlags the state of the mouse. + */ +void CSplitBar::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseUp(inPoint, inFlags); + + m_MouseDown = false; + + Invalidate(); +} + +//============================================================================= +/** + * Do the drawing of this splitter. + * @param inRenderer the renderer to draw to. + */ +void CSplitBar::Draw(CRenderer *inRenderer) +{ + CRct theRect(CPt(0, 0), GetSize()); + CRct theHighlightRect; + CRct theShadowRect; + + if (m_Splitter->GetSplitDirection() == CSplitterBase::SPLIT_HORIZONTAL) { + theHighlightRect.position = CPt(0, 0); + theHighlightRect.size = CPt(GetSize().x, 1); + theShadowRect.position = CPt(0, theRect.size.y - 1); + theShadowRect.size = CPt(theRect.size.x, 1); + } else { + theHighlightRect.position = CPt(0, 0); + theHighlightRect.size = CPt(1, GetSize().y); + theShadowRect.position = CPt(theRect.size.x - 1, 0); + theShadowRect.size = CPt(1, theRect.size.y); + } + + inRenderer->FillSolidRect(theRect, CStudioPreferences::GetBaseColor()); + inRenderer->FillSolidRect(theHighlightRect, CStudioPreferences::GetButtonHighlightColor()); + inRenderer->FillSolidRect(theShadowRect, CStudioPreferences::GetButtonShadowColor()); +} + +//============================================================================= +/** + * Get the width of this splitter bar. + */ +long CSplitBar::GetWidth() +{ + return m_Width; +} + +//============================================================================= +/** + * Set the width of this splitter bar. + */ +void CSplitBar::SetWidth(long inWidth) +{ + m_Width = inWidth; +} + +//============================================================================= +/** + * Processes the dragging of the split bar. + * @param inPoint the position of the mouse. + * @param inFlags the state of the mouse buttons. + */ +void CSplitBar::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseMove(inPoint, inFlags); + + const Qt::MouseButtons buttons = QApplication::mouseButtons(); + + // Don't show the cursor if the mouse is down from someone else. + if (!(buttons & Qt::LeftButton) && !(buttons & Qt::RightButton)) { + // If the buttons are not down and the mouse is over this control + if (HitTest(inPoint + GetPosition())) { + // Show the appropriate resize cursor + setCursorIfNotSet(m_Splitter->GetSplitDirection() == CSplitterBase::SPLIT_HORIZONTAL + ? CMouseCursor::CURSOR_RESIZE_UPDOWN + : CMouseCursor::CURSOR_RESIZE_LEFTRIGHT); + } else { + resetCursor(); + } + } + + // Only care if the mouse is down + if (m_MouseDown) { + // When calculating the offsets remember that this object is moving with the mouse + // and the inPoint is relative to this position, so inPoint's relative position is + // changing on every drag. + long theSplitPos = m_Splitter->GetSplitLocation(); + + if (m_Splitter->GetSplitDirection() == CSplitterBase::SPLIT_HORIZONTAL) { + theSplitPos += inPoint.y - m_MouseDownPoint.y; + } else { + theSplitPos += inPoint.x - m_MouseDownPoint.x; + } + + m_Splitter->SetSplitLocation(theSplitPos); + } +} + +//============================================================================= +/** + * Processes the mouse out event. Changes the cursor if necessary back to normal. + * @param inPoint the position of the mouse. + * @param inFlags the state of the mouse buttons. + */ +void CSplitBar::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + const Qt::MouseButtons buttons = QApplication::mouseButtons(); + // Don't change the cursor if the mouse is down (from someone else or from ourselves) + if (!m_MouseDown && !(buttons & Qt::LeftButton) && !(buttons & Qt::RightButton)) + resetCursor(); + CControl::OnMouseOut(inPoint, inFlags); +} diff --git a/src/Authoring/Studio/Controls/SplitBar.h b/src/Authoring/Studio/Controls/SplitBar.h new file mode 100644 index 00000000..f70b4469 --- /dev/null +++ b/src/Authoring/Studio/Controls/SplitBar.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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_SPLIT_BAR_H +#define INCLUDED_SPLIT_BAR_H 1 + +#pragma once + +//============================================================================= +// Includes +//============================================================================= +#include "Control.h" + +#include + +//============================================================================= +// Forwards +//============================================================================= + +//============================================================================= +/** + * Abstract class for implementing a splitter control + */ +class CSplitterBase +{ +public: + enum ESplitDirection { + SPLIT_VERTICAL, + SPLIT_HORIZONTAL, + }; + + virtual void SetSplitLocation(long inPixels) = 0; + virtual long GetSplitLocation() const = 0; + virtual ESplitDirection GetSplitDirection() const = 0; +}; + +//============================================================================= +/** + * Defines the bar used in a splitter control. Handles drawing and cursors for + * the bar. + */ +class CSplitBar : public CControl +{ +public: + static const long DEFAULT_WIDTH; + + CSplitBar(CSplitterBase *inSplitter, long inWidth = DEFAULT_WIDTH); + virtual ~CSplitBar(); + + 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; + + virtual long GetWidth(); + virtual void SetWidth(long inWidth); + +protected: + CSplitterBase *m_Splitter; + long m_Width; + + bool m_MouseDown; + CPt m_MouseDownPoint; +}; + +#endif // INCLUDED_SPLIT_BAR_H diff --git a/src/Authoring/Studio/Controls/Splitter.cpp b/src/Authoring/Studio/Controls/Splitter.cpp new file mode 100644 index 00000000..b0ae0eb0 --- /dev/null +++ b/src/Authoring/Studio/Controls/Splitter.cpp @@ -0,0 +1,419 @@ +/**************************************************************************** +** +** 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 "Splitter.h" +#include "ControlData.h" + +using namespace Q3DStudio; +using namespace Q3DStudio::Control; +//============================================================================= +/** + * Constructor, creates a Splitter. + */ +CSplitter::CSplitter() + : m_SplitDirection(SPLIT_VERTICAL) + , m_SplitLocation(0) + , m_InRecalcLayoutFlag(false) +{ + m_SplitMinMargin = 10; + m_SplitMaxMargin = 10; + m_SplitBar = new CSplitBar(this); + AddChild(m_SplitBar); +} + +CSplitter::~CSplitter() +{ + RemoveChild(m_SplitBar); + delete m_SplitBar; +} + +//============================================================================= +/** + * Set the size of this splitter. + * @param inSize the size of this splitter. + */ +void CSplitter::SetSize(CPt inSize) +{ + if (inSize != GetSize()) { + CControl::SetSize(inSize); + + RecalcLayout(); + } +} + +void CSplitter::SetLayout(CPt inSize, CPt inPosition) +{ + CControl::SetLayout(inSize, inPosition); + RecalcLayout(); +} + +//============================================================================= +/** + * Get the preferred size of this splitter. + * The preferred size is the sum of both the panes. + * @return the preferred size of this splitter. + */ +CPt CSplitter::GetPreferredSize() +{ + CPt theSize = CControl::GetPreferredSize(); + + if (m_SplitDirection == SPLIT_VERTICAL) { + theSize.x = m_SplitBar->GetWidth(); + + // If vertical then sum up x's + ControlGraph::SIterator thePos = GetChildren(); + for (; thePos.HasNext(); ++thePos) { + CPt thePrefSize = (*thePos)->GetPreferredSize(); + theSize.x += thePrefSize.x; + } + } else { + theSize.y = m_SplitBar->GetWidth(); + + // If horizontal then sum up y's + ControlGraph::SIterator thePos = GetChildren(); + for (; thePos.HasNext(); ++thePos) { + CPt thePrefSize = (*thePos)->GetPreferredSize(); + theSize.y += thePrefSize.y; + } + } + + return theSize; +} + +//============================================================================= +/** + * Get the minimum allowable size of this splitter. + * The minimum size is the sum of both the minimum sizes in the split direciton + * and the largest minimum in the non-split direction. + * @return the minimum size of this control. + */ +CPt CSplitter::GetMinimumSize() +{ + CPt theSize(0, 0); + + if (m_SplitDirection == SPLIT_VERTICAL) { + theSize.x += m_SplitBar->GetWidth(); + + // Sum up in the split direction and take max min size in non-split direction + ControlGraph::SIterator thePos = GetChildren(); + for (; thePos.HasNext(); ++thePos) { + CPt theMinSize = (*thePos)->GetMinimumSize(); + theSize.x += theMinSize.x; + + if (theSize.y < theMinSize.y) { + theSize.y = theMinSize.y; + } + } + } else { + theSize.y += m_SplitBar->GetWidth(); + + // Sum up in the split direction and take max min size in non-split direction. + ControlGraph::SIterator thePos = GetChildren(); + for (; thePos.HasNext(); ++thePos) { + CPt theMinSize = (*thePos)->GetMinimumSize(); + theSize.y += theMinSize.y; + + if (theSize.x > theMinSize.x) { + theSize.x = theMinSize.x; + } + } + } + + return theSize; +} + +//============================================================================= +/** + * Get the maximum size that this control should be. + * The maximum size is the sum of both the maximum sizes in the split direction + * and the smalled maximum size in the non-split direction. + * @return the maximum size of this control. + */ +CPt CSplitter::GetMaximumSize() +{ + CPt theSize(0, 0); + + if (m_SplitDirection == SPLIT_VERTICAL) { + theSize.x += m_SplitBar->GetWidth(); + theSize.y = LONG_MAX; + + // Sum up the split direction and take min max size in non-split direction. + ControlGraph::SIterator thePos = GetChildren(); + // Skip the separator + ++thePos; + for (; thePos.HasNext(); ++thePos) { + CPt theMaxSize = (*thePos)->GetMaximumSize(); + theSize.x += theMaxSize.x; + + if (theSize.y > theMaxSize.y) { + theSize.y = theMaxSize.y; + } + } + } else { + theSize.y += m_SplitBar->GetWidth(); + theSize.x = LONG_MAX; + + // Sum up the split direction and take min max size in the non-split direction. + ControlGraph::SIterator thePos = GetChildren(); + // Skip the separator. + ++thePos; + for (; thePos.HasNext(); ++thePos) { + CPt theMaxSize = (*thePos)->GetMaximumSize(); + theSize.y += theMaxSize.y; + + if (theSize.x > theMaxSize.x) { + theSize.x = theMaxSize.x; + } + } + } + + return theSize; +} + +//============================================================================= +/** + * Set the location of the splitter bar. + * @param inSplitLocation the location of the splitter bar, in pixels from the right/top. + */ +void CSplitter::SetSplitLocation(long inSplitLocation) +{ + ControlGraph::SIterator theChildren = GetChildren(); + + std::shared_ptr theControl1; + std::shared_ptr theControl2; + ++theChildren; + if (theChildren.HasNext()) { + theControl1 = *theChildren; + + ++theChildren; + if (theChildren.HasNext()) { + theControl2 = *theChildren; + } + } + if (m_SplitDirection == SPLIT_VERTICAL && theControl1) { + CPt theControl1Min = theControl1->GetMinimumSize(); + if (theControl1Min.x > inSplitLocation) + inSplitLocation = theControl1Min.x; + } else if (theControl2) { + CPt theControl1Min = theControl1->GetMinimumSize(); + if (theControl1Min.y > inSplitLocation && theControl2) + inSplitLocation = theControl1Min.y; + } + m_SplitLocation = inSplitLocation; + + RecalcLayout(); +} + +//============================================================================= +/** + * Get the location of the splitter bar. + * @return the location of the splitter bar, in pixels from the right/top. + */ +long CSplitter::GetSplitLocation() const +{ + long theSplitLocation = m_SplitLocation; + + // Enforce the max margin and then the min margin (in that order) + // this is done on the get so that internally we maintain + // the correct location of the splitter + if (m_SplitDirection == SPLIT_VERTICAL) { + if (m_SplitLocation > GetSize().x - m_SplitMaxMargin /*- m_SplitBar->GetWidth( )*/) + theSplitLocation = GetSize().x - m_SplitMaxMargin /*- m_SplitBar->GetWidth( )*/; + } else { + if (m_SplitLocation > GetSize().y - m_SplitMaxMargin) + theSplitLocation = GetSize().y - m_SplitMaxMargin; + } + + if (m_SplitLocation < m_SplitMinMargin) + theSplitLocation = m_SplitMinMargin; + + return theSplitLocation; +} + +//============================================================================= +/** + * Set the minimum and maximum split location. This will limit the splitter + * left and right or up and down. + * @param inSplitMinMargin the number of pixels from the left/top of the pane + * @param inSplitMaxMargin the number of pixels from the right/bottom of the pane. + */ +void CSplitter::SetSplitLimits(long inSplitMinMargin, long inSplitMaxMargin) +{ + m_SplitMinMargin = inSplitMinMargin; + m_SplitMaxMargin = inSplitMaxMargin; +} + +//============================================================================= +/** + * Set the direction that this is being split in. + * @param inSplitDirection the direction that this is being split in. + */ +void CSplitter::SetSplitDirection(CSplitterBase::ESplitDirection inSplitDirection) +{ + m_SplitDirection = inSplitDirection; + RecalcLayout(); +} + +//============================================================================= +/** + * Get the direction that this is being split in. + * @return the direction that this is being split in. + */ +CSplitterBase::ESplitDirection CSplitter::GetSplitDirection() const +{ + return m_SplitDirection; +} + +//============================================================================= +/** + * Add a child to this splitter. + * If more than 2 children are added then this will pop off the last one to be + * added before inControl. + * @param inControl the control to add to this. + * @param inInsertAfter the position to inster the control. + */ +void CSplitter::AddChild(CControl *inControl, CControl *inInsertAfter /*=nullptr*/) +{ + CControl::AddChild(inControl, inInsertAfter); + + // If there are more than 3 objects then ditch the last one, allows the insert after to still + // work. + if (GetChildCount() > 3) + RemoveChild(GetReverseChildren().GetCurrent()->GetControl()); + + RecalcLayout(); +} + +void CSplitter::RecalcLayout() +{ + CPt thePoint(0, 0); + CPt theSize = GetSize(); + + std::shared_ptr theControl1; + std::shared_ptr theControl2; + + long theSplitLocation = GetSplitLocation(); + + ControlGraph::SIterator theChildren = GetChildren(); + ++theChildren; + if (theChildren.HasNext()) { + theControl1 = *theChildren; + + ++theChildren; + if (theChildren.HasNext()) { + theControl2 = *theChildren; + } + } + + // Prevent OnChildSizeChanged from screwing with us + m_InRecalcLayoutFlag = true; + + if (theControl2 != nullptr) { + CPt theControl1Max = theControl1->GetMaximumSize(); + CPt theControl2Max = theControl2->GetMaximumSize(); + + if (m_SplitDirection == SPLIT_VERTICAL) { + CPt theControl1Min = theControl1->GetMinimumSize(); + if (theControl1Min.x > theSplitLocation) { + theSplitLocation = theControl1Min.x; + } + theControl1->SetPosition(CPt(0, 0)); + theControl1->SetSize(CPt(theSplitLocation, min(theSize.y, theControl1Max.y))); + + m_SplitBar->SetPosition(CPt(theSplitLocation, 0)); + m_SplitBar->SetSize(CPt(m_SplitBar->GetWidth(), theSize.y)); + + theControl2->SetPosition(CPt(theSplitLocation + m_SplitBar->GetWidth(), 0)); + theControl2->SetSize(CPt(theSize.x - (theSplitLocation + m_SplitBar->GetWidth()), + min(theSize.y, theControl2Max.y))); + } else { + CPt theControl1Min = theControl1->GetMinimumSize(); + if (theControl1Min.y > theSplitLocation) { + theSplitLocation = theControl1Min.y; + } + theControl1->SetPosition(CPt(0, 0)); + theControl1->SetSize(CPt(min(theSize.x, theControl1Max.x), theSplitLocation)); + + m_SplitBar->SetPosition(CPt(0, theSplitLocation)); + m_SplitBar->SetSize(CPt(theSize.x, m_SplitBar->GetWidth())); + + theControl2->SetPosition(CPt(0, theSplitLocation + m_SplitBar->GetWidth())); + theControl2->SetSize(CPt(min(theSize.x, theControl2Max.x), + theSize.y - (theSplitLocation + m_SplitBar->GetWidth()))); + } + } + + m_InRecalcLayoutFlag = false; + + Invalidate(); +} + +void CSplitter::OnChildSizeChanged(CControl *) +{ + if (m_InRecalcLayoutFlag == false) { + std::shared_ptr theControl1; + std::shared_ptr theControl2; + + ControlGraph::SIterator theChildren = GetChildren(); + ++theChildren; + if (theChildren.HasNext()) { + theControl1 = *theChildren; + + ++theChildren; + if (theChildren.HasNext()) { + theControl2 = *theChildren; + } + } + + CPt theSize = GetSize(); + if (theControl2 != nullptr) { + CPt theSize1 = theControl1->GetSize(); + CPt theSize2 = theControl2->GetSize(); + if (m_SplitDirection == SPLIT_VERTICAL) + theSize.y = max(theSize1.y, theSize2.y); + else + theSize.x = max(theSize1.x, theSize2.x); + } + + SetSize(theSize); + SetMaximumSize(theSize); + + RecalcLayout(); + } + + // Notify the folks + if (GetParent() != nullptr) + GetParent()->OnChildSizeChanged(this); +} + +void CSplitter::SetSplitBarWidth(const long inWidth) +{ + m_SplitBar->SetWidth(inWidth); +} \ No newline at end of file diff --git a/src/Authoring/Studio/Controls/Splitter.h b/src/Authoring/Studio/Controls/Splitter.h new file mode 100644 index 00000000..94c70781 --- /dev/null +++ b/src/Authoring/Studio/Controls/Splitter.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_SPLIT_AGENT_H +#define INCLUDED_SPLIT_AGENT_H 1 + +#pragma once + +#include "SplitBar.h" + +class CSplitter : public CControl, public CSplitterBase +{ +public: + CSplitter(); + virtual ~CSplitter(); + + virtual void SetSize(CPt inSize); + virtual void SetLayout(CPt inSize, CPt inPosition); + virtual CPt GetPreferredSize(); + virtual CPt GetMinimumSize(); + virtual CPt GetMaximumSize(); + + // CSplitterBase + virtual void SetSplitLocation(long inPixels); + virtual long GetSplitLocation() const; + virtual ESplitDirection GetSplitDirection() const; + + virtual void SetSplitLimits(long inSplitMinMargin, long inSplitMaxMargin); + virtual void SetSplitDirection(CSplitterBase::ESplitDirection inSplitDirection); + + virtual void AddChild(CControl *inControl, CControl *inInsertBefore = nullptr); + + virtual void OnChildSizeChanged(CControl *inChild); + + virtual void SetSplitBarWidth(const long inWidth); + +protected: + void RecalcLayout(); + + ESplitDirection m_SplitDirection; + long m_SplitLocation; + long m_SplitMinMargin; + long m_SplitMaxMargin; + CSplitBar *m_SplitBar; + bool m_InRecalcLayoutFlag; +}; + +#endif // INCLUDED_SPLIT_AGENT_H \ No newline at end of file diff --git a/src/Authoring/Studio/Controls/StringEdit.cpp b/src/Authoring/Studio/Controls/StringEdit.cpp new file mode 100644 index 00000000..34b5f521 --- /dev/null +++ b/src/Authoring/Studio/Controls/StringEdit.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" + +//============================================================================== +// Include +//============================================================================== +#include "StringEdit.h" +#include "OffscreenRenderer.h" +#include "CoreUtils.h" + +//============================================================================== +/** + * Constructor + */ +CStringEdit::CStringEdit() + : m_AutoSize(false) +{ + // StringEdit is going to have to handle its own RevertText. + // This can't be done in TextEdit because FloatEdit ( VectorEdit, etc ) are using the command + // stack for undo/redo + // StringEdit doesn't have command stack set until you hit enter or lose focus. + // We can't make CTextEdit::RegisterCommands a virtual function since its being called in the + // constructor, + // therefore this is a pretty lame way to register for a hotkey. + m_CommandHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CStringEdit::RevertText), + Qt::ControlModifier, Qt::Key_Z); +} + +//============================================================================== +/** + * Destructor + */ +CStringEdit::~CStringEdit() +{ +} + +//============================================================================== +/** + * Returns the string value of the control. + */ +Q3DStudio::CString CStringEdit::GetString() +{ + return m_Value; +} + +//============================================================================== +/** + * Sets the string value of the control. + */ +void CStringEdit::SetData(const Q3DStudio::CString &inValue, bool inFireEvent /*= true*/) +{ + if (m_Value != inValue) { + m_Value = inValue; + SetDisplayString(inValue, inFireEvent); + + if (inFireEvent) + SetDirty(true); + } +} + +//============================================================================== +/** + * Commits changes to the value of this control when the control loses focus. + */ +void CStringEdit::OnLoseFocus() +{ + CTextEdit::OnLoseFocus(); + FireCommitEvent(); +} + +//============================================================================== +/** + * Commits changes to the value of this control when the Enter button is pressed. + * @param inHighlight true to highlight the text after committing it + */ +void CStringEdit::EnterText(bool inHighlight) +{ + CTextEdit::EnterText(inHighlight); + FireCommitEvent(); +} + +void CStringEdit::RefreshDisplayFromData() +{ + SetDisplayString(GetString()); + Invalidate(); +} + +bool CStringEdit::CanPaste() +{ + return true; +} + +//============================================================================== +/** + * Enables or disables auto-sizing of this control. If auto-sizing is enabled + * the size of this control will be automatically set to fit the text that it + * contains. + * @param inAllow true to enable auto-sizing, false to disable auto-sizing + */ +void CStringEdit::AllowAutoSize(bool inAllow) +{ + m_AutoSize = inAllow; +} + +//============================================================================== +/** + * @return true if auto-resizing is enabled, otherwise false + */ +bool CStringEdit::GetAllowAutoSize() +{ + return m_AutoSize; +} + +//============================================================================== +/** + * If auto-resizing is enabled, this function will resize this control so that + * it is the same size as the text that it is displaying. Text size is calculated + * with an offscreen buffer, so this can be done outside of a draw operation. + */ +void CStringEdit::ResetSize() +{ + // If auto-resizing of the text field is enabled + if (m_AutoSize) { + // Resize the control to fit the text, plus the buffer gap + COffscreenRenderer theRenderer(CRct(0, 0, 100, 16)); + CPt theSize; + const auto textSize = theRenderer.GetTextSize(GetDisplayString().toQString()); + theSize.x = textSize.width() + GetBufferLength() * 3; + theSize.y = textSize.height() + 1; + SetMinimumSize(theSize); + SetPreferredSize(theSize); + SetMaximumSize(theSize); + } +} + +//============================================================================== +/** + * Primarily delegates up to the parent class, but responds by recalculating + * size of the text box for auto-sized strings. + * + * @param inDirty true to mark this control as dirty, which causes the string to be redrawn + * false to mark the control as not needing to reevaluate its text during next draw cycle + */ +void CStringEdit::SetDirty(bool inDirty) +{ + // Allow the parent to handle this situation + CTextEdit::SetDirty(inDirty); + + ResetSize(); +} + +//============================================================================== +/** + * Reverts the displayed text to the previous text. + */ +void CStringEdit::RevertText() +{ + SetData(m_PreviousValue); + SetDisplayString(m_PreviousValue); + + FireCommitEvent(); + SelectAllText(); +} + +//============================================================================== +/** + * Handles any non-character keys that were pressed and need to be handled. + * + * @param inChar The key that was pressed + * @param inFlags Indicates which modifier keys were down when event occurred + * @return true if this function handled the character, otherwise false + */ +bool CStringEdit::HandleSpecialChar(unsigned int inChar, Qt::KeyboardModifiers inFlags) +{ + bool theMessageWasHandled = false; + + switch (inChar) { + // Escape and Ctrl+Z both do basically the same thing for StringEdits, + // They are special cased in TextEditInPlace though. + case Qt::Key_Escape: + RevertText(); + theMessageWasHandled = true; + break; + + default: + theMessageWasHandled = CTextEdit::HandleSpecialChar(inChar, inFlags); + } + + return theMessageWasHandled; +} + +//============================================================================== +/** + * Called when this control gains focus. Shows the caret, clears the current + * selection and invalidates the control so that it will get redrawn. + */ +void CStringEdit::OnGainFocus() +{ + CTextEdit::OnGainFocus(); + m_PreviousValue = GetString(); +} + +//============================================================================= +/** + * Handles character input from the keyboard. + * + * @param inChar Character that was pressed + * @return true if the character was handled, false if this control does not + * care about the character that was pressed + */ +bool CStringEdit::OnChar(const QString &inChar, Qt::KeyboardModifiers inFlags) +{ + return CTextEdit::OnChar(inChar, inFlags); +} diff --git a/src/Authoring/Studio/Controls/StringEdit.h b/src/Authoring/Studio/Controls/StringEdit.h new file mode 100644 index 00000000..8f3c34b1 --- /dev/null +++ b/src/Authoring/Studio/Controls/StringEdit.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** 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_STRING_EDIT_H +#define INCLUDED_STRING_EDIT_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +#include "TextEdit.h" + +class CStringEdit : public CTextEdit +{ +public: + CStringEdit(); + virtual ~CStringEdit(); + Q3DStudio::CString GetString() override; + void SetData(const Q3DStudio::CString &inValue, bool inFireEvent = true) override; + void OnLoseFocus() override; + void EnterText(bool inHighlight) override; + void RefreshDisplayFromData() override; + bool CanPaste() override; + virtual void ResetSize(); + void AllowAutoSize(bool inAllow); + bool GetAllowAutoSize(); + + // overload functions + bool HandleSpecialChar(unsigned int inChar, Qt::KeyboardModifiers inFlags) override; + void OnGainFocus() override; + bool OnChar(const QString &inChar, Qt::KeyboardModifiers inFlags) override; + +protected: + Q3DStudio::CString m_Value; + Q3DStudio::CString m_PreviousValue; + bool m_AutoSize; + + virtual void RevertText(); + void SetDirty(bool inDirty) override; +}; + +#endif // INCLUDED_STRING_EDIT_H diff --git a/src/Authoring/Studio/Controls/TextButton.h b/src/Authoring/Studio/Controls/TextButton.h new file mode 100644 index 00000000..2593a1d1 --- /dev/null +++ b/src/Authoring/Studio/Controls/TextButton.h @@ -0,0 +1,350 @@ +/**************************************************************************** +** +** 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_TEXT_BUTTON_H +#define INCLUDED_TEXT_BUTTON_H 1 +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Renderer.h" +#include "OffscreenRenderer.h" +#include "CoreUtils.h" +#include "StudioPreferences.h" +#include "ButtonControl.h" +#include "CColor.h" + +#include + +const long MARGIN_X = 12; +const long MARGIN_Y = 6; + +//============================================================================= +/** + * Template class for making buttons that have text on them. The text can be + * displayed with or without the button's icon. In order to use this class, + * you must instantiate it with some sort of CButtonControl to act as the base + * class. + */ +template +class CTextButton : public TButton +{ + // Enumerations +public: + enum EAlignment { + ALIGNMENT_LEFT, + ALIGNMENT_CENTER, + ALIGNMENT_RIGHT, + ALIGNMENT_VCENTER ///< Only align center vertically + }; + + // Constuction/Destruction +public: + CTextButton(); + virtual ~CTextButton(); + // Access +public: + void SetText(const Q3DStudio::CString &inText); + void SetBoldText(const Q3DStudio::CString &inText); + Q3DStudio::CString GetText(); + void SetTextColorUp(const CColor &inColor); + void SetTextColorDown(const CColor &inColor); + CColor GetTextColorUp(); + CColor GetTextColorDown(); + void SetTextAlignment(EAlignment inAlignment); + long GetTextAlignment(); + + // Implementation +protected: + virtual void Render(CRenderer *inRenderer); + virtual void Resize(); + void SizeToFitTextLen(); + + // Field members +protected: + Q3DStudio::CString m_Text; ///< Text + CColor m_TextColorUp; ///< Color of text + CColor m_TextColorDown; ///< Color of text + CPt m_TextPos; ///< Position of text + EAlignment m_TextAlign; ///< Alignment of text + BOOL m_BoldText; +}; + +//============================================================================== +// Template implemenations +//============================================================================== + +//============================================================================= +/** + * Constructor + */ +template +CTextButton::CTextButton() + : TButton() + , m_TextColorUp(CStudioPreferences::GetNormalColor()) + , m_TextColorDown(CStudioPreferences::GetNormalColor()) + , m_TextPos(MARGIN_X, MARGIN_Y / 2) + , m_TextAlign(ALIGNMENT_LEFT) + , m_BoldText(FALSE) +{ +} + +//============================================================================= +/** + * Destructor + */ +template +CTextButton::~CTextButton() +{ +} + +//============================================================================= +/** + * Sets the text displayed on this button to the specified string. + * @param inText new text to be displayed on this button + */ +template +void CTextButton::SetText(const Q3DStudio::CString &inText) +{ + if (m_Text != inText) { + m_Text = inText; + SizeToFitTextLen(); + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * Sets the text bold to be displayed on this button to the specified string. + * @param inText new text to be displayed on this button + */ +template +void CTextButton::SetBoldText(const Q3DStudio::CString &inText) +{ + m_Text = inText; + m_BoldText = TRUE; + SizeToFitTextLen(); + TButton::Invalidate(); +} + +//============================================================================= +/** + * @return the text currently displayed on this button + */ +template +Q3DStudio::CString CTextButton::GetText() +{ + return m_Text; +} + +//============================================================================= +/** + * Sets the color of the text displayed on this button in the up state + * @param inColor new text color + */ +template +void CTextButton::SetTextColorUp(const CColor &inColor) +{ + if (m_TextColorUp != inColor) { + m_TextColorUp = inColor; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * Sets the color of the text displayed on this button in the down state + * @param inColor new text color + */ +template +void CTextButton::SetTextColorDown(const CColor &inColor) +{ + if (m_TextColorDown != inColor) { + m_TextColorDown = inColor; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * @return the color of the text displayed on this button in the up state + */ +template +CColor CTextButton::GetTextColorUp() +{ + return m_TextColorUp; +} + +//============================================================================= +/** + * @return the color of the text displayed on this button in the down state + */ +template +CColor CTextButton::GetTextColorDown() +{ + return m_TextColorDown; +} + +//============================================================================= +/** + * Set the alignment of the text. + */ +template +void CTextButton::SetTextAlignment(EAlignment inAlignment) +{ + if (inAlignment != m_TextAlign) { + m_TextAlign = inAlignment; + TButton::Invalidate(); + } +} + +//============================================================================= +/** + * @return the alignment of the text displayed on this button + */ +template +long CTextButton::GetTextAlignment() +{ + return m_TextAlign; +} + +//============================================================================= +/** + * Draws the button, then draws the specified text onto the button. + * @param inRenderer the renderer to draw to + */ +template +void CTextButton::Render(CRenderer *inRenderer) +{ + // Draw the button icon + TButton::Render(inRenderer); + + // Detertmine position of text based off horizontal alignment + float theTextPosX(static_cast(m_TextPos.x)); + float theTextPosY(static_cast(m_TextPos.y)); + + long theImageX = 0; + long theImageY = 0; + if (!TButton::GetCurrentImage().isNull()) { + theImageX += TButton::GetCurrentImage().size().width(); + theImageY += TButton::GetCurrentImage().size().height(); + } + + switch (m_TextAlign) { + case ALIGNMENT_CENTER: { + const auto textSize = inRenderer->GetTextSize(m_Text.toQString()); + theTextPosX = (TButton::GetSize().x - textSize.width() + theImageX) / 2; + theTextPosY = static_cast(m_TextPos.y); + } break; + + case ALIGNMENT_RIGHT: { + const auto textSize = inRenderer->GetTextSize(m_Text.toQString()); + theTextPosX = TButton::GetSize().x - textSize.width(); + theTextPosY = static_cast(m_TextPos.y); + } break; + + case ALIGNMENT_VCENTER: { + const auto textSize = inRenderer->GetTextSize(m_Text.toQString()); + theTextPosY = (TButton::GetSize().y - textSize.height() + theImageY) / 2; + theTextPosX = static_cast(m_TextPos.x); + } + // Default is LEFT justification + default: + case ALIGNMENT_LEFT: + theTextPosX += theImageX; + break; + } + + typename TButton::EButtonState theState = TButton::GetButtonState(); + ::CColor theTextColor = m_TextColorUp; + if (theState == CButtonControl::EBUTTONSTATE_DOWN) + theTextColor = m_TextColorDown; + if (TButton::IsEnabled() == false) + theTextColor = CStudioPreferences::GetDisabledTextColor(); + + inRenderer->PushPen(theTextColor); + + // Draw the text + const auto buttonSize = TButton::GetSize(); + const QRect rect(0, 0, buttonSize.x, buttonSize.y); + if (m_BoldText && !m_Text.IsEmpty()) { + inRenderer->DrawBoldText(theTextPosX, theTextPosY, m_Text.toQString(), rect, theTextColor); + } else { + if (!m_Text.IsEmpty()) + inRenderer->DrawText(theTextPosX, theTextPosY, m_Text.toQString(), rect, theTextColor); + } + + inRenderer->PopPen(); +} + +//============================================================================= +/** + * this function calculates the text length in the button control and sets the size of the + *button + */ +template +void CTextButton::Resize() +{ + TButton::Resize(); + SizeToFitTextLen(); +} + +//============================================================================= +/** + * this function calculates the text length in the button control and sets the size of the + *button + */ +template +void CTextButton::SizeToFitTextLen() +{ + // If auto-resizing of the text field is enabled + if (TButton::m_AutoSize) { + // Resize the control to fit the text, plus the buffer gap + COffscreenRenderer theRenderer(CRct(0, 0, 1, 1)); + CPt theSize; + const auto textSize = theRenderer.GetTextSize(m_Text.toQString()); + int theX = textSize.width(); + int theY = textSize.height(); + + if (!TButton::GetCurrentImage().isNull()) + theX += TButton::GetCurrentImage().size().width(); + + // MARGIN_LEN * 2 is just to add some space between the text and the button + theSize.x = ::dtol(theX) + (MARGIN_X * 2); + theSize.y = static_cast(theY + (MARGIN_Y * 2)); + TButton::SetSize(theSize); + TButton::SetMaximumSize(theSize); + TButton::Invalidate(); + } +} +#endif // INCLUDED_TEXT_BUTTON_H diff --git a/src/Authoring/Studio/Controls/TextEdit.cpp b/src/Authoring/Studio/Controls/TextEdit.cpp new file mode 100644 index 00000000..76f925e1 --- /dev/null +++ b/src/Authoring/Studio/Controls/TextEdit.cpp @@ -0,0 +1,1478 @@ +/**************************************************************************** +** +** 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 "TextEdit.h" +#include "Renderer.h" +#include "SystemPreferences.h" +#include "HotKeys.h" +#include "TextEditContextMenu.h" +#include "StudioClipboard.h" +#include "CoreUtils.h" +#include "UICMath.h" +#include "UICDMSignals.h" +#include "MouseCursor.h" +#include "StudioApp.h" +#include "Core.h" + +#include + +using namespace Q3DStudio; + +//============================================================================== +// Constants +//============================================================================== +const long BLINKSPEED = + 700; ///< Speed of the blinking cursor while editing, measured in milliseconds + +IMPLEMENT_OBJECT_COUNTER(CTextEdit) + +// using namespace Q3DStudio; <-- Do not do this here because it will conflict with CList and make +// the template generator go blah + +//============================================================================== +/** + * Constructor + */ +CTextEdit::CTextEdit() + : m_IsStringDirty(true) + , m_NeedsCommit(false) + , m_Alignment(RIGHT) + , m_TotalCharWidth(0) + , m_BufferLength(2) + , m_MaxLength(QT3DS_MAX_I32) + , m_IsReadOnly(false) + , m_MouseIsDown(false) + , m_FillBackground(true) + , m_TextColor(0, 0, 0) + , m_UseBGColorReadOnly(false) + , m_BackgroundColorNoFocus(CStudioPreferences::GetTextBoxBGColorNoFocus()) + , m_BackgroundColorFocus(CStudioPreferences::GetTextBoxBGColorWithFocus()) + , m_BoldText(false) + , m_ScrollAmount(0, 0) + , m_CommandHandler(g_StudioApp.GetCore()->GetHotKeys()) +{ + ADDTO_OBJECT_COUNTER(CTextEdit) + + m_Caret.color = ::CColor(0, 0, 0); + m_Caret.position = 0; + m_Caret.show = false; + + m_StartDragPt = CPt(0, 0); + m_SelectionStart = 0; + m_SelectionEnd = 0; + + m_TextColor = CStudioPreferences::GetRulerTickColor(); + + RegisterCommands(); +} + +//============================================================================== +/** + * Destructor + */ +CTextEdit::~CTextEdit() +{ + m_TimerConnection = std::shared_ptr(); + + REMOVEFROM_OBJECT_COUNTER(CTextEdit) + + // Added to help debug freeing memory allocated from inside a DLL + m_DisplayString.Clear(); +} + +//============================================================================== +/** + * Sets text justification to left, right, or center. + * + * @param inAlignment Enumeration describing the t3xt justification + */ +void CTextEdit::SetAlignment(EAlignment inAlignment) +{ + m_Alignment = inAlignment; +} + +//============================================================================== +/** + * Draws the bounding rectangle and white edit box for the text edit class. Also + * draws the actual text in the box by calling GetString(), which should be + * implemented by any class that extends CTextEdit. + */ +void CTextEdit::Draw(CRenderer *inRenderer) +{ + inRenderer->PushClippingRect(QRect(0, 0, GetSize().x, GetSize().y)); + + // If the string has changed since we last drew it, cache the character widths + if (m_IsStringDirty) { + CalculateCharWidths(inRenderer); + SetDirty(false); + } + + DoFillBackground(inRenderer); + + // Draw the actual text + DrawText(inRenderer); + + // Draw the caret last + DrawCaret(inRenderer); + + inRenderer->PopClippingRect(); +} + +//============================================================================== +/** + * Determines the bounding rectangle for the text based on the text justification + * setting. + * + * @return the bounding rectangle for the text being displayed. + */ +CRct CTextEdit::GetTextRect() +{ + CRct theTextRect; + + switch (m_Alignment) { + case LEFT: + theTextRect = CRct(CPt(m_BufferLength, 0), CPt(::dtol(m_TotalCharWidth), GetSize().y)); + break; + + case CENTER: + theTextRect = CRct(CPt(GetSize().x / 2 - ::dtol(m_TotalCharWidth / 2), 0), + CPt(::dtol(m_TotalCharWidth), GetSize().y)); + break; + + case RIGHT: + // NO BREAK + default: { + theTextRect = CRct(CPt(GetSize().x - ::dtol(m_TotalCharWidth + m_BufferLength), 0), + CPt(::dtol(m_TotalCharWidth), GetSize().y)); + } break; + } + + return theTextRect; +} + +//============================================================================== +/** + * Draws the text out to the screen. If any selection is occurring, the + * appropriate text is rendered out to the screen using the system preferences + * for selection color. + * + * @param inRenderer Renderer to draw the text out to + */ +void CTextEdit::DrawText(CRenderer *inRenderer) +{ + Q3DStudio::CString theCompleteString = GetDisplayString(); + Q3DStudio::CString theFirstPart = theCompleteString; + Q3DStudio::CString theHighlightedString; + Q3DStudio::CString theLastPart; + + float theTextSizeX; + float theTextSizeY; + + if (HasSelectedText()) { + theFirstPart = theCompleteString.Extract(0, GetSelectionLeft()); + theHighlightedString = + theCompleteString.Extract(GetSelectionLeft(), GetSelectionRight() - GetSelectionLeft()); + theLastPart = theCompleteString.Extract(GetSelectionRight(), + theCompleteString.Length() - GetSelectionRight()); + } + + // Calculate where the upper left corner where text begins (we'll move this point for each part + // of the text) + float theUpperLeftX = static_cast(GetTextRect().position.x + m_ScrollAmount.x); + float theUpperLeftY = static_cast(GetTextRect().position.y + m_ScrollAmount.y); + + const QRect sizeRect(0, 0, GetSize().x, GetSize().y); + CRct theSelectionRect(0, 0, 0, 0); + + if (theFirstPart.Length() > 0) { + if (!m_BoldText) { + inRenderer->DrawText(theUpperLeftX, theUpperLeftY, theFirstPart.toQString(), + CRct(GetSize()), m_TextColor); + } else { + inRenderer->DrawBoldText(theUpperLeftX, theUpperLeftY, theFirstPart.toQString(), + CRct(GetSize()), m_TextColor); + } + + // Move the upper left corner + const auto textSize = inRenderer->GetTextSize(theFirstPart.toQString()); + theTextSizeX = textSize.width(); + theTextSizeY = textSize.height(); + theUpperLeftX += theTextSizeX; + } + + if (theHighlightedString.Length() > 0) { + // Draw the selection rectangle + const auto textSize = inRenderer->GetTextSize(theHighlightedString.toQString()); + theTextSizeX = textSize.width(); + theTextSizeY = textSize.height(); + theSelectionRect.position.x = ::dtol(theUpperLeftX); + theSelectionRect.size = CPt(::dtol(theTextSizeX), ::dtol(theTextSizeY) + 2); + + // If the caret is at the far right of the selection, shrink the highlight rect by one + // pixel. This is so that you can actually see the blinking cursor on the right edge. + if (static_cast(m_Caret.position) == GetSelectionRight()) + --theSelectionRect.size.x; + + inRenderer->FillSolidRect(theSelectionRect, CSystemPreferences::GetSelectedItemColor()); + + // Draw the actual text in the highlight color + if (!m_BoldText) { + inRenderer->DrawText(theUpperLeftX, theUpperLeftY, theHighlightedString.toQString(), + sizeRect, CSystemPreferences::GetSelectedTextColor()); + } else { + inRenderer->DrawBoldText(theUpperLeftX, theUpperLeftY, theHighlightedString.toQString(), + sizeRect, CSystemPreferences::GetSelectedTextColor()); + } + + // Move the upper left corner + theUpperLeftX += theTextSizeX; + } + + if (theLastPart.Length() > 0) { + if (!m_BoldText) { + inRenderer->DrawText(theUpperLeftX, theUpperLeftY, theLastPart.toQString(), sizeRect, + m_TextColor); + } else { + inRenderer->DrawBoldText(theUpperLeftX, theUpperLeftY, theLastPart.toQString(), sizeRect, + m_TextColor); + } + } +} + +//============================================================================== +/** + * Draws the caret out to the screen. + * + * @param inRenderer Renderer to draw the text out to + */ +void CTextEdit::DrawCaret(CRenderer *inRenderer) +{ + if (m_Caret.show && m_Caret.visible) { + CRct theTextRect = GetTextRect(); + CPt theCaretPosition(theTextRect.position.x, 0); + + float theSizeX; + float theSizeY; + + const auto textSize = inRenderer->GetTextSize(GetDisplayString(). + Extract(0, m_Caret.position).toQString()); + theSizeX = textSize.width(); + theSizeY = textSize.height(); + + theCaretPosition.x = ::dtol(theSizeX) + theTextRect.position.x; + + // Adjust the caret postion so that it draws just before the current character, instead of + // on the current character + theCaretPosition.x--; + + theCaretPosition += m_ScrollAmount; + + inRenderer->PushPen(::CColor(m_Caret.color)); + theCaretPosition.y = theCaretPosition.y; + inRenderer->MoveTo(theCaretPosition); + inRenderer->LineTo(theCaretPosition.x, GetSize().y - 1); + inRenderer->PopPen(); + } +} + +//============================================================================= +/** + * Inserts the specified character into the control + */ +bool CTextEdit::InsertChar(unsigned int inChar) +{ + bool theReturnValue = false; + Q3DStudio::CString theTempString = m_DisplayString; + + if (!m_Caret.show) + SelectAllText(); + + long theLeftSelection = GetSelectionLeft(); + long theRightSelection = GetSelectionRight(); + long thePosition = m_Caret.position; + + if (theLeftSelection != theRightSelection) { + Q3DStudio::CString theDisplayString = m_DisplayString; + + theTempString = ""; + theTempString = theDisplayString.Extract(0, theLeftSelection); + theTempString += theDisplayString.Extract(theRightSelection, + theDisplayString.Length() - theRightSelection); + thePosition = theLeftSelection; + } + + if (CanAcceptChar(theTempString, inChar, thePosition) + && theTempString.Length() < GetMaxLength()) { + DeleteCurrentSelection(false); + + Q3DStudio::CString theChar = static_cast(inChar); + theTempString.Insert(m_Caret.position, theChar); + SetData(theTempString); + + // Advance the caret past the character that we just typed + MoveCaretTo(m_Caret.position + 1); + + ResetBlinkingCursor(); + theReturnValue = true; + } + + return theReturnValue; +} + +//============================================================================= +/** + * Handles character input from the keyboard. + * + * @param inChar Character that was pressed + * @return true if the character was handled, false if this control does not + * care about the character that was pressed + */ +bool CTextEdit::OnChar(const QString &inChar, Qt::KeyboardModifiers inFlags) +{ + // 0x7F is a character generated by the delete key + if (inChar.size() == 0 || inChar[0].unicode() == 0x7F) + return false; + + bool theReturnValue = false; + + if (!m_CommandHandler->OnChar(QKeySequence::fromString(inChar)[0], 1, inFlags)) { + // Do not process the character if control is down, this will allow + // app's hotkey to process application hotkeys. + if (!(inFlags & Qt::ControlModifier)) { + // Always return true whenever it captures focus and tries insert character. + // Though InsertChar fails, this is still getting the focus and have processed the + // event, return true so that no other controls will handle it + // Refer to Bug 897 + InsertChar(inChar[0].unicode()); + theReturnValue = true; + } + } else + theReturnValue = true; + + return theReturnValue; +} + +//============================================================================= +/** + * Virtual function that determines if a key recieved via OnChar can actually be + * processed. Sub-classes should override this implementation and provide their + * own function for determining what characters they accept. + * + * @param inCheckString the string that is to be checked (in case a lenght requirement is exceeded) + * @param inChar the character that was pressed + * @param inPosition character index where we are attempting to insert inChar into inCheckString + * @return true if this control can accept the character into the string, otherwise false + */ +bool CTextEdit::CanAcceptChar(const Q3DStudio::CString &inCheckString, unsigned int inChar, + unsigned int inPosition) +{ + Q_UNUSED(inCheckString); + Q_UNUSED(inPosition); + + bool theAcceptFlag = false; + + if (inChar >= 32 && inChar <= 255 && !m_IsReadOnly) + theAcceptFlag = true; + + return theAcceptFlag; +} + +//============================================================================= +/** + * Handles key presses. OnKeyDown events pass in non-printable characters + * such as the arrow keys or Enter. Some of these keys will be handled by this + * control. + * + * @param inChar the character that was pressed + * @return true if the character was consumed by this control, otherwise false + */ +bool CTextEdit::OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inFlags) +{ + bool theHandledFlag = false; + if (!m_IsReadOnly) { + if (!m_CommandHandler->OnChar(inChar, 1, inFlags)) { + theHandledFlag = HandleSpecialChar(inChar, inFlags); + + // Enter key commits the last change + if (inChar == Qt::Key_Enter) + FireCommitEvent(); + + ResetBlinkingCursor(); + Invalidate(); + } else { + theHandledFlag = true; + } + } + return theHandledFlag; +} + +//============================================================================== +/** + * Handles any non-character keys that were pressed and need to be handled. + * + * @param inChar The key that was pressed + * @param inFlags Indicates which modifier keys were down when event occurred + * @return true if this function handled the character, otherwise false + */ +bool CTextEdit::HandleSpecialChar(unsigned int inChar, Qt::KeyboardModifiers inFlags) +{ + bool theHandledFlag = true; + bool isShiftDown = inFlags & CHotKeys::MODIFIER_SHIFT ? true : false; + // bool isControlDown = inFlags & CHotKeys::MODIFIER_CONTROL ? true : false; + + switch (inChar) { + case Qt::Key_Left: + // If we are cancelling selection, then we need to change how the caret moves + if (HasSelectedText() && !isShiftDown) + MoveCaretTo(GetSelectionLeft(), isShiftDown); + // Otherwise, just move the caret left by one character + else + MoveCaretTo(m_Caret.position - 1, isShiftDown); + break; + + case Qt::Key_Right: + // If we are cancelling selection, then we need to change how the caret moves + if (HasSelectedText() && !isShiftDown) + MoveCaretTo(GetSelectionRight(), isShiftDown); + // Otherwise, just move the caret right by one character + else + MoveCaretTo(m_Caret.position + 1, isShiftDown); + break; + + case Qt::Key_Home: + MoveCaretTo(0, isShiftDown); + break; + + case Qt::Key_End: + MoveCaretTo((long)m_CharWidths.size(), isShiftDown); + break; + + case Qt::Key_Backspace: + if (HasSelectedText()) + DeleteCurrentSelection(); + else + DeleteCharacter(false); + break; + + case Qt::Key_Delete: { + if (HasSelectedText()) + DeleteCurrentSelection(); + else + DeleteCharacter(true); + } break; + case Qt::Key_Return: + EnterText(true); + break; + + default: + theHandledFlag = false; + break; + } + + return theHandledFlag; +} + +//============================================================================== +/** + * Handles mouse down events. Places the caret in the appropriate place based + * upon the mouse position. + * + * @param inLocation Location of the mouse at the time the click occurred + * @param inFlags Flags indicating various key states (not used) + * @return true (this control always handles mouse down events) + */ +void CTextEdit::OnMouseOver(CPt inLocation, Qt::KeyboardModifiers inFlags) +{ + CControl::OnMouseOver(inLocation, inFlags); + + if (!m_IsReadOnly) + setCursorIfNotSet(CMouseCursor::CURSOR_IBEAM); +} + +//============================================================================== +/** + * Handles mouse down events. Places the caret in the appropriate place based + * upon the mouse position. + * + * @param inLocation Location of the mouse at the time the click occurred + * @param inFlags Flags indicating various key states (not used) + * @return true (this control always handles mouse down events) + */ +bool CTextEdit::OnMouseDown(CPt inLocation, Qt::KeyboardModifiers inFlags) +{ + bool theReturnValue = CControl::OnMouseDown(inLocation, inFlags); + + if (!m_IsReadOnly) { + // If the text is scrolled, we'll need to adjust for that + inLocation -= m_ScrollAmount; + + m_StartDragPt = inLocation; + m_MouseIsDown = true; + + ClearSelection(); + + MoveCaretTo(ConvertPositionToIndex(inLocation), false, false); + + // Turn the caret on + m_Caret.show = true; + m_Caret.visible = true; + + ResetBlinkingCursor(); + + m_TimerConnection = + ITickTock::GetInstance().AddTimer(1000, true, std::bind(&CTextEdit::OnTimer, this), + "CTextEdit::OnMouseDown::" + GetDisplayString()); + + theReturnValue = true; + } + + return theReturnValue; +} + +//============================================================================== +/** + * Called when the mouse button is released. Disables any dragging that may + * have been occurring. + * + * @param inPoint location of the mouse when the event occurred + * @param inFlags various flags about other key states + */ +void CTextEdit::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + m_MouseIsDown = false; + m_StartDragPt = CPt(0, 0); + CControl::OnMouseUp(inPoint, inFlags); +} + +//============================================================================== +/** + * Handles mouse movement. If the left mouse button is down and the user is + * dragging the mouse over the text in the edit box, the appropriate text is + * selected. + * + * @param inPoint location of the mouse. + * @param inFlags not used + */ +void CTextEdit::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inFlags); + + if (!m_IsReadOnly) + setCursorIfNotSet(CMouseCursor::CURSOR_IBEAM); + + if (m_MouseIsDown && !m_IsReadOnly) { + // The point was scrolled in OnMouseDown, so we have to scroll it when we drag as well so + // that it lines up + inPoint -= m_ScrollAmount; + + // Figure out what character index inPoint.x translates to + long theCharOffset = ConvertPositionToIndex(inPoint); + + MoveCaretTo(theCharOffset, true); + } +} + +//============================================================================== +/** + * Converts a given pixel position on the screen into an index into the display + * string. + * + * @param inPosition the point to be converted + * @return the character index derived from inPostion + */ +long CTextEdit::ConvertPositionToIndex(CPt inPosition) +{ + CRct theTextRect = GetTextRect(); + long theIndex = 0; + long theTotalPixels = theTextRect.position.x; + + // NOTE: We technically only care about the x-position of the point, so just ignore + // inPosition.y if it is not within the text area. This may need to be changed in + // the future (perhaps if vertical alignment is implemented). + CPt thePositionNoY = CPt(inPosition.x, theTextRect.position.y); + + // If the point is within the text area + if (theTextRect.IsInRect(thePositionNoY)) { + // Figure out which characters it falls in between + for (TCharLengths::iterator thePos = m_CharWidths.begin(); thePos != m_CharWidths.end(); + ++thePos) { + theTotalPixels += ::dtol(*thePos); + if (inPosition.x < theTotalPixels) + break; + theIndex++; + } + } + // If the point is to the left of the text, default the index to the beginning of the text + else if (theTextRect.position.x > thePositionNoY.x) { + theIndex = 0; + } + // Otherwise, the point must be to the right of the text, so move the index to the end of the + // text + else { + theIndex = (long)m_CharWidths.size(); + } + + return theIndex; +} + +//============================================================================== +/** + * Converts a given character index into a pixel postion on the screen. This + * function is the inverse of ConvertPositionToIndex. + * @param inIndex the character index to be converted + * @return the x-position (in pixels) of character at inIndex + */ +long CTextEdit::ConvertIndexToPosition(long inIndex) +{ + long theXPixelOffset = GetTextRect().position.x; + long theCurrentIndex = 0; + + for (TCharLengths::iterator thePos = m_CharWidths.begin(); thePos != m_CharWidths.end(); + ++thePos) { + theCurrentIndex++; + + if (theCurrentIndex > inIndex) { + break; + } + + theXPixelOffset += ::dtol(*thePos); + } + + return theXPixelOffset; +} + +//============================================================================== +/** + * Handles double clicks on the control. Highlights all the text in the control. + * + * @param inPoint Not used + * @param inFlags Not used + * @return true (this control always handles double clicks) + */ +bool CTextEdit::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theHandledFlag = false; + Q_UNUSED(inPoint); + Q_UNUSED(inFlags); + if (!m_IsReadOnly) { + SelectAllText(); + + if (GetParent()) + GetParent()->GrabFocus(this); + + theHandledFlag = true; + } + + return theHandledFlag; +} + +//============================================================================== +/** + * Selects all the text in the display string + */ +void CTextEdit::SelectAllText() +{ + if (!m_IsReadOnly) { + MoveCaretTo(GetDisplayString().Length()); + SetSelection(0, GetDisplayString().Length()); + // Turn the caret on + m_Caret.show = true; + } +} + +//============================================================================== +/** + * Marks the string contained by this control as dirty so that it is reevaluated + * the next time that the control draws itself. Also clears out any selection + * that may have been present, resetting the selection to the caret position. + * + * @param inDirty true to mark this control as dirty, which causes the string to be redrawn + * false to mark the control as not needing to reevaluate its text during next draw cycle + */ +void CTextEdit::SetDirty(bool inDirty) +{ + m_IsStringDirty = inDirty; + if (m_IsStringDirty) { + m_NeedsCommit = true; + ClearSelection(); + Invalidate(); + } +} + +//============================================================================== +/** + * @return true if the string is currently dirty and needs to be reevalutated. + */ +bool CTextEdit::IsDirty() const +{ + return m_IsStringDirty; +} + +//============================================================================== +/** + * Determines the width in pixels of each letter in the display string. + * + * @param inRenderer The current renderer being drawn to (since only the renderer + * knows how to calculate the pixel width of the text in the current font). + * @return The total width in pixels of the entire display string + */ +float CTextEdit::CalculateCharWidths(CRenderer *inRenderer) +{ + Q3DStudio::CString theString = GetDisplayString(); + + m_CharWidths.clear(); + m_TotalCharWidth = 0; + + for (long theCharIndex = 0; theCharIndex < theString.Length(); ++theCharIndex) { + const auto textSize = inRenderer->GetTextSize(theString.Extract(theCharIndex, 1).toQString()); + m_CharWidths.push_back(textSize.width()); + m_TotalCharWidth += textSize.width(); + } + + return m_TotalCharWidth; +} + +//============================================================================== +/** + * Sets the number of pixels worth of buffer space to place at the left and + * right ends of the edit box. + */ +void CTextEdit::SetBufferLength(long inLength) +{ + m_BufferLength = inLength; +} + +//============================================================================== +/** + * Sets the maximum length of text + */ +void CTextEdit::SetMaxLength(long inLength) +{ + m_MaxLength = inLength; +} + +//============================================================================== +/** + * Allows you to turn the background fill on and off. + * @param inFillBackground true to fill the background color when drawing, false to turn it off + */ +void CTextEdit::SetFillBackground(bool inFillBackground) +{ + if (m_FillBackground == inFillBackground) + return; + m_FillBackground = inFillBackground; + Invalidate(); +} + +//============================================================================== +/** + * Called when this control loses focus. Hides the caret, clears the current + * selection and invalidates the control so that it will get redrawn. + */ +void CTextEdit::OnLoseFocus() +{ + m_TimerConnection = std::shared_ptr(); + m_Caret.show = false; + m_ScrollAmount.x = 0; + ClearSelection(); + m_IsStringDirty = true; + FireCommitEvent(); + resetCursor(); + CControl::OnLoseFocus(); +} + +//============================================================================== +/** + * Called when this control gains focus. Shows the caret, clears the current + * selection and invalidates the control so that it will get redrawn. + */ +void CTextEdit::OnGainFocus() +{ + if (!m_MouseIsDown) { + m_Caret.position = 0; + m_Caret.show = !m_IsReadOnly; + if (!m_IsReadOnly) + SelectAllText(); + + if (m_Caret.show) { + ResetBlinkingCursor(); + m_TimerConnection = ITickTock::GetInstance().AddTimer( + 1000, true, std::bind(&CTextEdit::OnTimer, this), + "CTextEdit::OnGainFocus::" + GetDisplayString()); + } + } + + Invalidate(); +} + +//============================================================================== +/** + * Override to set whether or not this can gain focus. + */ +bool CTextEdit::CanGainFocus() +{ + return !m_IsReadOnly; +} + +//============================================================================== +/** + * If this control has focus, it's display may have a different string then the + * actual underlying string. This enables us to revert back to the original + * string if the user presses the Escape while editing the text. So this function + * should be used to obtain the proper string to work with. If this control has + * focus, the internally stored string is returned, otherwise the CTextEdit asks + * its child class to reevaluate the string. + * + * @return the string being displayed in the edit box + */ +Q3DStudio::CString CTextEdit::GetDisplayString() +{ + // If this control does not have focus, we should just reevaluate the string + if (GetParent()) { + if (!GetParent()->HasFocus(this)) + SetDisplayString(GetString(), false); + } + + // If the edit box is read only, then add the pre and postfix, + // otherwise, just the display string is drawn while editing + Q3DStudio::CString theCompleteString = m_DisplayString; + if (m_IsReadOnly) { + theCompleteString = m_Prefix + m_DisplayString + m_Postfix; + } + + return theCompleteString; +} + +//============================================================================== +/** + * Invokied in a Draw call. Derived class can override to do their own background fill + */ +void CTextEdit::DoFillBackground(CRenderer *inRenderer) +{ + if ((m_FillBackground && m_UseBGColorReadOnly) || !m_IsReadOnly) { + // Fill the interior of the edit box + ::CColor theFillColor = m_BackgroundColorNoFocus; + // If this control has focus + if (GetParent()) { + // Lighten the fill color + if (GetParent()->HasFocus(this)) + theFillColor = m_BackgroundColorFocus; + } + inRenderer->FillSolidRect(QRect(0, 0, GetSize().x, GetSize().y), theFillColor); + } +} + +//============================================================================== +/** + * Selects the specified text within the edit box. If inFirstIndex == inLastIndex + * no text is selected. If the indices specified do not fall within the size of + * the actual text, no selection occurs. + * + * @param inFirstIndex Index of the first letter to be selected + * @param inLastIndex Index of the last letter to be selected + */ +void CTextEdit::SetSelection(long inFirstIndex, long inLastIndex) +{ + if (inFirstIndex < 0 || inLastIndex > GetDisplayString().Length()) { + ClearSelection(); + } else { + if (m_SelectionStart != inFirstIndex || m_SelectionEnd != inLastIndex) + Invalidate(); + + m_SelectionStart = inFirstIndex; + m_SelectionEnd = inLastIndex; + } + + m_Caret.position = m_SelectionEnd; +} + +//============================================================================== +/** + * Sets this CTextEdit as either read-only or read/write. When a CTextEdit + * control is set to read-only, users cannot input data via the keyboard, + * and the text cannot be selected. + * + * @param inReadOnly true to specify static, non-editable, non-selectable text + */ +void CTextEdit::SetReadOnly(bool inReadOnly) +{ + if (inReadOnly != m_IsReadOnly) + Invalidate(); + + m_IsReadOnly = inReadOnly; +} + +//============================================================================== +/** + * @return true if this control should not allow the string to be edited + */ +bool CTextEdit::IsReadOnly() +{ + return m_IsReadOnly; +} + +//============================================================================== +/** + * Sets the color of the text dispalyed by this control. + * @param inColor Color of the text to be displayed + */ +void CTextEdit::SetTextColor(::CColor inColor) +{ + if (m_TextColor == inColor) + return; + + m_TextColor = inColor; + m_Caret.color = inColor; + Invalidate(); +} + +//============================================================================== +/** + * @return The current text color + */ +::CColor CTextEdit::GetTextColor() +{ + return m_TextColor; +} + +//============================================================================== +/** + * Sets the flag that says whether or not to use the m_BackgroundColorFocus + * and m_BackgroundColorNoFocus user colors to draw the background color + * of the text box. + */ +void CTextEdit::SetUseBGColorReadOnly(bool inUseBGColorReadOnly) +{ + m_UseBGColorReadOnly = inUseBGColorReadOnly; +} + +//============================================================================== +/** + * Sets the color of the background of this control when it does not have focus. + * Note that this color only has an effect when SetFillBackground has been + * called with true. + * @param inColor Color of the background when the control does not have focus + * @return The previous background color + */ +::CColor CTextEdit::SetBGColorNoFocus(::CColor inColor) +{ + ::CColor theOldColor = m_BackgroundColorNoFocus; + m_BackgroundColorNoFocus = inColor; + return theOldColor; +} + +//============================================================================== +/** + * Sets the color of the background of this control when it has focus. + * Note that this color only has an effect when SetFillBackground has been + * called with true. + * @param inColor Color of the background when the control has focus + * @return The previous background color + */ +::CColor CTextEdit::SetBGColorFocus(::CColor inColor) +{ + ::CColor theOldColor = m_BackgroundColorFocus; + m_BackgroundColorFocus = inColor; + return theOldColor; +} + +void CTextEdit::AddCommitListener(CCommitDataListener *inListener) +{ + m_CommitListeners.AddListener(inListener); +} + +void CTextEdit::RemoveCommitListener(CCommitDataListener *inListener) +{ + m_CommitListeners.RemoveListener(inListener); +} + +//============================================================================== +/** + * Fires commit events on Listeners. Only fires a commit event if it has not + * been fired previously. + */ +void CTextEdit::FireCommitEvent() +{ + // If we are not currently processing a command to fire commit events to listeners + if (m_NeedsCommit) { + // Fire the event and undirty the text + m_CommitListeners.FireEvent(&CCommitDataListener::OnSetData, this); + m_NeedsCommit = false; + } +} + +void CTextEdit::AddChangeListener(IChangeDataListener *inListener) +{ + m_ChangeListeners.AddListener(inListener); +} + +void CTextEdit::RemoveChangeListener(IChangeDataListener *inListener) +{ + m_ChangeListeners.RemoveListener(inListener); +} + +//============================================================================== +/** + * Fires change events on Listeners. + */ +void CTextEdit::FireChangeEvent(const Q3DStudio::CString &inOldString, + const Q3DStudio::CString &inNewString) +{ + m_ChangeListeners.FireEvent(&IChangeDataListener::OnChangeData, inOldString, inNewString); +} + +void CTextEdit::AddEnterListener(ITextEditEnterListener *inListener) +{ + m_EnterListeners.AddListener(inListener); +} + +void CTextEdit::RemoveEnterListener(ITextEditEnterListener *inListener) +{ + m_EnterListeners.RemoveListener(inListener); +} + +//============================================================================== +/** + * Fires enter events on listeners. + */ +void CTextEdit::FireEnterEvent() +{ + m_EnterListeners.FireEvent(&ITextEditEnterListener::OnEnter, this); +} + +//============================================================================== +/** + * Delete any text that is currently selected. + * If there is no text selected this will do nothing. + */ +void CTextEdit::DeleteCurrentSelection(bool inFireEvent /*=true*/) +{ + if (HasSelectedText()) { + Q3DStudio::CString theTempString = m_DisplayString; + theTempString.Delete(GetSelectionLeft(), GetSelectionRight() - GetSelectionLeft()); + + m_Caret.position = GetSelectionLeft(); + + ClearSelection(); + + // @see DeleteCharacter( ) + SetData(theTempString, inFireEvent); + SetDisplayString(theTempString, inFireEvent); + SetDirty(true); + } +} + +//============================================================================== +/** + * Delete a character to the left or right of the cursor. + * This will delete a single character on the specified side of the cursor. + * @param inOnRight true if the character to be deleted is on the right of the cursor. + */ +void CTextEdit::DeleteCharacter(bool inOnRight) +{ + if (!inOnRight) { + if (m_Caret.position == 0) + return; + else + m_Caret.position--; + } + + Q3DStudio::CString theTempString = m_DisplayString; + theTempString.Delete(m_Caret.position, 1); + // Since SetData is overloaded by other types of text edit controls, + // it has to be called first so that subclasses have a chance to set their internal values + // before calling SetDisplayString, which fires a DataChanged event. + // @see DeleteCurrentSelection( ). EnterText got it right. + SetData(theTempString); + SetDisplayString(theTempString); + SetDirty(true); +} + +//============================================================================== +/** + * Move the caret to the specified position in the string. + * If inSelect then this will select the text from the selection start position + * to the new position. If there is no current selection start then this will + * select from the old position to the new position. If select is false and there + * is selected text the selection will be cleared. + * @param inPosition the position to move to in the string. + * @param inSelect true if the selection should be changed when moving. + * @param inScroll true if moving the caret should allow the text to scroll within the box + */ +void CTextEdit::MoveCaretTo(long inPosition, bool inSelect /*=false*/, bool inScroll /*=true*/) +{ + if (inPosition < 0) + inPosition = 0; + if (inPosition > GetDisplayString().Length()) + inPosition = GetDisplayString().Length(); + + // Only perform the operation if the caret is actually going to move, or the selection is going + // to change + if ((static_cast(inPosition) != m_Caret.position) + || (HasSelectedText() && !inSelect)) { + if (inSelect) { + if (!HasSelectedText()) + m_SelectionStart = m_Caret.position; + m_SelectionEnd = inPosition; + } else + ClearSelection(); + + m_Caret.position = inPosition; + + // Scroll if necessary + if (inScroll) { + long theCaretPixelPos = ConvertIndexToPosition(m_Caret.position); + if (theCaretPixelPos + m_ScrollAmount.x <= 0) + Scroll(m_ScrollAmount.x - (theCaretPixelPos + m_ScrollAmount.x) + m_BufferLength); + else if (theCaretPixelPos + m_ScrollAmount.x > GetSize().x) + Scroll(-(theCaretPixelPos - GetSize().x + m_BufferLength)); + } + + Invalidate(); + } +} + +//============================================================================== +/** + * Effectively scrolls the text in this edit box. + * Enables you to set the number of pixels to offset the text and caret by when + * they are drawn to the screen. If inPixel = 0, no scrolling takes place. If + * inPixel < 0, text is scrolled to the left. If inPixel > 0, text is scrolled + * to the right. + * @param inPixel specifies the horizontal scroll in pixels + */ +void CTextEdit::Scroll(long inPixel) +{ + m_ScrollAmount.x = inPixel; + Invalidate(); +} + +//============================================================================== +/** + * Pushes the display string back down to the control and optionally highlights + * the entire string. Called when the user clicks the enter button in an edit + * box. + * @param inHighlight true to highlight the string + */ +void CTextEdit::EnterText(bool inHighlight) +{ + SetData(m_DisplayString); + SetDisplayString(GetString()); + + if (inHighlight) + SetSelection(0, m_DisplayString.Length()); + + Invalidate(); + + FireEnterEvent(); +} + +//============================================================================== +/** + * Check to see if there is any text selected. + * @return true if there is any text selected. + */ +bool CTextEdit::HasSelectedText() +{ + return m_SelectionStart != m_SelectionEnd; +} + +//============================================================================== +/** + * Get the index of the leftmost selected character. + * @return the index, invalid if no text is selected. + */ +long CTextEdit::GetSelectionLeft() +{ + return m_SelectionStart < m_SelectionEnd ? m_SelectionStart : m_SelectionEnd; +} + +//============================================================================== +/** + * Get the index of the rightmost selected character. + * @return the index, invalid if no text is selected. + */ +long CTextEdit::GetSelectionRight() +{ + return m_SelectionStart > m_SelectionEnd ? m_SelectionStart : m_SelectionEnd; +} + +//============================================================================== +/** + * Clear any text from being selected, this will not delete the text, only deselect it. + */ +void CTextEdit::ClearSelection() +{ + m_SelectionStart = 0; + m_SelectionEnd = 0; + + Invalidate(); +} + +//============================================================================== +/** + * Re-get the display string. + */ +void CTextEdit::ReloadData() +{ + SetDisplayString(GetString()); +} + +//============================================================================== +/** + * Supply a prefix to be displayed when the string is not being edited (e.g. "#"). + */ +void CTextEdit::SetPrefix(const Q3DStudio::CString &inPrefix) +{ + m_Prefix = inPrefix; +} + +//============================================================================== +/** + * Supply a postfix to be displayed when the string is not being edited (e.g. " inches"). + */ +void CTextEdit::SetPostfix(const Q3DStudio::CString &inPostfix) +{ + m_Postfix = inPostfix; +} + +//============================================================================== +/** + * Handles the hotkey commands + */ + +void CTextEdit::RegisterCommands() +{ + m_CommandHandler->RegisterKeyEvent(new CDynHotKeyConsumer(this, &CTextEdit::CopyText), + Qt::ControlModifier, Qt::Key_C); + m_CommandHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CTextEdit::PasteText), Qt::ControlModifier, + Qt::Key_V); + m_CommandHandler->RegisterKeyEvent(new CDynHotKeyConsumer(this, &CTextEdit::CutText), + Qt::ControlModifier, Qt::Key_X); + m_CommandHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CTextEdit::SelectAllText), + Qt::ControlModifier, Qt::Key_A); +} + +//============================================================================== +/** + * Copies selected text to clipboard. If nothing is selected, everything is copied. + * @return true if text was copied + */ +bool CTextEdit::CopyText() +{ + if (!m_IsReadOnly) { + if (HasSelectedText()) + CStudioClipboard::CopyTextToClipboard(m_DisplayString.Extract( + GetSelectionLeft(), GetSelectionRight() - GetSelectionLeft()).toQString()); + else + CStudioClipboard::CopyTextToClipboard(m_DisplayString.toQString()); + } + return !m_IsReadOnly; +} + +//============================================================================== +/** + * Pastes text to clipboard + */ + +bool CTextEdit::PasteText() +{ + Q3DStudio::CString theText = Q3DStudio::CString + ::fromQString(CStudioClipboard::GetTextFromClipboard()); + bool theHandledFlag = !m_IsReadOnly && CanPaste() && !theText.IsEmpty(); + + theHandledFlag &= theText.Length() <= GetMaxLength(); + if (HasSelectedText()) { + theHandledFlag &= + m_DisplayString.Length() - (GetSelectionRight() - GetSelectionLeft()) + theText.Length() + <= GetMaxLength(); + } else { + theHandledFlag &= m_DisplayString.Length() + theText.Length() <= GetMaxLength(); + } + + if (theHandledFlag) { + if (!m_Caret.show) { + SetData(theText); + } else { + Q3DStudio::CString theNewString(m_DisplayString); + + if (HasSelectedText()) { + theNewString.Delete(GetSelectionLeft(), GetSelectionRight() - GetSelectionLeft()); + m_Caret.position = Q3DStudio::MIN(GetSelectionLeft(), GetSelectionRight()); + } + theNewString.Insert(m_Caret.position, theText); + + SetData(theNewString); + m_Caret.position += theText.Length(); + } + SetDirty(true); + } + return theHandledFlag; +} + +//============================================================================== +/** + * Cuts text to clipboard + */ + +bool CTextEdit::CutText() +{ + bool theReturn = false; + + if (CopyText()) { + DeleteCurrentSelection(); + theReturn = true; + } + + return theReturn; +} + +//============================================================================== +/** + * Reloads the display string with the given string + * @param inString The string to be set + */ +void CTextEdit::SetDisplayString(const Q3DStudio::CString &inString, bool inFireEvent /*= true*/) +{ + if (m_DisplayString != inString) { + Q3DStudio::CString theOldString = m_DisplayString; + m_DisplayString = inString; + + if (inFireEvent) + FireChangeEvent(theOldString, m_DisplayString); + + m_IsStringDirty = true; + } +} + +//============================================================================== +/** + * The buffer length is the number of pixels between where the control starts + * and where the text begins drawing (in the case of left alignment). In the + * case of right alignment it's the number of pixels on the right side of the + * control where the text ends before the actual edge of the control. Provided + * for sub classes. + */ +long CTextEdit::GetBufferLength() +{ + return m_BufferLength; +} + +//============================================================================== +/** + * The maximum allowed length of text + */ +long CTextEdit::GetMaxLength() +{ + return m_MaxLength; +} + +//============================================================================== +/** + * Displays the Copy/Cut/Paste context menu on right mouse down + */ +void CTextEdit::DisplayContextMenu(CPt inPt) +{ + CTextEditContextMenu theMenu(this); + DoPopup(&theMenu, inPt); +} + +//============================================================================== +/** + * Handles the Right mouse down event. Displays a cut/copy/paste context menu. + * @param inPoint location of the mouse at time of the event (context menu's upper left corner will + * be here) + * @param inFlags state of the modifier keys at the time of the event + * @return true - this control always consumes the event + */ +bool CTextEdit::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + // Give children the chance to handle the event, otherwise display the context menu + if (!CControl::OnMouseRDown(inPoint, inFlags)) { + if (!IsReadOnly()) { + DisplayContextMenu(CPt(inPoint.x, GetSize().y)); + return true; + } + } + return false; +} + +//============================================================================== +/** + * Periodic callback to make the caret blink. + */ +void CTextEdit::OnTimer() +{ + m_Caret.visible = !m_Caret.visible; + Invalidate(); +} + +//============================================================================== +/** + * Cancels the current timer and adds a new timer so that the cursor continues + * to blink. If the cursor is not currently visible, it is made visible. + */ +void CTextEdit::ResetBlinkingCursor() +{ + // Cancel the current timer + m_TimerConnection = std::shared_ptr(); + + // If the cursor is not visible, make it visible + if (!m_Caret.visible) { + m_Caret.visible = true; + Invalidate(); + } + + // Add the timer so that the cursor will blink back off after BLINKSPEED amount of time + m_TimerConnection = + ITickTock::GetInstance().AddTimer(BLINKSPEED, true, std::bind(&CTextEdit::OnTimer, this), + "CTextEdit::ResetBlinkingCursor::" + m_DisplayString); +} + +//============================================================================== +/** + * Set to true to indicate text should be drawn bold. + * @param inBold true to set text to bold + */ +void CTextEdit::SetBoldText(bool inBold) +{ + m_BoldText = inBold; +} diff --git a/src/Authoring/Studio/Controls/TextEdit.h b/src/Authoring/Studio/Controls/TextEdit.h new file mode 100644 index 00000000..b34dd75b --- /dev/null +++ b/src/Authoring/Studio/Controls/TextEdit.h @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** 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_TEXT_EDIT_H +#define INCLUDED_TEXT_EDIT_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +#include "Control.h" +#include "HotKeys.h" +#include "StudioPreferences.h" +#include "ITickTock.h" +#include "Multicaster.h" + +//============================================================================== +// Forwards +//============================================================================== + +class CRenderer; + +//============================================================================== +/** + * @class CTextEdit Base class for textual edit fields in Studio (timeline, inspector). + */ + +// Functors +GENERIC_FUNCTOR_1(CCommitDataListener, OnSetData, CControl *); +GENERIC_FUNCTOR_1(ITextEditEnterListener, OnEnter, CControl *); +GENERIC_FUNCTOR_2(IChangeDataListener, OnChangeData, const Q3DStudio::CString &, + const Q3DStudio::CString &); + +class CTextEdit : public CControl +{ + struct SCaret + { + unsigned long position; ///< index of the character that the cursor is currently in front of + ///(zero is first character) + ::CColor color; ///< color of the cursor + bool show; ///< must be true in order for the cursor to show up (outside of blink state) + bool visible; ///< blinking state of the cursor (true if currently visible) + }; + + typedef std::vector TCharLengths; + +public: + enum EAlignment { LEFT = 0, CENTER, RIGHT }; + + CTextEdit(); + virtual ~CTextEdit(); + + DEFINE_OBJECT_COUNTER(CTextEdit) + + virtual Q3DStudio::CString + GetString() = 0; ///< Returns the string to be displayed in the edit box + + void Draw(CRenderer *inRenderer) override; + void OnMouseOver(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDown(CPt inLocation, 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; + bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnChar(const QString &inChar, Qt::KeyboardModifiers inModifiers) override; + bool OnKeyDown(unsigned int inChar, Qt::KeyboardModifiers inModifiers) override; + void OnGainFocus() override; + void OnLoseFocus() override; + bool CanGainFocus() override; + virtual bool CanAcceptChar(const Q3DStudio::CString &inCheckString, unsigned int inChar, + unsigned int inPosition); + void SetAlignment(EAlignment inAlignment); + void SetBufferLength(long inLength); + void SetMaxLength(long inLength); + void SetFillBackground(bool inFillBackground); + void SelectAllText(); + void DisplayContextMenu(CPt inPt); + virtual bool CanPaste() = 0; + + virtual void SetData(const Q3DStudio::CString &inData, bool inFireEvent = true) = 0; + virtual void ReloadData(); + virtual void SetPrefix(const Q3DStudio::CString &inPrefix); + virtual void SetPostfix(const Q3DStudio::CString &inPostfix); + + void SetReadOnly(bool inReadOnly); + bool IsReadOnly(); + void SetTextColor(::CColor inColor); + ::CColor GetTextColor(); + void SetUseBGColorReadOnly(bool inUseBGColorReadOnly); + ::CColor SetBGColorNoFocus(::CColor inColor); + ::CColor SetBGColorFocus(::CColor inColor); + void SetBoldText(bool inBold); + + void AddCommitListener(CCommitDataListener *inListener); + void RemoveCommitListener(CCommitDataListener *inListener); + void FireCommitEvent(); + + void AddChangeListener(IChangeDataListener *inListener); + void RemoveChangeListener(IChangeDataListener *inListener); + void FireChangeEvent(const Q3DStudio::CString &inOldString, + const Q3DStudio::CString &inNewString); + + void AddEnterListener(ITextEditEnterListener *inListener); + void RemoveEnterListener(ITextEditEnterListener *inListener); + void FireEnterEvent(); + + bool HasSelectedText(); + long GetSelectionLeft(); + long GetSelectionRight(); + void ClearSelection(); + virtual void SetSelection(long inFirstIndex, long inLastIndex); + + void MoveCaretTo(long inPosition, bool inSelect = false, bool inScroll = true); + void Scroll(long inPixel); + virtual void EnterText(bool inHighlight); + + virtual void RefreshDisplayFromData() = 0; + + bool CopyText(); + bool PasteText(); + bool CutText(); + bool IsDirty() const; + + virtual void OnTimer(); + + // Public so that derived objects can query the value on change events + Q3DStudio::CString GetDisplayString(); + +protected: + virtual void DoFillBackground(CRenderer *inRenderer); + +protected: + bool m_IsStringDirty; + bool m_NeedsCommit; + TCharLengths m_CharWidths; + EAlignment m_Alignment; + float m_TotalCharWidth; + SCaret m_Caret; + long m_BufferLength; + long m_MaxLength; + bool m_IsReadOnly; + bool m_MouseIsDown; + CPt m_StartDragPt; + CHotKeys *m_CommandHandler; + bool m_FillBackground; + ::CColor m_TextColor; + bool m_UseBGColorReadOnly; ///< Flag indicating that we should use the background colors in read + ///only boxes as well as read/write + ::CColor m_BackgroundColorNoFocus; + ::CColor m_BackgroundColorFocus; + Q3DStudio::CString m_DisplayString; + Q3DStudio::CString m_Prefix; + Q3DStudio::CString m_Postfix; + bool m_BoldText; + + virtual void DeleteCurrentSelection(bool inFireEvent = true); + virtual void DeleteCharacter(bool inIsOnRight = false); + void RegisterCommands(); + virtual void SetDirty(bool inDirty); + float CalculateCharWidths(CRenderer *inRenderer); + virtual bool HandleSpecialChar(unsigned int inChar, Qt::KeyboardModifiers inFlags); + void DrawText(CRenderer *inRenderer); + void DrawCaret(CRenderer *inRenderer); + CRct GetTextRect(); + long ConvertIndexToPosition(long inIndex); + long ConvertPositionToIndex(CPt inPosition); + void SetDisplayString(const Q3DStudio::CString &inString, bool inFireEvent = true); + long GetBufferLength(); + long GetMaxLength(); + void ResetBlinkingCursor(); + bool InsertChar(unsigned int inChar); + +private: + CMulticaster m_CommitListeners; + CMulticaster m_ChangeListeners; + CMulticaster m_EnterListeners; + long m_SelectionStart; + long m_SelectionEnd; + CPt m_ScrollAmount; ///< Pixel offset to scroll the text and caret by + std::shared_ptr m_TimerConnection; +}; + +#endif // INCLUDED_TEXT_EDIT_H diff --git a/src/Authoring/Studio/Controls/TextEditContextMenu.cpp b/src/Authoring/Studio/Controls/TextEditContextMenu.cpp new file mode 100644 index 00000000..12d6ede9 --- /dev/null +++ b/src/Authoring/Studio/Controls/TextEditContextMenu.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" +#include "Strings.h" + +//============================================================================== +// Includes +//============================================================================== +#include "TextEditContextMenu.h" +#include "TextEdit.h" +#include "StudioClipboard.h" + +//============================================================================== +/** + * Constructor + */ + +CTextEditContextMenu::CTextEditContextMenu(CTextEdit *inEditControl, QWidget *parent) : QMenu(parent) +{ + m_TextEditControl = inEditControl; + + m_cutAction = new QAction(tr("Cut"), this); + connect(m_cutAction, &QAction::triggered, this, &CTextEditContextMenu::CutText); + addAction(m_cutAction); + + m_copyAction = new QAction(tr("Copy"), this); + connect(m_copyAction, &QAction::triggered, this, &CTextEditContextMenu::CopyText); + addAction(m_copyAction); + + m_pasteAction = new QAction(tr("Paste"), this); + connect(m_pasteAction, &QAction::triggered, this, &CTextEditContextMenu::PasteText); + addAction(m_pasteAction); +} + +//============================================================================== +/** + * Destructor + */ + +CTextEditContextMenu::~CTextEditContextMenu() +{ +} + +//============================================================================== +/** + * returns true if 'cut' can be applied to the control + */ +bool CTextEditContextMenu::CanCutText() +{ + return true; +} + +//============================================================================== +/** + * Returns true if you can copy the text in the control + */ +bool CTextEditContextMenu::CanCopyText() +{ + return true; +} + +//============================================================================== +/** + * Returns true if you may paste text from the clipboard into the control + */ +bool CTextEditContextMenu::CanPasteText() +{ + return CStudioClipboard::CanPasteText(); +} + +//============================================================================== +/** + * Calls the controls cuttext function + */ +void CTextEditContextMenu::CutText() +{ + m_TextEditControl->CutText(); +} + +//============================================================================== +/** + * Calls the controls copy text function + */ +void CTextEditContextMenu::CopyText() +{ + m_TextEditControl->CopyText(); +} + +//============================================================================== +/** + * Calls the controls paste text function + */ +void CTextEditContextMenu::PasteText() +{ + m_TextEditControl->PasteText(); +} + +void CTextEditContextMenu::showEvent(QShowEvent *event) +{ + m_cutAction->setEnabled(CanCutText()); + m_copyAction->setEnabled(CanCopyText()); + m_pasteAction->setEnabled(CanPasteText()); + + QMenu::showEvent(event); +} diff --git a/src/Authoring/Studio/Controls/TextEditContextMenu.h b/src/Authoring/Studio/Controls/TextEditContextMenu.h new file mode 100644 index 00000000..981253be --- /dev/null +++ b/src/Authoring/Studio/Controls/TextEditContextMenu.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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== + +#ifndef INCLUDED_TEXTEDITCONTEXTMENU_H +#define INCLUDED_TEXTEDITCONTEXTMENU_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include + +//============================================================================== +// Forwards +//============================================================================== +class CTextEdit; + +//============================================================================== +/** + * @class CTextEditContextMenu + */ + +class CTextEditContextMenu : public QMenu +{ + Q_OBJECT +public: + CTextEditContextMenu(CTextEdit *inEditControl, QWidget *parent = nullptr); + ~CTextEditContextMenu(); + +protected Q_SLOTS: + void CutText(); + void CopyText(); + void PasteText(); + +protected: + void showEvent(QShowEvent *event) override; + + bool CanCutText(); + bool CanPasteText(); + bool CanCopyText(); + + CTextEdit *m_TextEditControl; + QAction *m_cutAction; + QAction *m_copyAction; + QAction *m_pasteAction; +}; + +#endif // INCLUDED_TEXTEDITCONTEXTMENU_H diff --git a/src/Authoring/Studio/Controls/TextEditInPlace.cpp b/src/Authoring/Studio/Controls/TextEditInPlace.cpp new file mode 100644 index 00000000..145df140 --- /dev/null +++ b/src/Authoring/Studio/Controls/TextEditInPlace.cpp @@ -0,0 +1,324 @@ +/**************************************************************************** +** +** 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" + +// using namespace Q3DStudio; <-- Do not do this here because it will conflict with CList and make +// the template generator go blah + +//============================================================================== +// Includes +//============================================================================== +#include "TextEditInPlace.h" +#include "Renderer.h" + +//============================================================================== +// Static class constants +//============================================================================== +const long CTextEditInPlace::s_RightBuffer = + 6; ///< Extra space allotted on the right side of the text + +//============================================================================== +/** + * Constructor + */ +CTextEditInPlace::CTextEditInPlace() + : CStringEdit() + , m_IsInEditMode(false) + , m_IsEditable(true) + , m_AllowSingleClickEdit(true) +{ + SetAlignment(LEFT); + SetReadOnly(true); + SetFillBackground(false); +} + +//============================================================================== +/** + * Destructor + */ +CTextEditInPlace::~CTextEditInPlace() +{ +} + +//============================================================================== +/** + * Handles the mouse double-click event. Enters the text into edit mode so that + * the user can change its value. + * @param inPoint location of the mouse + * @param inFlags modifier flags for the mouse + * @return true if this message should not be passed to any other children, otherwise false + */ +bool CTextEditInPlace::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theMessageWasHandled = false; + if (m_IsEditable) { + SetEditMode(true); + SetSelection(0, GetString().Length()); + m_Caret.show = true; + theMessageWasHandled = true; + } else + theMessageWasHandled = CStringEdit::OnMouseDoubleClick(inPoint, inFlags); + return theMessageWasHandled; +} + +void CTextEditInPlace::OnMouseClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CStringEdit::OnMouseClick(inPoint, inFlags); + if (IsInFocus() && !(inFlags & CHotKeys::MOUSE_RBUTTON) && !m_IsInEditMode && m_IsEditable + && m_AllowSingleClickEdit) { + SetEditMode(true); + SelectAllText(); + } +} + +//============================================================================== +/** + * Called when this control loses focus. Turns off edit mode and redraws the + * control. + */ +void CTextEditInPlace::OnLoseFocus() +{ + SetEditMode(false); + CStringEdit::OnLoseFocus(); + Invalidate(); +} + +//============================================================================== +/** + * Handles most of the drawing, with some help from the parent class. + * @param inRenderer Renderer to draw to + */ +void CTextEditInPlace::Draw(CRenderer *inRenderer) +{ + CRct theRect(GetSize()); // CRct( CPt( ::dtol( CalculateCharWidths( inRenderer ) + s_RightBuffer + // ), GetSize( ).y ) ); + + inRenderer->PushClippingRect(theRect); + CStringEdit::Draw(inRenderer); + inRenderer->PopClippingRect(); +} + +//============================================================================== +/** + * Enables or disables this control from being able to enter "Edit Mode" when + * SetEditMode() is called. + * @param inIsEditable true if you want the control to be editable when double-clicked, otherwise + * false + */ +void CTextEditInPlace::SetEditable(bool inIsEditable) +{ + m_IsEditable = inIsEditable; + + if (!m_IsEditable && m_IsInEditMode) + SetEditMode(false); +} + +//============================================================================== +/** + * Starts or stops "Edit Mode". While in Edit Mode, the user can change the + * text, move the caret, and highlight the text. An edit box is also drawn + * around the text. + * @param inEditMode true to turn on Edit Mode, false to turn off Edit Mode + */ +void CTextEditInPlace::SetEditMode(bool inEditMode) +{ + if (m_IsEditable && (inEditMode != m_IsInEditMode)) { + m_IsInEditMode = inEditMode; + SetReadOnly(!m_IsInEditMode); + + // If we are in edit mode + if (m_IsInEditMode) { + m_PreviousValue = GetString(); + } + // If we are not in edit mode + else { + // Restore the text color and commit the changes + FireCommitEvent(); + } + } +} + +//============================================================================== +/** + * Overriden from the parent to cause this control to lose focus when the Enter + * button is pressed on the keyboard. + * @param inHighlight true to highlight all of the text, false to just change the string + */ +void CTextEditInPlace::EnterText(bool inHighlight) +{ + CStringEdit::EnterText(inHighlight); + OnLoseFocus(); +} + +//============================================================================== +/** + * Overriden to also invalidate/validate the parent. + * @param inInvalidate true to invalidate this control and the parent control + */ +void CTextEditInPlace::Invalidate(bool inInvalidate) +{ + if (inInvalidate && GetParent()) + GetParent()->Invalidate(inInvalidate); + + CStringEdit::Invalidate(inInvalidate); +} + +//============================================================================== +/** + * Override to avoid selecting all the text unless in edit mode. + */ +void CTextEditInPlace::OnGainFocus() +{ + if (m_IsInEditMode && m_IsEditable) + CStringEdit::OnGainFocus(); +} + +bool CTextEditInPlace::CanGainFocus() +{ + return true; +} + +//============================================================================== +/** + * Returns the edit mode. + * @return true if the control is currently in edit mode meaning that the user + * can enter text into it, otherwise false + */ +bool CTextEditInPlace::GetEditMode() +{ + return m_IsInEditMode; +} + +long CTextEditInPlace::GetRightBuffer() +{ + return s_RightBuffer; +} + +//============================================================================== +/** + * Handles the Right mouse button down command. Only shows the cut/copy/paste + * context menu if the control is currently being edited. You can't change a + * string that's not currently being edited + * @param inPoint The mouse position at the time of the event + * @param inFlags The state of the modifier keys at the time of the event + * @return true if this function handled the character, otherwise false + */ + +bool CTextEditInPlace::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theMessageWasHandled = false; + + // The base class shows the cut/copy/paste menu, so only do it if we are in edit mode + if (m_IsInEditMode) + theMessageWasHandled = CStringEdit::OnMouseRDown(inPoint, inFlags); + + return theMessageWasHandled; +} + +//============================================================================= +/** + * Handles character input from the keyboard. + * + * @param inChar Character that was pressed + * @return true if the character was handled, false if this control does not + * care about the character that was pressed + */ +bool CTextEditInPlace::OnChar(const QString &inChar, Qt::KeyboardModifiers inModifiers) +{ + bool theMessageWasHandled = false; + if (GetEditMode()) + theMessageWasHandled = CStringEdit::OnChar(inChar, inModifiers); + return theMessageWasHandled; +} + +//============================================================================== +/** + * By default, clicking on a CTextEditInPlace control that already has focus, will + * cause the control to enter edit mode (if SetEditable( true ) has been called). + * This is referred to as single-click editing. This function allows you to + * enable or disable this functionality. Even if single-click editing is + * disabled, the user can still edit the text control by double-clicking on it. + * @param inAllow true to enable single-click editing, false to prevent it + */ +void CTextEditInPlace::SetSingleClickEdit(bool inAllow) +{ + m_AllowSingleClickEdit = inAllow; +} + +//============================================================================== +/** + * Reverts the displayed text to the previous text. + */ +void CTextEditInPlace::RevertText() +{ + if (m_IsInEditMode) + CStringEdit::RevertText(); +} + +//============================================================================== +/** + * Override the base class's version + */ +void CTextEditInPlace::DoFillBackground(CRenderer *inRenderer) +{ + if (m_FillBackground && !m_IsInEditMode) + inRenderer->FillSolidRect(QRect(0, 0, GetSize().x, GetSize().y), m_BackgroundColorNoFocus); +} + +//============================================================================== +/** + * Handles any non-character keys that were pressed and need to be handled. + * + * @param inChar The key that was pressed + * @param inFlags Indicates which modifier keys were down when event occurred + * @return true if this function handled the character, otherwise false + */ +bool CTextEditInPlace::HandleSpecialChar(unsigned int inChar, Qt::KeyboardModifiers inFlags) +{ + bool theMessageWasHandled = false; + + switch (inChar) { + // We're overwriting the Escape hotkey sequence from StringEdit because we need to lose focus + // in TextEditInPlace, StringEdit basically does the same thing for Escape and Ctrl + Z. + case Qt::Key_Escape: + RevertText(); + OnLoseFocus(); + theMessageWasHandled = true; + break; + + default: + theMessageWasHandled = CStringEdit::HandleSpecialChar(inChar, inFlags); + } + + return theMessageWasHandled; +} diff --git a/src/Authoring/Studio/Controls/TextEditInPlace.h b/src/Authoring/Studio/Controls/TextEditInPlace.h new file mode 100644 index 00000000..7239e6fc --- /dev/null +++ b/src/Authoring/Studio/Controls/TextEditInPlace.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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_TEXT_EDIT_IN_PLACE_H +#define INCLUDED_TEXT_EDIT_IN_PLACE_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "StringEdit.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; + +//============================================================================== +/** + * @class CTextEditInPlace + */ +class CTextEditInPlace : public CStringEdit +{ +public: + CTextEditInPlace(); + virtual ~CTextEditInPlace(); + + bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnLoseFocus() override; + void OnGainFocus() override; + bool CanGainFocus() override; + void Draw(CRenderer *inRenderer) override; + void SetEditable(bool inIsEditable); + void SetEditMode(bool inEditMode); + void EnterText(bool inHighlight) override; + void Invalidate(bool inInvalidate = true) override; + bool GetEditMode(); + static long GetRightBuffer(); + bool OnChar(const QString &inChar, Qt::KeyboardModifiers inModifiers) override; + bool HandleSpecialChar(unsigned int inChar, Qt::KeyboardModifiers inFlags) override; + virtual void SetSingleClickEdit(bool inAllow); + +protected: + void DoFillBackground(CRenderer *inRenderer) override; + +protected: + bool m_IsInEditMode; ///< If in edit mode, the user is currently editing the control + bool m_IsEditable; ///< Can only enter edit mode when the control is editable + bool m_AllowSingleClickEdit; ///< True if clicking on the control while it has focus should + ///cause it to enter edit mode. False to force a double-click for + ///entering edit mode. + + void RevertText() override; + +private: + static const long s_RightBuffer; +}; + +#endif // INCLUDED_TEXT_EDIT_IN_PLACE_H diff --git a/src/Authoring/Studio/Controls/TimeEdit.cpp b/src/Authoring/Studio/Controls/TimeEdit.cpp new file mode 100644 index 00000000..3859721f --- /dev/null +++ b/src/Authoring/Studio/Controls/TimeEdit.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** 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 "CoreUtils.h" +#include "TimeEdit.h" +#include "Renderer.h" +#include "IDoc.h" +#include "TimeEditDlg.h" + +long DELIMITER_SIZE = 2; +long MINUTES_SIZE = 28; +long SECONDS_SIZE = 20; +long MILLIS_SIZE = 28; + +CTimeEdit::CTimeEdit(IDoc *inDoc) + : m_Time(0) + , m_MinimumTime(0) + , m_MaximumTime(LONG_MAX) +{ + AddChild(&m_Minutes); + AddChild(&m_Seconds); + AddChild(&m_Millis); + m_Doc = inDoc; +} + +CTimeEdit::~CTimeEdit() +{ +} +long CTimeEdit::GetTime() +{ + return m_Time; +} + +//============================================================================= +/** + * OnMouseDown: Displays a time edit dialog, when the user clicks on the time edit box. + * @param inPoint stores the point clicked + * @param inFlags stores the control keys pressed + */ +bool CTimeEdit::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + Q_UNUSED(inPoint); + Q_UNUSED(inFlags); + + CTimeEditDlg theTimeEditDlg; + theTimeEditDlg.ShowDialog(m_Time, 0, m_Doc, PLAYHEAD); + return true; +} + +void CTimeEdit::SetSize(CPt inSize) +{ + CControl::SetSize(inSize); + + inSize.x -= DELIMITER_SIZE * 2; + + m_Minutes.SetPosition(CPt(0, 0)); + m_Minutes.SetAbsoluteSize(CPt(MINUTES_SIZE, inSize.y)); + m_Minutes.SetAlignment(CTextEdit::RIGHT); + m_Minutes.SetNumDecimalPlaces(0); + m_Minutes.AddCommitListener(this); + m_Minutes.SetMin(0); + + m_Seconds.SetPosition(CPt(MINUTES_SIZE + DELIMITER_SIZE, 0)); + m_Seconds.SetAbsoluteSize(CPt(SECONDS_SIZE, inSize.y)); + m_Seconds.SetAlignment(CTextEdit::LEFT); + m_Seconds.SetFixedPlaces(2); + m_Seconds.SetNumDecimalPlaces(0); + m_Seconds.AddCommitListener(this); + m_Seconds.SetMin(0); + + m_Millis.SetPosition(CPt(MINUTES_SIZE + SECONDS_SIZE + DELIMITER_SIZE * 2, 0)); + m_Millis.SetAbsoluteSize(CPt(MILLIS_SIZE, inSize.y)); + m_Millis.SetAlignment(CTextEdit::LEFT); + m_Millis.SetFixedPlaces(3); + m_Millis.SetNumDecimalPlaces(0); + m_Millis.AddCommitListener(this); + m_Millis.SetMin(0); +} + +//============================================================================= +/** + * Draw this time. + * @param inRenderer the renderer to draw to. + */ + +void CTimeEdit::Draw(CRenderer *inRenderer) +{ + // Fill in the background, otherwise we'll have junk left over from before + CRct theRect(GetSize()); + inRenderer->FillSolidRect(theRect, m_BackgroundColor); + const float yPos = GetSize().y - 3; + inRenderer->PushPen(CStudioPreferences::GetRulerTickColor()); + inRenderer->DrawText(static_cast(m_Seconds.GetPosition().x - DELIMITER_SIZE - 1), yPos, + ":"); + inRenderer->DrawText(static_cast(m_Millis.GetPosition().x - DELIMITER_SIZE - 1), yPos, + "."); +} + +//============================================================================= +/** + * Set the text background color for this component. + * @param inColor the background color for this. + */ +void CTimeEdit::SetBackgroundColor(const CColor &inColor) +{ + m_BackgroundColor = inColor; + + m_Minutes.SetBGColorNoFocus(inColor); + m_Seconds.SetBGColorNoFocus(inColor); + m_Millis.SetBGColorNoFocus(inColor); +} + +//============================================================================= +/** + * Lame, yes. Basically gets the estimated width of this control. + */ +long CTimeEdit::GetWidth() +{ + return MINUTES_SIZE + SECONDS_SIZE + MILLIS_SIZE + DELIMITER_SIZE * 2; +} + +//============================================================================= +/** + * Set the time displayed by this control. + * This will make sure the time is in the proper ranges then set it to the + * value. + * @param inTime the new time value for this control. + */ +void CTimeEdit::SetTime(long inTime) +{ + m_Time = inTime; + + m_Minutes.SetData((float)(m_Time / (1000 * 60))); + m_Seconds.SetData((float)((m_Time / 1000) % 60)); + m_Millis.SetData((float)(m_Time % 1000)); + Invalidate(); +} + +void CTimeEdit::OnSetData(CControl *inControl) +{ + Q_UNUSED(inControl); + + long theTime = ::dtol(m_Millis.GetData()) + ::dtol(m_Seconds.GetData() * 1000) + + ::dtol(m_Minutes.GetData() * 60 * 1000); + + m_TimeListeners.FireEvent(&CTimeEditChangeListener::OnTimeChanged, theTime); +} + +//============================================================================= +/** + * Add a listener to this control for when the time changes. + * @param inListener the listener to be added to this control. + */ +void CTimeEdit::AddTimeChangeListener(CTimeEditChangeListener *inListener) +{ + m_TimeListeners.AddListener(inListener); +} + +//============================================================================= +/** + * Remove a time change listener from this control. + * @param inListener the listener to be removed from this control. + */ +void CTimeEdit::RemoveTimeChangeListener(CTimeEditChangeListener *inListener) +{ + m_TimeListeners.RemoveListener(inListener); +} diff --git a/src/Authoring/Studio/Controls/TimeEdit.h b/src/Authoring/Studio/Controls/TimeEdit.h new file mode 100644 index 00000000..39c8cd3b --- /dev/null +++ b/src/Authoring/Studio/Controls/TimeEdit.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_TIME_EDIT_H +#define INCLUDED_TIME_EDIT_H 1 + +#pragma once + +#include "Control.h" +#include "GenericFunctor.h" +#include "Multicaster.h" +#include "FloatEdit.h" +#include "EditInPlace.h" +#include "StringEdit.h" + +#include "IDoc.h" + +GENERIC_FUNCTOR_1(CTimeEditChangeListener, OnTimeChanged, long); + +class CTimeEdit : public CControl, public CCommitDataListener +{ +public: + CTimeEdit(IDoc *inDoc); + virtual ~CTimeEdit(); + + void SetMinimumTime(long inMinimumTime); + void SetMaximumTime(long inMaximumTime); + void SetBackgroundColor(const CColor &inColor); + void SetTime(long inTime); + virtual void Draw(CRenderer *inRenderer); + long GetWidth(); + void AddTimeChangeListener(CTimeEditChangeListener *inListener); + void RemoveTimeChangeListener(CTimeEditChangeListener *inListener); + + virtual void SetSize(CPt inSize); + + virtual void OnSetData(CControl *inControl); + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags); + long GetTime(); + +protected: + long m_Time; + IDoc *m_Doc; + CEditInPlace m_Minutes; + CEditInPlace m_Seconds; + CEditInPlace m_Millis; + + CColor m_BackgroundColor; + + long m_MinimumTime; + long m_MaximumTime; + + CMulticaster m_TimeListeners; +}; +#endif // INCLUDED_TIME_EDIT_H diff --git a/src/Authoring/Studio/Controls/ToggleButton.cpp b/src/Authoring/Studio/Controls/ToggleButton.cpp new file mode 100644 index 00000000..3271a949 --- /dev/null +++ b/src/Authoring/Studio/Controls/ToggleButton.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** 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 "ToggleButton.h" + +IMPLEMENT_OBJECT_COUNTER(CToggleButton) + +//============================================================================= +/** + * Constructor + */ +CToggleButton::CToggleButton() + : m_IsToggleDown(false) +{ + ADDTO_OBJECT_COUNTER(CToggleButton) +} + +//============================================================================= +/** + * Destructor + */ +CToggleButton::~CToggleButton() +{ + REMOVEFROM_OBJECT_COUNTER(CToggleButton) +} + +//============================================================================= +/** + * Handles mouse click events (full mouse down and mouse up combo). Causes the + * button to change states. + * @param inListener toggle listener to be removed + */ +void CToggleButton::OnMouseClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CButtonControl::OnMouseClick(inPoint, inFlags); + Toggle(); +} + +//============================================================================= +/** + * Handles mouse down on the button. Allows a button down event to be fired + * by the base class, but then returns the button to the proper state, meaning + * that toggle buttons should not actually change states on mouse down messages + * even though that's what the base class does. + * @param inPoint location of the mouse when this event occurred + * @param inFlags state of modifier keys at the time that this event occurred + */ +bool CToggleButton::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theReturn = CButtonControl::OnMouseDown(inPoint, inFlags); + + if (m_IsToggleDown) + SetButtonState(EBUTTONSTATE_DOWN); + else + SetButtonState(EBUTTONSTATE_UP); + Invalidate(); + + return theReturn; +} + +//============================================================================= +/** + * Handles mouse up on the button. Fires a mouse up event, but not a toggle + * event, as this is handled by OnMouseClick. Button state is maintained for + * the toggle button instead of changing immediately like on the base class. + * @param inPoint location of the mouse when this event occurred + * @param inFlags state of modifier keys at the time that this event occurred + */ +void CToggleButton::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + CButtonControl::OnMouseUp(inPoint, inFlags); + + if (m_IsToggleDown) + SetButtonState(EBUTTONSTATE_DOWN); + else + SetButtonState(EBUTTONSTATE_UP); + + Invalidate(); +} + +//============================================================================= +/** + * Changes the state of the button. If the button is currently down, it will + * be changed to up and vice versa. An event is fired to notify interested + * listeners that the button was toggled. + */ +void CToggleButton::Toggle() +{ + m_IsToggleDown = !m_IsToggleDown; + if (m_IsToggleDown) + SetButtonState(EBUTTONSTATE_DOWN); + else + SetButtonState(EBUTTONSTATE_UP); + + SigToggle(this, GetButtonState()); + + Invalidate(); +} + +void CToggleButton::SetToggleState(bool inIsDown) +{ + if (inIsDown != m_IsToggleDown) { + m_IsToggleDown = inIsDown; + SetButtonState(inIsDown ? EBUTTONSTATE_DOWN : EBUTTONSTATE_UP); + } +} diff --git a/src/Authoring/Studio/Controls/ToggleButton.h b/src/Authoring/Studio/Controls/ToggleButton.h new file mode 100644 index 00000000..59feafb5 --- /dev/null +++ b/src/Authoring/Studio/Controls/ToggleButton.h @@ -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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_TOGGLE_BUTTON_H +#define INCLUDED_TOGGLE_BUTTON_H 1 +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "ButtonControl.h" + +//============================================================================== +// Functors +//============================================================================== + +//============================================================================= +/** + * Class for making toggle buttons. A toggle button changes state each time a + * full mouse click is received. When you click the mouse on a toggle button, + * it will enter the "down" state. When you click it again, the toggle button + * will enter the "up" state. This differs from a regular button, which only + * enters the "down" state while the mouse is being held down, then immediately + * returns to the "up" state when the mouse is released. + */ +class CToggleButton : public CButtonControl +{ +public: + CToggleButton(); + virtual ~CToggleButton(); + + DEFINE_OBJECT_COUNTER(CToggleButton) + + void OnMouseClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + virtual void Toggle(); + + virtual void SetToggleState(bool inIsDown); + bool GetToggleState() const { return m_IsToggleDown; } + + //============================================================================= + /** + * Functor for handling button toggle messages. The message will be fired to + * interested listeners when a full button click occurs on this button. If you + * want to be a listener for button toggle events, you must define an + * OnButtonToggle function with the following parameters. + * @param CToggleButton* pointer to the button that generated the event + * @param EButtonState the state of the button as a result of this event + */ + boost::signal2 SigToggle; + +protected: + // protected to make fools use SetToggleState instead. + void SetButtonState(EButtonState inState) override { CButtonControl::SetButtonState(inState); } + + bool m_IsToggleDown; +}; + +#endif // INCLUDED_TOGGLE_BUTTON_H diff --git a/src/Authoring/Studio/Controls/TreeControl.cpp b/src/Authoring/Studio/Controls/TreeControl.cpp new file mode 100644 index 00000000..892c2086 --- /dev/null +++ b/src/Authoring/Studio/Controls/TreeControl.cpp @@ -0,0 +1,749 @@ +/**************************************************************************** +** +** 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 "TreeControl.h" +#include "Renderer.h" +#include "HotKeys.h" +#include "MasterP.h" +#include "StudioPreferences.h" +#include "StudioErrorIDs.h" + +//============================================================================= +/** + * Constructor + */ +CTreeControl::CTreeControl() + : m_AllowMultipleSelection(false) + , m_Refresh(true) + , m_SortFlag(false) +{ + + m_BGColor = CStudioPreferences::GetBaseColor(); +} + +//============================================================================= +/** + * Destructor + */ +CTreeControl::~CTreeControl() +{ + // Just clear out our lists, deletion is handled by whoever created the items. + m_ItemList.clear(); + m_SelectedItemList.clear(); +} + +//============================================================================= +/** + * Sets the background color of this control. + * @param inColor new background color + */ +void CTreeControl::SetBackgroundColor(const CColor &inColor) +{ + m_BGColor = inColor; + Invalidate(); +} + +//============================================================================= +/** + * Draws the control. + */ +void CTreeControl::Draw(CRenderer *inRenderer) +{ + inRenderer->FillSolidRect(QRect(QPoint(0, 0), GetSize()), m_BGColor); +} + +//============================================================================= +/** + * Find the item that this item should be added after to maintian sort order. + */ +CTreeItem *CTreeControl::FindPrevSortSibling(CTreeItem *, CTreeItem *) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + UIC_THROW(E_FAIL); // this is ass +#endif + return NULL; +} + +//============================================================================= +/** + * Find the item that this item should be before after to maintian sort order. + */ +CTreeItem *CTreeControl::FindNextSortSibling(CTreeItem *inParent, CTreeItem *inChild) +{ + CTreeItem *theSortItem = nullptr; + + if (inParent) { + theSortItem = inParent->FindNextSortSibling(inChild); + } else { + // No items in the list - return nullptr (because we don't care) + if (m_ItemList.size()) { + CTreeItem::TItemList::iterator thePos = m_ItemList.begin(); + for (; thePos != m_ItemList.end(); ++thePos) { + // Item in the list + theSortItem = *thePos; + if (IsItemLess(inChild, theSortItem)) + break; + } + + // Last item in the list + if (thePos == m_ItemList.end()) + theSortItem = nullptr; + } + } + + return theSortItem; +} + +//============================================================================= +/** + * Adds a tree item to the tree control. The child is automatically added to + * the end of the list under the specified parent. Once you add a tree item, + * to this tree control. You must call the remove functions to take it out of + * the tree control, after which point, it is safe for you to delete it. + * @param inParent parent of the tree item or nullptr if the item is to be a root + * @param inChild the child item to be added + */ +void CTreeControl::AddItem(CTreeItem *inParent, CTreeItem *inChild) +{ + CTreeItem *theBeforeItem = nullptr; + + if (IsSorting()) + theBeforeItem = FindNextSortSibling(inParent, inChild); + + AddItemBefore(inParent, inChild, theBeforeItem); +} + +//============================================================================= +/** + * Same as AddItem( ), except that you can specify where to put the child in relation + * to its siblings. + * @param inParent parent of the new item, or nullptr if adding a root level item + * @param inChild new child to be added + * @param inBefore should be a child of inParent, in which case, inChild is added before it; + * can be nullptr to indicate that inChild needs to go at the end of the inParent's children. + */ +void CTreeControl::AddItemBefore(CTreeItem *inParent, CTreeItem *inChild, CTreeItem *inBefore) +{ + if (inParent) + inParent->AddItem(inChild, inBefore); + else + AddToRootItemList(inChild, inBefore); + + CTreeItem *theControlBefore = inBefore; + if (inParent && !inBefore) + theControlBefore = RecurseGetControlAfter(inParent); + + AddToHierarchy(inChild, theControlBefore, true); +} + +//============================================================================= +/** + * Same as AddItem( ), except that you can specify where to put the child in relation + * to its siblings. + * @param inParent parent of the new item, or nullptr if adding a root level item + * @param inChild new child to be added + * @param inAfter should be a child of inParent, in which case, inChild is added after it + */ +void CTreeControl::AddItemAfter(CTreeItem *inParent, CTreeItem *inChild, CTreeItem *inAfter) +{ + CTreeItem *theItemBefore = nullptr; + CTreeItem *theControlBefore = nullptr; + + theItemBefore = GetSiblingAfter(inAfter); + theControlBefore = RecurseGetControlAfter(inAfter); + + if (inParent) + inParent->AddItem(inChild, theItemBefore); + else + AddToRootItemList(inChild, theItemBefore); + + AddToHierarchy(inChild, theControlBefore, true); +} + +//============================================================================= +/** + * Simply detaches inItem from the tree. Provided so that subclasses can + * override this function to actually perform item deletion if necessary. + * @param inItem Item to be removed + */ +void CTreeControl::RemoveItem(CTreeItem *inItem) +{ + Detach(inItem); +} + +//============================================================================= +/** + * Removes all currently selected items. + * @param inItem Item to be removed + */ +void CTreeControl::RemoveSelectedItems() +{ + // Iterate through the selected items, removing each one + CTreeItem::TItemList::iterator thePos = m_SelectedItemList.begin(); + for (; thePos != m_SelectedItemList.end(); ++thePos) { + CTreeItem *theItem = *thePos; + RemoveItem(theItem); + } + m_SelectedItemList.clear(); +} + +//============================================================================= +/** + * Removes all currently selected items. + * @param inItem Item to be removed + */ +void CTreeControl::RemoveAllItems() +{ + // Iterate through the selected items, removing each one + CTreeItem::TItemList::iterator thePos = m_ItemList.begin(); + + while (thePos != m_ItemList.end()) { + CTreeItem *theItem = *thePos; + RemoveItem(theItem); + thePos = m_ItemList.begin(); + } + ASSERT(m_ItemList.empty() == true); +} + +//============================================================================= +/** + * Creates a break in the tree. The item being detached is disconnected from + * it's parent (or from the tree control itself if it has no parent). The + * releations between branches below inItem are maintained internally by + * each child item. However, inItem and all of it's children are removed + * from the control hierarchy (they won't be drawn). This is useful if you + * want to move sections of the tree around without deleting anything. + * @param inItem item to detach + */ +void CTreeControl::Detach(CTreeItem *inItem) +{ + inItem->Detach(); + + if (inItem->IsRootItem()) + RemoveFromRootItemList(inItem); + + RemoveFromHierarchy(inItem, true); +} + +//============================================================================= +/** + * Allows you to enable or disable multiple selection for this tree control. + * @param inAllow true to allow multiple selection, false to only allow single selection + */ +void CTreeControl::SetAllowMultipleSelection(bool inAllow) +{ + m_AllowMultipleSelection = inAllow; +} + +//============================================================================= +/** + * @return true if multiple selection is enabled, false if only single + * selection is enabled. + */ +bool CTreeControl::GetAllowMultipleSelection() +{ + return m_AllowMultipleSelection; +} + +//============================================================================= +/** + * @return the number of items at the root level of this tree control + */ +long CTreeControl::GetNumRootItems() +{ + return (long)m_ItemList.size(); +} + +//============================================================================= +/** + * Get the root item at the specified index + */ +CTreeItem *CTreeControl::GetRootItem(long inIndex) +{ + CTreeItem::TItemList::iterator thePos = m_ItemList.begin(); + std::advance(thePos, inIndex); + + if (thePos != m_ItemList.end()) + return (*thePos); + + return nullptr; +} + +//============================================================================= +/** + * Gets iterators for traversing the list of selected tree items. + * @param outListBegin returns an iterator to the beginning of the selected item list + * @param outListEnd returns an iterator to the end of the selected item list + */ +void CTreeControl::GetSelectionIterators(CTreeItem::TItemList::iterator &outListBegin, + CTreeItem::TItemList::iterator &outListEnd) +{ + outListBegin = m_SelectedItemList.begin(); + outListEnd = m_SelectedItemList.end(); +} + +//============================================================================= +/** + * @return number of selected items in this tree control + */ +long CTreeControl::GetNumSelectedItems() +{ + return (long)m_SelectedItemList.size(); +} + +//============================================================================= +/** + * @return the first selected item in the tree control + */ +CTreeItem *CTreeControl::GetFirstSelectedItem() +{ + CTreeItem::TItemList::iterator theBegin = m_SelectedItemList.begin(); + if (theBegin != m_SelectedItemList.end()) + return (*theBegin); + return nullptr; +} + +//============================================================================= +/** + * Selects the specified tree item and adds the item to the selection list. + * Multiple selection is handled via inKeyModifiers and setting of the multiple + * selection flag on this class. + * @param inItem item to be selected + * @param inKeyModifiers optionally indicates the state of shift, ctrl, etc. for multiple selection + */ +void CTreeControl::Select(CTreeItem *inItem, long inKeyModifiers /*=0*/) +{ + ASSERT(inItem != nullptr); + + bool theCtrlKeyIsDown = + (inKeyModifiers & CHotKeys::MODIFIER_CONTROL) == CHotKeys::MODIFIER_CONTROL; + bool theShiftKeyIsDown = + (inKeyModifiers & CHotKeys::MODIFIER_SHIFT) == CHotKeys::MODIFIER_SHIFT; + + // clears all existing selection if multiple selection is not allowed + // If multiple selection is not enabled or neither control nor shift is down + if (!m_AllowMultipleSelection || (!theCtrlKeyIsDown && !theShiftKeyIsDown)) { + CTreeItem::TItemList::iterator thePos = m_SelectedItemList.begin(); + // Iterate through all the selected items and deselect them + for (; thePos != m_SelectedItemList.end();) { + CTreeItem *theItem = *thePos; + if (theItem->IsSelected() && inItem != theItem) { + theItem->SetSelected(false); + thePos = m_SelectedItemList.erase(thePos); // remove unselected item from list + } else + ++thePos; + } + } + + // Don't bother selecting the item if it is already selected + if (!inItem->IsSelected()) { + inItem->SetSelected(true); + m_SelectedItemList.push_back(inItem); + + // Tell all TreeItemSelectionListeners that the item was selected + FireItemSelected(inItem); + } + + if (theShiftKeyIsDown) { + // TODO: advanced selection + } +} + +//============================================================================= +/** + * Deselects the specified item, if it is selected. + * @param inItem item to be deselected + */ +void CTreeControl::Deselect(CTreeItem *inItem) +{ + // Run through the list and look for the specified item + bool theItemWasFound = false; + CTreeItem::TItemList::iterator thePos = m_SelectedItemList.begin(); + CTreeItem::TItemList::iterator theEnd = m_SelectedItemList.end(); + for (; thePos != theEnd; ++thePos) { + CTreeItem *theItem = *thePos; + if (theItem == inItem) { + theItemWasFound = true; + break; + } + } + + // If the item was found, remove it from the selected item list + if (theItemWasFound) { + m_SelectedItemList.erase(thePos); + // Tell the item it is no longer selected + inItem->SetSelected(false); + } +} + +//============================================================================= +/** + * Deselects all currently selected items. + */ +void CTreeControl::DeselectAll() +{ + CTreeItem::TItemList::iterator thePos = m_SelectedItemList.begin(); + CTreeItem::TItemList::iterator theEnd = m_SelectedItemList.end(); + for (; thePos != theEnd; ++thePos) { + CTreeItem *theItem = *thePos; + theItem->SetSelected(false); + } + m_SelectedItemList.clear(); +} + +//============================================================================= +/** + * Expand all nodes to the specified item. + */ +void CTreeControl::ExpandTo(CTreeItem *inItem) +{ + // Turn off tree refreshing + bool theAllowRefresh = GetAllowRefresh(); + SetAllowRefresh(false); + + // Expand the specified item + inItem->Expand(); + + // Expand the parents + CTreeItem *theParent = inItem->GetParentItem(); + if (theParent) + ExpandTo(theParent); + + // Restore tree refreshing + SetAllowRefresh(theAllowRefresh); +} + +//============================================================================= +/** + * Expand all nodes from this item onwards. + */ +void CTreeControl::ExpandFrom(CTreeItem *inItem) +{ + // Turn off tree refreshing + bool theAllowRefresh = GetAllowRefresh(); + SetAllowRefresh(false); + + // Expand the item's immediate children + inItem->Expand(); + + CTreeItem::TItemList::iterator theBegin; + CTreeItem::TItemList::iterator theEnd; + + inItem->GetItemIterator(theBegin, theEnd); + + // Expand all children + std::for_each(theBegin, theEnd, std::bind1st(std::mem_fun(&CTreeControl::ExpandFrom), this)); + + // Restore refresh state + SetAllowRefresh(theAllowRefresh); +} + +//============================================================================= +/** + * Collapse all items in the tree. + */ +void CTreeControl::CollapseAll() +{ + // Not implemented + UIC_THROW(STUDIO_E_FAIL); +} + +//============================================================================= +/** + * Allows or disallows calls to RecalcLayout. This is useful if you are adding + * a bulk amount of items to the tree control at once. You can simply call + * this function with false, add your items, the call this function again with + * true. In this way, you don't incur a call to RecalcLayout for each item + * added, just one call at the end when all the items are added. + * @param inAllowRefresh true to allow RecalcLayout calls, false to prevent them + * from doing anything. + */ +void CTreeControl::SetAllowRefresh(bool inAllowRefresh) +{ + m_Refresh = inAllowRefresh; +} + +//============================================================================= +/** + * Tells you whether or not a call to RecalcLayout will actually result in + * resizing and repositioning the items in the tree. + * @return true if the tree control is currently allowing recalc layout calls + * to process, otherwise false. + */ +bool CTreeControl::GetAllowRefresh() +{ + return m_Refresh; +} + +//============================================================================= +/** + * Helper function for finding the tree item that is the next sibling after + * the specified item. If inItem has a parent, the parent's list is searched, + * otherwise, we just search the root item list. If there is no sibling, this + * function recurses on the parent (if there is one) all the way up the tree + * until we reach the top. If there is not a control after the specified one, + * this function returns nullptr. + * @param inItem Item whose sibling we are searching for + * @return the sibling that occurs after inItem in the tree hierarchy + */ +CTreeItem *CTreeControl::GetSiblingAfter(CTreeItem *inItem) +{ + UICPROFILE(GetSiblingAfter); + + ASSERT(inItem); + + CTreeItem *theSibling = nullptr; + CTreeItem *theParent = inItem->GetParentItem(); + + // Declare the iterators, then use them on either list + CTreeItem::TItemList::reverse_iterator thePos; + CTreeItem::TItemList::reverse_iterator theListEnd; + + // If we have a parent, get the iterators from the parent + if (theParent) { + theParent->GetReverseItemIterator(thePos, theListEnd); + } + // If we don't have a parent, we must be searching for a root-level item, so search the tree + // control's list + else { + thePos = m_ItemList.rbegin(); + theListEnd = m_ItemList.rend(); + } + + // Iterate through the list + bool theItemWasFound = false; + CTreeItem *thePreviousItem = nullptr; + for (; thePos != theListEnd; ++thePos) { + CTreeItem *theCurrentItem = *thePos; + + // If we found the item we are looking for, break out of the loop + if (theCurrentItem == inItem) { + theItemWasFound = true; + break; + } + + thePreviousItem = theCurrentItem; + } + + // If the item we were looking for was found, the sibling is probably contained in + // thePreviousItem + if (theItemWasFound) + theSibling = thePreviousItem; + + return theSibling; +} + +//============================================================================= +/** + * Helper function for fetching the control after inItem. If inItem has siblings, + * those are searched to determine if there is a sibling after inItem. If no + * sibling is found, this function recurses, this time searching for a sibling + * of inItem->GetParentItem( ); assuming that inItem has a parent. In this + * way, we determine the control that occurs after inItem in the Control + * hierarchy. + * @param inItem we are searching for the item after this one + * @return the item after inItem in the control hierarchy or nullptr if there is no item after inItem. + */ +CTreeItem *CTreeControl::RecurseGetControlAfter(CTreeItem *inItem) +{ + UICPROFILE(RecurseGetControlAfter); + + ASSERT(inItem); + + CTreeItem *theControlAfter = GetSiblingAfter(inItem); + CTreeItem *theParent = inItem->GetParentItem(); + + // If we still haven't found a sibling, and we have a valid parent, recursively search for a + // sibling of the parent + if (!theControlAfter && theParent) + theControlAfter = RecurseGetControlAfter(theParent); + + return theControlAfter; +} + +//============================================================================= +/** + * Protected function for adding items to the root level of this control. + * @param inItem new item to be added + * @param inInsertBefore item to insert inItem before in the list, or + * nullptr to insert the item at the end of the list + */ +void CTreeControl::AddToRootItemList(CTreeItem *inItem, CTreeItem *inInsertBefore) +{ + // If an item to insert before is specified + if (inInsertBefore) { + // Go through the list and insert inItem before inInsertBefore + CTreeItem::TItemList::iterator thePos = m_ItemList.begin(); + for (; thePos != m_ItemList.end(); ++thePos) { + CTreeItem *theCurrentItem = *thePos; + if (theCurrentItem == inInsertBefore) { + m_ItemList.insert(thePos, inItem); + break; + } + } + } + // If no item is specified for inserting before, add inItem to the end of the list + else { + m_ItemList.push_back(inItem); + } +} + +//============================================================================= +/** + * Protected function for removing items from the root level of this control. + * The item is not deleted and nothing is done to the children of the item. + * @param inItem item to be removed from the list + */ +void CTreeControl::RemoveFromRootItemList(CTreeItem *inItem) +{ + bool theItemWasFound = false; + CTreeItem::TItemList::iterator thePos = m_ItemList.begin(); + for (; thePos != m_ItemList.end(); ++thePos) { + CTreeItem *theItem = *thePos; + if (theItem == inItem) { + theItemWasFound = true; + break; + } + } + + if (theItemWasFound) { + m_ItemList.erase(thePos); + } +} + +//============================================================================= +/** + * Protected function for adding items to the root level of this control. No + * lists are updated, this is merely for updating the control hierarchy. + * @param inItem item to be added to the control hierarchy + * @param inBefore item to insert inItem before in the control hierarchy or nullptr + * to insert at the end of the control hierarchy. + * @param inIsRecursive true to recursively add all children of inItem to hierarchy + */ +void CTreeControl::AddToHierarchy(CTreeItem *inItem, CTreeItem *inBefore, bool inIsRecursive) +{ + AddChild(inItem, inBefore); + + if (inIsRecursive) { + bool theAllowRefresh = GetAllowRefresh(); + SetAllowRefresh(false); + + if (inItem->IsContainer()) { + CTreeItem::TItemList::iterator thePos; + CTreeItem::TItemList::iterator theEnd; + inItem->GetItemIterator(thePos, theEnd); + for (; thePos != theEnd; ++thePos) { + CTreeItem *theChild = *thePos; + AddToHierarchy(theChild, inBefore, inIsRecursive); + } + } + + SetAllowRefresh(theAllowRefresh); + } +} + +//============================================================================= +/** + * Protected function for removing an item from the control hierarchy. The + * item is not deleted, but it will no longer be drawn. + * @param inItem Item to remove + * @param inIsRecursive true to recursively call this function on all of the item's children + */ +void CTreeControl::RemoveFromHierarchy(CTreeItem *inItem, bool inIsRecursive) +{ + if (inIsRecursive) { + bool theAllowRefresh = GetAllowRefresh(); + SetAllowRefresh(false); + + if (inItem->IsContainer()) { + CTreeItem::TItemList::iterator thePos; + CTreeItem::TItemList::iterator theEnd; + inItem->GetItemIterator(thePos, theEnd); + for (; thePos != theEnd; ++thePos) { + CTreeItem *theChild = *thePos; + RemoveFromHierarchy(theChild, inIsRecursive); + } + } + + SetAllowRefresh(theAllowRefresh); + } + + Deselect(inItem); + RemoveChild(inItem); +} + +//============================================================================= +/** + * Private function for adding children to the Control hierarchy. Only this + * class should call this function. Everyone else needs to go through AddItem( ). + * @param inControl new control to be added + * @param inInsertBefore control to insert the new one before in the hierarchy + */ +void CTreeControl::AddChild(CControl *inControl, CControl *inInsertBefore) +{ + Q3DStudio::Control::SVerticalLazyFlow::AddChild(inControl, inInsertBefore); +} + +//============================================================================== +/** + * Add a CTreeItemSelectionListener to this control's list of + * CTreeItemSelectionListeners. + * + * @param inListener CTreeItemSelectionListener to add to m_SelectionListeners + */ +void CTreeControl::AddSelectionListener(CTreeItemSelectionListener *inListener) +{ + m_SelectionListeners.AddListener(inListener); +} + +//============================================================================== +/** + * Remove a CTreeItemSelectionListener from this control's list of + * CTreeItemSelectionListeners. + * + * @param inListener CTreeItemSelectionListener to remove from m_SelectionListeners + */ +void CTreeControl::RemoveSelectionListener(CTreeItemSelectionListener *inListener) +{ + m_SelectionListeners.RemoveListener(inListener); +} + +void CTreeControl::FireItemSelected(CTreeItem *inItem) +{ + OnTreeItemSelected(inItem); + m_SelectionListeners.FireEvent(&CTreeItemSelectionListener::OnTreeItemSelected, inItem); +} diff --git a/src/Authoring/Studio/Controls/TreeControl.h b/src/Authoring/Studio/Controls/TreeControl.h new file mode 100644 index 00000000..e9958322 --- /dev/null +++ b/src/Authoring/Studio/Controls/TreeControl.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** 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_TREE_CONTROL_H +#define INCLUDED_TREE_CONTROL_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include "LazyFlow.h" +#include "TreeItem.h" + +//============================================================================== +// Forwards +//============================================================================== +class CRenderer; +class CTest_TreeControl; + +//============================================================================== +// Functor +//============================================================================== +/// This means that any class that wants be informed when TreeItems are selected +/// needs to implement the CTreeItemSelectionListener interface, and the +/// void OnTreeItemSelected( CTreeItem* ) method +/// The CTreeItem is the item that was selected +GENERIC_FUNCTOR_1(CTreeItemSelectionListener, OnTreeItemSelected, CTreeItem *); + +//============================================================================= +/** + * Custom tree control class. You need to call one of the AddItem*( ) functions + * to add tree items to this control. Multiple selection can be enabled using + * the provided functions. The tree control maintains a list of all the root + * level items. It is also responsible for managing the separate "Control + * hierarchy." + */ +class CTreeControl : public Q3DStudio::Control::SVerticalLazyFlow +{ +public: + CTreeControl(); + virtual ~CTreeControl(); + void SetBackgroundColor(const ::CColor &inColor); + void Draw(CRenderer *inRenderer) override; + virtual void AddItem(CTreeItem *inParent, CTreeItem *inChild); + virtual void AddItemBefore(CTreeItem *inParent, CTreeItem *inChild, CTreeItem *inBefore); + virtual void AddItemAfter(CTreeItem *inParent, CTreeItem *inChild, CTreeItem *inAfter); + virtual void RemoveItem(CTreeItem *inItem); + virtual void RemoveSelectedItems(); + virtual void RemoveAllItems(); + virtual void Detach(CTreeItem *inItem); + void SetAllowMultipleSelection(bool inAllow); + bool GetAllowMultipleSelection(); + void GetSelectionIterators(CTreeItem::TItemList::iterator &outListBegin, + CTreeItem::TItemList::iterator &outListEnd); + long GetNumSelectedItems(); + CTreeItem *GetFirstSelectedItem(); + virtual void Select(CTreeItem *inItem, long inKeyModifiers = 0); + virtual void Deselect(CTreeItem *inItem); + virtual void DeselectAll(); + void SetAllowRefresh(bool inAllowRefresh); + bool GetAllowRefresh(); + long GetNumRootItems(); + CTreeItem *GetRootItem(long inIndex); + virtual void ExpandTo(CTreeItem *inItem); + virtual void ExpandFrom(CTreeItem *inItem); + virtual void CollapseAll(); + virtual void SetSorting(bool inSort) { m_SortFlag = inSort; } + virtual bool IsSorting() { return m_SortFlag; } + + virtual bool IsItemGreater(CTreeItem *, CTreeItem *) { return true; } + virtual bool IsItemLess(CTreeItem *, CTreeItem *) { return false; } + + // SelectionListener methods + void AddSelectionListener(CTreeItemSelectionListener *inListener); + void RemoveSelectionListener(CTreeItemSelectionListener *inListener); + void FireItemSelected(CTreeItem *inItem); + + // Override to hear select + virtual void OnTreeItemSelected(CTreeItem *) {} + virtual void OnItemExpanding(CTreeItem *) {} + virtual void OnItemExpanded(CTreeItem *) { NotifyParentNeedsLayout(); } + virtual void OnItemCollapsing(CTreeItem *) {} + virtual void OnItemCollapsed(CTreeItem *) { NotifyParentNeedsLayout(); } + +protected: + // Member Vars + ::CColor m_BGColor; ///< Specifies the background color of this control + bool m_AllowMultipleSelection; ///< If true, multiple selection is enabled for this control + CTreeItem::TItemList m_ItemList; ///< List of all root level tree items + CTreeItem::TItemList m_SelectedItemList; ///< List of all selected tree items, regardless of + ///whether or not they are root level + bool m_Refresh; + bool m_SortFlag; + + // Member Functions + CTreeItem *GetSiblingAfter(CTreeItem *inItem); + CTreeItem *RecurseGetControlAfter(CTreeItem *inItem); + CTreeItem *FindPrevSortSibling(CTreeItem *inParent, CTreeItem *inChild); + CTreeItem *FindNextSortSibling(CTreeItem *inParent, CTreeItem *inChild); + void AddToRootItemList(CTreeItem *inItem, CTreeItem *inInsertBefore); + void RemoveFromRootItemList(CTreeItem *inItem); + void AddToHierarchy(CTreeItem *inItem, CTreeItem *inBefore, bool inIsRecursive); + void RemoveFromHierarchy(CTreeItem *inItem, bool inIsRecursive); + +private: + /// Private because you can only add CTreeItems to this control with AddItem( ). + void AddChild(CControl *inControl, CControl *inInsertBefore = nullptr) override; + + CMulticaster + m_SelectionListeners; ///< List of listeners who want to know when a TreeItem is selected +}; +#endif // INCLUDED_TREE_CONTROL_H diff --git a/src/Authoring/Studio/Controls/TreeItem.cpp b/src/Authoring/Studio/Controls/TreeItem.cpp new file mode 100644 index 00000000..03a41530 --- /dev/null +++ b/src/Authoring/Studio/Controls/TreeItem.cpp @@ -0,0 +1,939 @@ +/**************************************************************************** +** +** 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 "TreeItem.h" +#include "TreeControl.h" +#include "Renderer.h" +#include "SIcon.h" +#include "ResourceCache.h" +#include "HotKeys.h" +#include "MasterP.h" +#include "StudioPreferences.h" + +IMPLEMENT_OBJECT_COUNTER(CTreeItem) + +//============================================================================= +/** + * Constructor + * @param inTreeControl the tree control that this item will belong to + */ +CTreeItem::CTreeItem(CTreeControl *inTreeControl) + : m_TreeControl(inTreeControl) + , m_Parent(NULL) + , m_Toggle(NULL) + , m_Name(NULL) + , m_Icon(NULL) + , m_ControlGap(2) + , m_IndentLevel(0) + , m_IndentSize(0) + , m_IsExpanded(false) + , m_IsSelected(false) + , m_ShowVisibleSelection(true) + , m_Color(CStudioPreferences::GetBaseColor()) + , m_TextColor(CStudioPreferences::GetNormalColor()) +{ + ADDTO_OBJECT_COUNTER(CTreeItem) + + // Set up some of our flow layout properties + SetFlowDirection(FLOW_HORIZONTAL); + SetAlignment(ALIGN_VERT_NEITHER, ALIGN_LEFT); + SetGapBetweenChildren(m_ControlGap); + SetMaximumSize(CPt(LONG_MAX, CStudioPreferences::GetDefaultTextEditSize())); + SetMinimumSize(CPt(0, CStudioPreferences::GetDefaultTextEditSize())); + + // Create the toggle + CreateToggle(); + + // Icon control + m_Icon = new CSIcon(); + + // Name control + m_Name = new CTextEditInPlace(); + m_Name->SetAlignment(CTextEditInPlace::LEFT); + m_Name->SetTextColor(m_TextColor); + m_Name->SetBGColorNoFocus(CStudioPreferences::GetSelectColor()); + m_Name->SetFillBackground(false); + m_Name->AllowAutoSize(true); + + // Name change listener + m_NameChangeListener = + new CSpecificCCommitDataListener(this, &CTreeItem::OnNameChanged); + m_Name->AddCommitListener(m_NameChangeListener); + + // Toggle listener + m_Toggle->SigToggle.connect(std::bind(&CTreeItem::OnToggleExpansion, this, + std::placeholders::_1, std::placeholders::_2)); + + // Add all the controls to the flow + AddChild(m_Toggle); + AddChild(m_Icon); + AddChild(m_Name); +} + +//============================================================================= +/** + * Destructor + */ +CTreeItem::~CTreeItem() +{ + m_Name->RemoveCommitListener(m_NameChangeListener); + delete m_NameChangeListener; + + // Clear out our list of subitems, but don't delete anything (whoever called new should do the + // delete) + m_ItemList.clear(); + delete m_Toggle; + delete m_Icon; + delete m_Name; + + REMOVEFROM_OBJECT_COUNTER(CTreeItem) +} + +//============================================================================= +/** + * Fills in the background color of this control. + * @param inRenderer renderer to draw to + */ +void CTreeItem::Draw(CRenderer *inRenderer) +{ + inRenderer->FillSolidRect(QRect({}, GetSize()), m_Color); +} + +//============================================================================= +/** + * Allows you to set the background color of this control. + * @param inColor new background color for this control + */ +void CTreeItem::SetBackgroundColor(const CColor &inColor) +{ + m_Color = inColor; + Invalidate(); +} + +void CTreeItem::SetTextColor(const CColor &inColor) +{ + m_Name->SetTextColor(inColor); + m_TextColor = inColor; + Invalidate(); +} + +void CTreeItem::SetTextBGFocusColor(const ::CColor &inColor) +{ + m_Name->SetBGColorNoFocus(inColor); + Invalidate(); +} +//============================================================================= +/** + * @return the current background color of this control + */ +CColor CTreeItem::GetBackgroundColor() +{ + return m_Color; +} + +//============================================================================= +/** + * Sets the parent of this tree item. The parent is the tree item that can + * be toggled to hide or show this item. You can set this value to nullptr to + * specify that this item is a root item, thus making it always be visible. + * @param inParent parent of this item + */ +void CTreeItem::SetParentItem(CTreeItem *inParent) +{ + m_Parent = inParent; +} + +//============================================================================= +/** + * Allows you to access the parent of this tree item. Note that this parent is + * not the same as parenting in the Control hierarchy. The parent is the tree + * item that can be toggled to hide or show this item. + * @return the parent of this tree item, or nullptr if this is a root level item. + */ +CTreeItem *CTreeItem::GetParentItem() +{ + return m_Parent; +} + +//============================================================================= +/** + * Allows you to change the icon associated with this tree item. + * @param inIcon name of the icon in normal state + * @param inSelectedIcon name of the icon to be displayed when this item is selected + */ +void CTreeItem::SetIcon(const QString &inIcon, const QString &inSelectedIcon) +{ + SetIcon(CResourceCache::GetInstance()->GetBitmap(inIcon), + CResourceCache::GetInstance()->GetBitmap(inSelectedIcon)); +} + +//============================================================================= +/** + * Allows you to change the icon associated with this tree item. + */ +void CTreeItem::SetIcon(const QPixmap &inNormalIcon, const QPixmap &inSelectedIcon) +{ + m_NormalIcon = inNormalIcon; + m_SelectedIcon = inSelectedIcon; + + m_Icon->SetImage(m_NormalIcon); +} + +//============================================================================= +/** + * Allows you to specifiy whether or not the name of this tree item can be edited. + * If set to true, the user can edit an item's name by double-clicking on it. + * @param inIsEditable true to specify that the user is allowed to edit this + * item, otherwise false to prevent double-click editing. + */ +void CTreeItem::SetIsNameEditable(bool inIsEditable) +{ + m_Name->SetEditable(inIsEditable); +} + +//============================================================================= +/** + * Sets the text displayed by this tree item. This does not trigger a name + * change event. + * @param inText text to be displayed + */ +void CTreeItem::SetText(const Q3DStudio::CString &inText) +{ + m_Name->SetData(inText); +} + +//============================================================================= +/** + * Gets the text displayed by this tree item. + * @return the text that is displayed. + */ +Q3DStudio::CString CTreeItem::GetText() +{ + return m_Name->GetString(); +} + +//============================================================================= +/** + * Called when the name of the tree item is changed. Notifies any interested + * listeners. This is only for when the name control is edited directly. If + * you call SetText directly or change the text by other means, no listeners + * are notified. + * @param inControl control that generated the name change message (not used) + */ +void CTreeItem::OnNameChanged(CControl *inControl) +{ + Q_UNUSED(inControl); + + // Maintain the color scheme based upon whether or not this item is selected + if (m_ShowVisibleSelection) { + if (m_IsSelected) { + m_Name->SetFillBackground(true); + m_Name->SetTextColor(CColor(255, 255, 255)); + } else { + m_Name->SetFillBackground(false); + m_Name->SetTextColor(m_TextColor); + } + } + + // TODO: notify listeners +} + +//============================================================================= +/** + * Allows you to specify the indent level of this tree item. Generally, this + * is called automatically when adding a child item. An item at level 0 is a + * root item, an item at level 1 is a child of a root item, and so on. The + * indent level is multiplied by a fixed amount to cause the control to appear + * indented. + * @param inAmount number indicating how many children deep this item is + * @param inIsRecursive set to true to recursively set the indent level of all + * children in addition to this item. Each child is set at one more indent + * level than its parent. + */ +void CTreeItem::SetIndent(long inAmount, bool inIsRecursive) +{ + m_IndentLevel = inAmount; + + SetLeftMargin((m_IndentLevel * m_IndentSize) + m_ControlGap); + + if (inIsRecursive) { + TItemList::iterator thePos = m_ItemList.begin(); + for (; thePos != m_ItemList.end(); ++thePos) { + CTreeItem *theChild = *thePos; + theChild->SetIndent(m_IndentLevel + 1, inIsRecursive); + } + } +} + +//============================================================================= +/** + * Handles clicking on this item and selects or deselects it appropriately. + * @param inPoint location of the mouse + * @param inFlags key modifier states at time of mouse event + */ +bool CTreeItem::OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + if (!CFlowLayout::OnMouseDown(inPoint, inFlags)) { + // If the name is being edited, but was not clicked on, force it to lose focus + if (m_Name->GetEditMode() && !m_Name->HitTest(inPoint)) + m_Name->OnLoseFocus(); + + // The item needs to see if the control key is down, because that might mean that it needs + // to deselect itself + bool theControlKeyIsDown = + (inFlags & CHotKeys::MODIFIER_CONTROL) == CHotKeys::MODIFIER_CONTROL; + + // If the control key is down and we are currently selected, deselect ourselves + if (theControlKeyIsDown && IsSelected()) + m_TreeControl->Deselect(this); + // Otherwise, go ahead and perform a normal select command + else + m_TreeControl->Select(this, inFlags); + } + + return true; +} + +//============================================================================= +/** + * If this item is a container, double-click will expand it or collapse it. + * @param inPoint location of mouse at time of event + * @param inFlags modifier flags at time of event + */ +bool CTreeItem::OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + // Let the children have the chance to handle the message + bool theMessageWasHandled = CFlowLayout::OnMouseDoubleClick(inPoint, inFlags); + + // If no one else handled it, we'll just go ahead and expand + if (!theMessageWasHandled) { + // If this item is a container, toggle whether or not it's expanded + if (IsContainer()) + ToggleExpansion(); + } + + return theMessageWasHandled; +} + +//============================================================================= +/** + * Handles right clicking on this item and selects or deselects it appropriately. + * @param inPoint location of the mouse + * @param inFlags key modifier states at time of mouse event + * @return true if the event was consumed, false if it should continue to propagate + */ +bool CTreeItem::OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) +{ + bool theMessageWasHandled = CFlowLayout::OnMouseRDown(inPoint, inFlags); + if (!theMessageWasHandled) { + // If the name is being edited, but was not clicked on, force it to lose focus + if (m_Name->GetEditMode() && !m_Name->HitTest(inPoint)) + m_Name->OnLoseFocus(); + + // If this item is not already selected + if (!IsSelected()) { + // Select this tree item + m_TreeControl->Select(this, inFlags); + } + } + + return theMessageWasHandled; +} + +//============================================================================= +/** + * @return true if this row is currently expanded (showing it's children). + */ +bool CTreeItem::IsExpanded() +{ + return m_IsExpanded; +} + +//============================================================================= +/** + * If the row is currently expanded, this call will collapse it, or vice-versa. + */ +void CTreeItem::ToggleExpansion() +{ + if (IsExpanded()) + Collapse(); + else + Expand(); +} + +//============================================================================= +/** + * Expands this item to reveal all of its children. + */ +void CTreeItem::Expand() +{ + UICPROFILE(Expand); + + if (!m_IsExpanded) { + m_TreeControl->OnItemExpanding(this); + + bool theAllowRefresh = m_TreeControl->GetAllowRefresh(); + m_TreeControl->SetAllowRefresh(false); + + TItemList::iterator thePos = m_ItemList.begin(); + for (; thePos != m_ItemList.end(); ++thePos) { + CTreeItem *theItem = *thePos; + theItem->ShowChildItems(); + } + + m_IsExpanded = true; + + m_TreeControl->SetAllowRefresh(theAllowRefresh); + + // Expand/collapse might come from somewhere other than the button itself (see + // CTreeItem::OnMouseDoubleClick), + // so make sure we toggle it just in case + m_Toggle->SetToggleState(true); + + m_TreeControl->OnItemExpanded(this); + } +} + +//============================================================================= +/** + * Collapses this row, hiding all of its children + */ +void CTreeItem::Collapse() +{ + if (m_IsExpanded) { + m_TreeControl->OnItemCollapsing(this); + + bool theAllowRefresh = m_TreeControl->GetAllowRefresh(); + m_TreeControl->SetAllowRefresh(false); + + TItemList::iterator thePos = m_ItemList.begin(); + for (; thePos != m_ItemList.end(); ++thePos) { + CTreeItem *theItem = *thePos; + theItem->HideChildItems(); + } + + m_IsExpanded = false; + + // Deselect all children if they are being hidden and see if any children were in fact + // selected + // If there were children that were selected, we need to add this item to the selection + // list, without + // interfering with the selection state of other items + if (DeselectChildren()) { + long theFlags = 0; + + // If multiple selection is enabled, we need to make sure that we don't disrupt any + // other selection, + // so we simulate a control click on this item (selects this item in addition to + // whatever is already + // selected). + if (m_TreeControl->GetAllowMultipleSelection()) + theFlags = CHotKeys::MODIFIER_CONTROL; + + m_TreeControl->Select(this, theFlags); + } + + m_TreeControl->SetAllowRefresh(theAllowRefresh); + + // Expand/collapse might come from somewhere other than the button itself (see + // CTreeItem::OnMouseDoubleClick), + // so make sure we toggle it just in case + m_Toggle->SetToggleState(false); + + m_TreeControl->OnItemCollapsed(this); + } +} + +//============================================================================= +/** + * Adds a tree item as a child of this one. + * @param inItem the new item to be added. + * @param inInsertBefore the item to insert the new one before, or nullptr to + * insert at the end of the list + */ +void CTreeItem::AddItem(CTreeItem *inItem, CTreeItem *inInsertBefore /*=nullptr*/) +{ + inItem->SetIndent(m_IndentLevel + 1, true); + + inItem->SetVisible(IsExpanded()); + + if (!inInsertBefore) { + m_ItemList.push_back(inItem); + } else { + TItemList::iterator thePos = m_ItemList.begin(); + for (; thePos != m_ItemList.end(); ++thePos) { + CTreeItem *theItem = *thePos; + if (theItem == inInsertBefore) { + m_ItemList.insert(thePos, inItem); + break; + } + } + } + + inItem->SetParentItem(this); + + UpdateToggle(); + + Invalidate(); +} + +//============================================================================= +/** + * The number of children this item has. Note that this is different than + * the GetChildCount( ) function on the base class CControl. The "children" + * counted by this function are the ones that have been added to this control + * to form a tree by calls to AddItem. + * @return the number of items added a "child tree items" to this one. + */ +long CTreeItem::GetNumChildItems() +{ + return (long)m_ItemList.size(); +} + +//============================================================================= +/** + * Retrieve the child tree item based on it's position within m_ItemList + * @param inIndex position of the child tree item + * @return CTreeItem* ptr to child tree item or nullptr if inIndex is invalid. + */ +CTreeItem *CTreeItem::GetChildItem(long inIndex) +{ + CTreeItem::TItemList::iterator thePos = m_ItemList.begin(); + std::advance(thePos, inIndex); + + if (thePos != m_ItemList.end()) + return (*thePos); + + return nullptr; +} + +//============================================================================= +/** + * Retrieve the index of a child tree item based on it's position within + * m_ItemList. + * @param inChildItem ptr to the child tree item + * @return long index to the child tree item or -1 if inChildItem is invalid. + */ +long CTreeItem::GetChildTreeItemIndex(const CTreeItem *inChildItem) const +{ + TItemList::const_iterator thePos = m_ItemList.begin(); + TItemList::const_iterator theEnd = m_ItemList.end(); + + long theItemIndex(-1); + bool theIsFound(false); + for (; thePos != theEnd && !theIsFound; ++thePos) { + ++theItemIndex; + + if ((*thePos) == inChildItem) + theIsFound = true; + } + + if (theIsFound) + return theItemIndex; + else + return -1; +} + +//============================================================================= +/** + * Retrieves the necessary iterators for searching through this item's list + * of children. You should not need to access this directly. This is provided + * for use by the CTreeControl class. + * @param outListBegin returns an iterator pointing to the first element in the list + * @param outListEnd returns an iterator pointing to the last element + */ +void CTreeItem::GetItemIterator(TItemList::iterator &outListBegin, TItemList::iterator &outListEnd) +{ + outListBegin = m_ItemList.begin(); + outListEnd = m_ItemList.end(); +} + +//============================================================================= +/** + * Retrieves the necessary iterators for searching through this item's list + * of children (in reverse order). You should not need to access this directly. + * This is provided for use by the CTreeControl class. + * @param outListBegin returns a reverse iterator pointing to the last element in the list + * @param outListEnd returns a reverse iterator pointing to the first element + */ +void CTreeItem::GetReverseItemIterator(TItemList::reverse_iterator &outListBegin, + TItemList::reverse_iterator &outListEnd) +{ + outListBegin = m_ItemList.rbegin(); + outListEnd = m_ItemList.rend(); +} + +//============================================================================= +/** + * An item that is a container has a visible toggle that can be clicked to + * hide or show its children. + * @return true if this item is a parent and has children, otherwise false + */ +bool CTreeItem::IsContainer() +{ + return m_ItemList.size() > 0; +} + +//============================================================================= +/** + * @return true if this item is a root level item, false if it has a parent + */ +bool CTreeItem::IsRootItem() +{ + return (!m_Parent); +} + +//============================================================================= +/** + * Removes this tree item and all its children from the tree control. Recursively + * goes through all children and asks them to detach themselves as children of + * the tree control. No items are actually deleted, as this is deferred to + * the class that created the items. + */ +void CTreeItem::RemoveItem() +{ + // Enable or disable the toggle on the parent accordingly + if (m_Parent) + m_Parent->UpdateToggle(); + + // Recursively remove all children + RemoveChildren(); + + // If this item has a parent, ask the parent to remove us from it's list of children + if (m_Parent) + m_Parent->RemoveFromList(this); + + // Remove this item from the control hierarchy + m_TreeControl->RemoveChild(this); +} + +//============================================================================= +/** + * Updates the visibility of the expand toggle. If the the item is a container, + * the toggle is shown, otherwise it is hidden. + */ +void CTreeItem::UpdateToggle() +{ + UICPROFILE(UpdateToggle); + + bool theEnableToggle = IsContainer(); + bool theToggleIsEnabled = m_Toggle->IsEnabled(); + + if (theEnableToggle != theToggleIsEnabled) { + m_Toggle->SetEnabled(theEnableToggle); + Invalidate(); + } +} + +//============================================================================= +/** + * Recursively removes all children from the child list and from the control + * hierarchy maintained by the tree control. + */ +void CTreeItem::RemoveChildren() +{ + // If this item has children + if (IsContainer()) { + // Iterate through each child + TItemList::iterator thePos = m_ItemList.begin(); + for (; thePos != m_ItemList.end(); ++thePos) { + // And recursively remove the child's children + CTreeItem *theItem = *thePos; + theItem->RemoveChildren(); + + // Ask the tree control to remove this child from the control hierarchy + m_TreeControl->RemoveChild(theItem); + } + + // Clear the child list since we deleted all the children + m_ItemList.clear(); + } +} + +//============================================================================= +/** + * Helper function for item removal. Goes through the list of child items that + * belongs to this control and removes the specified item from the list. + * @param inItem item to be removed from list + */ +void CTreeItem::RemoveFromList(CTreeItem *inItem) +{ + TItemList::iterator thePos = m_ItemList.begin(); + for (; thePos != m_ItemList.end(); ++thePos) { + CTreeItem *theItem = *thePos; + if (theItem == inItem) { + m_ItemList.erase(thePos); + break; + } + } +} + +//============================================================================= +/** + * Detaches this item from its parent. + */ +void CTreeItem::Detach() +{ + if (m_Parent) + m_Parent->RemoveFromList(this); +} + +//============================================================================= +/** + * @return true if this item is currently selected, otherwise false. + */ +bool CTreeItem::IsSelected() +{ + return m_IsSelected; +} + +//============================================================================= +/** + * Selects or deselects this row. Color of the selected item changes, as well + * as the item's icon. + * @param inIsSelected true to select this item, false to deselect it + */ +void CTreeItem::SetSelected(bool inIsSelected) +{ + // If this command is actually resulting in a change of state + if (m_IsSelected != inIsSelected) { + m_IsSelected = inIsSelected; + + if (m_ShowVisibleSelection) { + // If the item is to be selected + if (m_IsSelected) { + // Change to the selection color + m_Name->SetFillBackground(true); + + if (!m_SelectedIcon.isNull()) + m_Icon->SetImage(m_SelectedIcon); + } + // Otherwise, the item is to be deselected + else { + // Change to the normal color scheme + m_Name->SetFillBackground(false); + m_Name->SetTextColor(m_TextColor); + + if (!m_NormalIcon.isNull()) + m_Icon->SetImage(m_NormalIcon); + } + } + } +} + +//============================================================================= +/** + * Deselects all children, grandchildren, and so on who are currently selected. + * @return true if there were any selected children who were deselected + */ +bool CTreeItem::DeselectChildren() +{ + bool theChildSelection = false; + + TItemList::iterator thePos = m_ItemList.begin(); + for (; thePos != m_ItemList.end(); ++thePos) { + CTreeItem *theChild = *thePos; + + if (theChild->IsContainer()) { + bool theRecursiveCheck = theChild->DeselectChildren(); + if (!theChildSelection) + theChildSelection = theRecursiveCheck; + } + + if (theChild->IsSelected()) { + m_TreeControl->Deselect(theChild); + theChildSelection = true; + } + } + + return theChildSelection; +} + +//============================================================================= +/** + * Creates the toggle control used by this tree item. + */ +void CTreeItem::CreateToggle() +{ + m_Toggle = new CToggleButton(); + + // Make sure these sizes are accurate + QSize theImageSize = CResourceCache::GetInstance()->GetBitmap("arrow.png").size(); + m_Toggle->SetUpImage("arrow.png"); + + m_Toggle->SetDownImage("arrow_down.png"); + m_Toggle->SetDisabledImage("empty-pixel.png"); + m_Toggle->SetAbsoluteSize({theImageSize.width(), theImageSize.height()}); + m_Toggle->SetEnabled(false); + + // This is to get around a problem in SetIndent when the parent control is 0 + m_IndentSize = theImageSize.width(); +} + +//============================================================================= +/** + * Called when the toggle button for this item is clicked on. Expands the item + * if is currently collapsed, otherwise, collapses the row. + * @param inButton button that generated this event + * @param inState state of the button after the toggle event + */ +void CTreeItem::OnToggleExpansion(CToggleButton *inButton, CButtonControl::EButtonState inState) +{ + Q_UNUSED(inState); + + if (inButton == m_Toggle) + ToggleExpansion(); +} + +//============================================================================= +/** + * Recursive function to help change the visiblity of all children of this item. + */ +void CTreeItem::HideChildItems() +{ + TItemList::iterator thePos = m_ItemList.begin(); + for (; thePos != m_ItemList.end(); ++thePos) { + CTreeItem *theItem = *thePos; + theItem->HideChildItems(); + } + + SetVisible(false); +} + +//============================================================================= +/** + * Recursive function to help change the visiblity of all children of this item. + * If a child is expanded, this function is called recursively to reveal all of + * the grandchildren, and so on. + */ +void CTreeItem::ShowChildItems() +{ + if (m_Parent) + SetVisible(m_Parent->IsVisible()); + else + SetVisible(true); + + TItemList::iterator thePos = m_ItemList.begin(); + for (; thePos != m_ItemList.end(); ++thePos) { + CTreeItem *theItem = *thePos; + if (IsExpanded()) + theItem->ShowChildItems(); + } +} + +//============================================================================= +/** + * Private function for adding children to this control. The only children + * should be a toggle, an icon, and a text control for the name. If you + * need to add another tree item as a "child" of this one, you should use + * AddItem( ). + * @param inControl Control to be added as a child to this one + * @param inInsertBefore Control to insert before in the hierarchy or nullptr to + * insert at the end of the list. + */ +void CTreeItem::AddChild(CControl *inControl, CControl *inInsertBefore /*= nullptr*/) +{ + CFlowLayout::AddChild(inControl, inInsertBefore); +} + +//============================================================================= +/** + * Find the item that this item should be added after to maintian sort order. + */ +CTreeItem *CTreeItem::FindPrevSortSibling(CTreeItem *) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + UIC_THROW(E_FAIL); +#endif + return NULL; +} + +//============================================================================= +/** + * Find the item that this item should be added before to maintian sort order. + */ +CTreeItem *CTreeItem::FindNextSortSibling(CTreeItem *inChild) +{ + CTreeItem *theSortItem = nullptr; + + // No items in the list - return nullptr (because we don't care) + if (m_ItemList.size()) { + CTreeItem::TItemList::iterator thePos = m_ItemList.begin(); + for (; thePos != m_ItemList.end(); ++thePos) { + // Item in the list + theSortItem = *thePos; + if (m_TreeControl->IsItemLess(inChild, theSortItem)) + break; + } + + // Last item in the list + if (thePos == m_ItemList.end()) + theSortItem = nullptr; + } + + return theSortItem; +} + +/** + * Retrieve the edit state of the text edit control associated with this tree item + */ +bool CTreeItem::GetEditMode() +{ + if (m_Name) { + return m_Name->GetEditMode(); + } + + return false; +} + +//============================================================================= +/** + * Sets whether item is 'visibly' selected + */ +void CTreeItem::SetVisibleSelection(bool inValue) +{ + m_ShowVisibleSelection = inValue; +} + +//============================================================================= +/** + * Gets whether item is 'visibly' selected + */ +bool CTreeItem::GetVisibleSelection() const +{ + return m_ShowVisibleSelection; +} diff --git a/src/Authoring/Studio/Controls/TreeItem.h b/src/Authoring/Studio/Controls/TreeItem.h new file mode 100644 index 00000000..78cb54bb --- /dev/null +++ b/src/Authoring/Studio/Controls/TreeItem.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** 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_TREE_ITEM_H +#define INCLUDED_TREE_ITEM_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "FlowLayout.h" +#include "ToggleButton.h" +#include "TextEditInPlace.h" + +#include +//============================================================================== +// Forwards +//============================================================================== +class CTreeControl; +class CRenderer; +class CSIcon; +class CTreeItem; +class CTest_TreeControl; + +//============================================================================= +/** + * Class encapsulating a single row in a tree control. Manages the toggle, the + * icon, and the name of the tree item. When you create a tree item you must + * associate it with a tree control. Then you can specify it's parent when you + * call AddItem( ). + */ +class CTreeItem : public CFlowLayout +{ +public: + typedef std::vector TItemList; + +public: + CTreeItem(CTreeControl *inTreeControl); + virtual ~CTreeItem(); + + DEFINE_OBJECT_COUNTER(CTreeItem) + + void Draw(CRenderer *inRenderer) override; + + void SetBackgroundColor(const ::CColor &inColor); + ::CColor GetBackgroundColor(); + void SetTextColor(const ::CColor &inColor); + void SetTextBGFocusColor(const ::CColor &inColor); + + void SetParentItem(CTreeItem *inParent); + CTreeItem *GetParentItem(); + bool GetEditMode(); + + virtual void SetIcon(const QString &inIcon, + const QString &inSelectedIcon); + virtual void SetIcon(const QPixmap &inNormalIcon, const QPixmap &inSelectedIcon); + void SetIsNameEditable(bool inIsEditable); + virtual void SetText(const Q3DStudio::CString &inText); + virtual Q3DStudio::CString GetText(); + virtual void OnNameChanged(CControl *inControl); + void SetIndent(long inAmount, bool inIsRecursive); + + bool OnMouseDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseDoubleClick(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + bool OnMouseRDown(CPt inPoint, Qt::KeyboardModifiers inFlags) override; + + bool IsExpanded(); + virtual void ToggleExpansion(); + virtual void Expand(); + virtual void Collapse(); + + virtual void AddItem(CTreeItem *inItem, CTreeItem *inInsertBefore = nullptr); + long GetNumChildItems(); + CTreeItem *GetChildItem(long inIndex); + long GetChildTreeItemIndex(const CTreeItem *inChildItem) const; + void GetItemIterator(TItemList::iterator &outListBegin, TItemList::iterator &outListEnd); + void GetReverseItemIterator(TItemList::reverse_iterator &outListBegin, + TItemList::reverse_iterator &outListEnd); + virtual bool IsContainer(); + bool IsRootItem(); + virtual void RemoveItem(); + void UpdateToggle(); + virtual void RemoveChildren(); + void RemoveFromList(CTreeItem *inItem); + virtual void Detach(); + virtual CTreeItem *FindPrevSortSibling(CTreeItem *inChild); + virtual CTreeItem *FindNextSortSibling(CTreeItem *inChild); + + bool IsSelected(); + virtual void SetSelected(bool inIsSelected); + bool DeselectChildren(); + + void SetVisibleSelection(bool inValue); + bool GetVisibleSelection() const; + + boost::signal1 SigToggle; + +protected: + // Member Vars + CTreeControl *m_TreeControl; + CTreeItem *m_Parent; + CToggleButton *m_Toggle; + CTextEditInPlace *m_Name; + CCommitDataListener *m_NameChangeListener; + CSIcon *m_Icon; + QPixmap m_NormalIcon; + QPixmap m_SelectedIcon; + TItemList m_ItemList; + long m_ControlGap; + long m_IndentLevel; + long m_IndentSize; + bool m_IsExpanded; + bool m_IsSelected; + bool m_ShowVisibleSelection; + ::CColor m_Color; + ::CColor m_TextColor; + + // Member Functions + void CreateToggle(); + void OnToggleExpansion(CToggleButton *inButton, CButtonControl::EButtonState inState); + void HideChildItems(); + void ShowChildItems(); + +private: + /// Private because no one outside this class should be calling it; use AddItem( ) instead. + void AddChild(CControl *inControl, CControl *inInsertBefore = nullptr) override; +}; +#endif // INCLUDED_TREE_ITEM_H diff --git a/src/Authoring/Studio/Controls/WidgetControl.cpp b/src/Authoring/Studio/Controls/WidgetControl.cpp new file mode 100644 index 00000000..ae45468a --- /dev/null +++ b/src/Authoring/Studio/Controls/WidgetControl.cpp @@ -0,0 +1,439 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "WidgetControl.h" + +#include "Control.h" +#include "DropSource.h" +#include "IDragable.h" +#include "OffscreenRenderer.h" +#include "Pt.h" +#include "Rct.h" +#include "UICFile.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +WidgetControl::WidgetControl(CControl *control, QWidget *parent) + : QWidget(parent) + , m_control(control) + , m_controlListener(this) +{ + Q_ASSERT(control); + control->SetWindowListener(&m_controlListener); + setControlSize(sizeHint()); +} + +bool WidgetControl::event(QEvent *event) +{ + if (event->type() == QEvent::ShortcutOverride) { + QKeyEvent *ke = static_cast(event); + m_control->OnKeyDown(ke->key(), ke->modifiers()); + } + return QWidget::event(event); +} + +void WidgetControl::showEvent(QShowEvent *event) +{ + QWidget::showEvent(event); +} + +void WidgetControl::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + const auto boundRect = QRect(QPoint(0,0), size()); + CWinRenderer renderer(&painter, boundRect); + CRct rect(event->rect()); + m_control->OnDraw(&renderer, rect, true); + + QWidget::paintEvent(event); +} + +void WidgetControl::resizeEvent(QResizeEvent *event) +{ + setControlSize(event->size()); + QWidget::resizeEvent(event); +} + +void WidgetControl::keyPressEvent(QKeyEvent *event) +{ + m_control->OnKeyDown(event->key(), event->modifiers()); + m_control->OnChar(event->text(), event->modifiers()); + QWidget::keyPressEvent(event); +} + +void WidgetControl::keyReleaseEvent(QKeyEvent *event) +{ + m_control->OnKeyUp(event->key(), event->modifiers()); + QWidget::keyReleaseEvent(event); +} + +void WidgetControl::mousePressEvent(QMouseEvent *event) +{ + const auto pos = CPt(event->pos()); + if (m_isLeftMouseDown) + m_control->OnMouseUp(pos, event->modifiers()); + + m_isLeftMouseDown = (event->button() == Qt::LeftButton); + if (m_isLeftMouseDown) + m_control->OnMouseDown(pos, event->modifiers()); + else + m_control->OnMouseRDown(pos, event->modifiers()); + + setFocus(); + QWidget::mousePressEvent(event); +} + +void WidgetControl::mouseReleaseEvent(QMouseEvent *event) +{ + const auto pos = CPt(event->pos()); + if (event->button() == Qt::LeftButton) { + m_isLeftMouseDown = false; + m_control->OnMouseUp(pos, event->modifiers()); + } else { + m_control->OnMouseRUp(pos, event->modifiers()); + } + + QWidget::mouseReleaseEvent(event); +} + +void WidgetControl::mouseMoveEvent(QMouseEvent *event) +{ + m_control->OnMouseMove(event->pos(), event->modifiers()); + QWidget::mouseMoveEvent(event); +} + +void WidgetControl::mouseDoubleClickEvent(QMouseEvent *event) +{ + // call QWidget handler first to not deliver OnMouseDown after OnMouseDoubleClick + QWidget::mouseDoubleClickEvent(event); + m_control->OnMouseDoubleClick(event->pos(), event->modifiers()); +} + +void WidgetControl::wheelEvent(QWheelEvent *event) +{ + m_control->OnMouseWheel(event->pos(), event->angleDelta().y(), event->modifiers()); + QWidget::wheelEvent(event); +} + +void WidgetControl::enterEvent(QEvent *event) +{ + setMouseTracking(true); + m_control->OnMouseHover(mapFromGlobal(QCursor::pos()), {}); + QWidget::enterEvent(event); +} + +void WidgetControl::leaveEvent(QEvent *event) +{ + setMouseTracking(false); + m_control->OnMouseOut(mapFromGlobal(QCursor::pos()), {}); + QWidget::leaveEvent(event); +} + +void WidgetControl::focusInEvent(QFocusEvent *event) +{ + m_control->OnGainFocus(); + QWidget::focusInEvent(event); +} + +void WidgetControl::focusOutEvent(QFocusEvent *event) +{ + if (!m_isContextMenuShown) + m_control->OnLoseFocus(); + QWidget::focusOutEvent(event); +} + +QSize WidgetControl::sizeHint() const +{ + const auto preferredSize = m_control->GetPreferredSize(); + return QSize(preferredSize.x, preferredSize.y); +} + +/* + * CPaletteManager::GetTimelineControl() needs a way of accessing + * the CControl inside the widget + */ +CControl *WidgetControl::getControl() const +{ + return m_control; +} + +void WidgetControl::setControlSize(const QSize &size) +{ + m_control->SetSize(size.width(), size.height()); +} + +void WidgetControl::DoStartDrag(IDragable *inDragable) +{ + if (m_isDragging || !m_isLeftMouseDown) + return; + + QDrag drag(this); + m_isDragging = true; + + drag.setMimeData(CDropSourceFactory::Create(inDragable->GetFlavor(), inDragable)); + drag.exec(); + m_isLeftMouseDown = false; + + m_isDragging = false; +} + +void WidgetControl::DoStartDrag(std::vector &inDragFileNameList) +{ + if (m_isDragging || !m_isLeftMouseDown) + return; + + QDrag drag(this); + m_isDragging = true; + + try { + auto thePos = inDragFileNameList.begin(); + auto theEndPos = inDragFileNameList.end(); + + Q3DStudio::CAutoMemPtr theDragFile; + for (; thePos != theEndPos; ++thePos) { + Q3DStudio::CString theDragFileName = *thePos; + if (theDragFileName.Length() > 0) { + theDragFile = new CUICFile(theDragFileName); + CDropSource *theDropSource = CDropSourceFactory::Create( + EUIC_FLAVOR_ASSET_UICFILE, (void *)theDragFile, sizeof(theDragFile)); + // Add the UIC_GESTURE_FLAVOR. This will allow us to drag to StudioControls. + drag.setMimeData(theDropSource); + break; + } + } + drag.exec(); + m_isLeftMouseDown = false; + } catch (...) { // if there are any errors that throws an exception, there + // there will be no more drag and drop, since the flag will not be reset. + } + + m_isDragging = false; +} + +bool WidgetControl::OnDragWithin(CDropSource &inSource) +{ + bool theReturn = false; + CPt thePoint = inSource.GetCurrentPoint(); + Qt::KeyboardModifiers theFlags = inSource.GetCurrentFlags(); + CDropTarget *theDropTarget = m_control->FindDropCandidate(thePoint, theFlags); + + if (theDropTarget) { + theReturn = theDropTarget->Accept(inSource); + delete theDropTarget; + } + return theReturn; +} + +bool WidgetControl::OnDragReceive(CDropSource &inSource) +{ + bool theReturn = false; + CPt thePoint = inSource.GetCurrentPoint(); + Qt::KeyboardModifiers theFlags = inSource.GetCurrentFlags(); + + CDropTarget *theDropTarget = m_control->FindDropCandidate(thePoint, theFlags); + + if (theDropTarget) { + theReturn = theDropTarget->Drop(inSource); + delete theDropTarget; + } + return theReturn; +} + +void WidgetControl::OnDragLeave() +{ + m_control->OnMouseMove(CPt(-1, -1), 0); +} + +void WidgetControl::OnReflectMouse(CPt &inPoint, Qt::KeyboardModifiers inFlags) +{ + // Notify the control that the mouse moved + m_control->OnMouseMove(inPoint, inFlags /*CHotKeys::GetCurrentKeyModifiers( )*/); + + // If the control invalidated because of a mouse event then we want to do an immediate redraw. + // this ensures consistent visible feedback. + if (m_control->IsChildInvalidated()) + repaint(); +} + +//============================================================================= +/** + * Creates the pass thru class for the wnd control. + */ +WidgetControlControlListener::WidgetControlControlListener(WidgetControl *inParent) +{ + m_Parent = inParent; +} + +WidgetControlControlListener::~WidgetControlControlListener() +{ +} + +//============================================================================= +/** + * Notification from the control that the window was invalidated. + */ +void WidgetControlControlListener::OnControlInvalidated() +{ + m_Parent->update(); +} + +//============================================================================= +/** + * Notification from the control to do a popup at the specified location. + */ +long WidgetControlControlListener::DoPopup(QMenu *inMenu, CPt inPoint) +{ + long selectedIndex = -1; + if (inMenu) { + m_Parent->setContextMenuShown(true); + auto action = inMenu->exec(m_Parent->mapToGlobal(inPoint)); + m_Parent->setContextMenuShown(false); + if (action) + selectedIndex = inMenu->actions().indexOf(action); + } + + return selectedIndex; +} + +//============================================================================= +/** + * Get the location of the point in Screen coordinates. + */ +CPt WidgetControlControlListener::ClientToScreen(CPt inPoint) +{ + return m_Parent->mapToGlobal(inPoint); +} + +//============================================================================= +/** + * Get the location of the point into client coordinates. + */ +CPt WidgetControlControlListener::ScreenToClient(CPt inPoint) +{ + return m_Parent->mapFromGlobal(inPoint); +} + +//============================================================================= +/** + * Get the platform dependent view that this is embedding. + * Used when platform dependent controls need to be embedded into the Controls. + */ +TPlatformView WidgetControlControlListener::GetPlatformView() +{ +#ifdef KDAB_TEMPORARILY_REMOVED + return m_Parent->m_hWnd; +#else + return nullptr; +#endif +} + +//============================================================================= +/** + * Pass-thru to the CWndControl's SetIsDragging function. + * @param inIsDragging true to specify that a drag is occurring or false to cancel a drag + */ +void WidgetControlControlListener::SetIsDragging(bool inIsDragging) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + m_Parent->SetIsDragging(inIsDragging); +#endif +} + +//============================================================================= +/** + * Pass-thru to the CWndControl's ShowTooltips function. + * @param inLocation mid-point of the tooltip in global coordinates + * @param inText text to display as a tooltip + */ +void WidgetControlControlListener::ShowTooltips(CPt inLocation, const Q3DStudio::CString &inText) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + m_Parent->ShowTooltips(inLocation, inText); +#endif +} + +//============================================================================= +/** + * Pass-thru to the CWndControl's HideTooltips function. + */ +void WidgetControlControlListener::HideTooltips() +{ +#ifdef KDAB_TEMPORARILY_REMOVED + m_Parent->HideTooltips(); +#endif +} + +//============================================================================= +/** + * Pass-thru to the CWndControl's ShowMoveableTooltips function. + * @param inLocation mid-point of the tooltip in global coordinates + * @param inText text to display as a tooltip + */ +void WidgetControlControlListener::ShowMoveableWindow(CPt inLocation, const Q3DStudio::CString &inText, + CRct inBoundingRct) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + m_Parent->ShowMoveableWindow(inLocation, inText, inBoundingRct); +#endif +} + +//============================================================================= +/** + * Pass-thru to the CWndControl's HideMoveableTooltips function. + */ +void WidgetControlControlListener::HideMoveableWindow() +{ +#ifdef KDAB_TEMPORARILY_REMOVED + m_Parent->HideMoveableWindow(); +#endif +} + +void WidgetControlControlListener::DoStartDrag(IDragable *inDragable) +{ + m_Parent->DoStartDrag(inDragable); +} + +//=============================================================================== +/** +* performs a drag operation on a file +*/ +void WidgetControlControlListener::DoStartDrag(std::vector &inDragFileNameList) +{ + m_Parent->DoStartDrag(inDragFileNameList); +} + + + diff --git a/src/Authoring/Studio/Controls/WidgetControl.h b/src/Authoring/Studio/Controls/WidgetControl.h new file mode 100644 index 00000000..8c30f1bb --- /dev/null +++ b/src/Authoring/Studio/Controls/WidgetControl.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 WIDGETCONTROL_H +#define WIDGETCONTROL_H + +#include + +#include "Control.h" +#include "DropContainer.h" + +class CRenderer; +class WidgetControl; + +class WidgetControlControlListener : public CControlWindowListener +{ +public: + WidgetControlControlListener(WidgetControl *inParent); + virtual ~WidgetControlControlListener(); + + void OnControlInvalidated() override; + long DoPopup(QMenu *inMenu, CPt inLocation) override; + CPt ClientToScreen(CPt inPoint) override; + CPt ScreenToClient(CPt inPoint) override; + TPlatformView GetPlatformView() override; + void SetIsDragging(bool inIsDragging) override; + void ShowTooltips(CPt inLocation, const Q3DStudio::CString &inText) override; + void HideTooltips() override; + void DoStartDrag(IDragable *inDragable) override; + void DoStartDrag(std::vector &inDragFileNameList) override; + void ShowMoveableWindow(CPt inLocation, const Q3DStudio::CString &inText, CRct inBoundingRct) override; + void HideMoveableWindow() override; + +protected: + WidgetControl *m_Parent; +}; +class WidgetControl : public QWidget, public CWinDropContainer +{ + Q_OBJECT + friend class ::WidgetControlControlListener; +public: + explicit WidgetControl(CControl *control, QWidget *parent = nullptr); + void setContextMenuShown(bool shown) { m_isContextMenuShown = shown; } + +protected: + bool event(QEvent *event) override; + void showEvent(QShowEvent *event) override; + void paintEvent(QPaintEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + void wheelEvent(QWheelEvent *event) override; + void enterEvent(QEvent *event) override; + void leaveEvent(QEvent *event) override; + void focusInEvent(QFocusEvent *event) override; + void focusOutEvent(QFocusEvent *event) override; + +public: + QSize sizeHint() const override; + CControl *getControl() const; + +protected: + void DoStartDrag(IDragable *inDragable); + void DoStartDrag(std::vector &inDragFileNameList); + + bool OnDragWithin(CDropSource &inSource) override; + bool OnDragReceive(CDropSource &inSource) override; + void OnDragLeave() override; + void OnReflectMouse(CPt &inPoint, Qt::KeyboardModifiers inFlags) override; + +private: + void setControlSize(const QSize &size); + + CControl *m_control; + bool m_isLeftMouseDown = false; + bool m_isDragging = false; + bool m_isContextMenuShown = false; + WidgetControlControlListener m_controlListener; +}; + +#endif // WIDGETCONTROL_H diff --git a/src/Authoring/Studio/Docs/CmdLineOptions.txt b/src/Authoring/Studio/Docs/CmdLineOptions.txt new file mode 100644 index 00000000..42610e8a --- /dev/null +++ b/src/Authoring/Studio/Docs/CmdLineOptions.txt @@ -0,0 +1,27 @@ +-t, -test - Runs the specified Unit Test(s) (TEST_CMD_LINE) +-n - Normal operation (NORMAL) +-replay - Replay File +-export - Export the file. Usage: Studio.exe -export AMWFilename AMCFilename DOMPath [ slide index(optional and defaults to 1) ] +-silent - Run silent run deep +-refresh - Refresh resources + +Unused: +-u, -xml - TEST_XML +-i, -testInfo - TEST_INFO + +It is possible to stack command line options, with left to right operation precedence. With the exception of +-test and -silent which take effect regardless of ordering. Any failed operations would result in the +aborting of subsequent operations, and a -1 (failure) value will be returned. + +Example 1: +StudioC -silent -refresh myFile.uip -export myOutput.amc Scene.Layer.Component +Refreshes the myFile.uip, then exports to myOutput.amc the component found at the indicated DOM path. No dialogs are +displayed. Error messages are piped to stdout. + +Example 2: +Studio -refresh myFile.uip myOutput.xgf -export +Refreshes myFile.uip then exports to myOutput.xgf using the XGF exporter. + +Example 3: +StudioC -silent -export myFile.uip -refresh myOutput.avi +Exports myFile.uip to myOutput.avi THEN refreshes myFile.uip. Error messages are piped to stdout. \ No newline at end of file diff --git a/src/Authoring/Studio/DragAndDrop/BasicObjectDropSource.cpp b/src/Authoring/Studio/DragAndDrop/BasicObjectDropSource.cpp new file mode 100644 index 00000000..089a9c97 --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/BasicObjectDropSource.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** 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 "BasicObjectDropSource.h" +#include "Doc.h" +#include "DropTarget.h" + +#include "Dialogs.h" +#include "Dispatch.h" +#include "StudioApp.h" +#include "Core.h" +#include "UICDMStudioSystem.h" +#include "ClientDataModelBridge.h" +#include "UICDMDataCore.h" +#include "IDocumentEditor.h" +#include "ImportUtils.h" +#include "BasicObjectsModel.h" +#include "IDragable.h" +#include "IDocSceneGraph.h" +#include "UICTextRenderer.h" +#include "HotKeys.h" +#include "StudioUtils.h" + +#include + +//=============================================================================== +/** + * + */ +CBasicObjectDropSource::CBasicObjectDropSource(long inFlavor, IDragable *inDragable) + : CDropSource(inFlavor, 0) + , m_IsIndependent(false) +{ + auto item = dynamic_cast(inDragable); + if (item) { + m_ObjectType = item->objectType(); + m_PrimitiveType = item->primitiveType(); + } +} + +//=============================================================================== +/** + * + */ +bool CBasicObjectDropSource::ValidateTarget(CDropTarget *inTarget) +{ + using namespace Q3DStudio; + + EStudioObjectType targetType = (EStudioObjectType)inTarget->GetObjectType(); + bool theValidTarget = false; + + // the only thing we want to do from here is check the type. + theValidTarget = + CStudioObjectTypes::AcceptableParent((EStudioObjectType)m_ObjectType, targetType); + + if (!theValidTarget) { + SetHasValidTarget(theValidTarget); + return theValidTarget; + } else { + if (CHotKeys::IsKeyDown(Qt::AltModifier) && targetType != OBJTYPE_SCENE + && targetType != OBJTYPE_COMPONENT) { + UICDM::CUICDMInstanceHandle theTarget = inTarget->GetInstance(); + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + IDocumentReader &theReader(theDoc->GetDocumentReader()); + UICDM::CUICDMSlideHandle toSlide = theReader.GetAssociatedSlide(theTarget); + ; + + if (!theReader.IsMasterSlide(toSlide)) + theValidTarget = false; + } + + SetHasValidTarget(theValidTarget); + return theValidTarget; + } +} + +//=============================================================================== +/** + * + */ +bool CBasicObjectDropSource::CanMove() +{ + return true; +} + +//=============================================================================== +/** + * + */ +bool CBasicObjectDropSource::CanCopy() +{ + return true; +} + +CCmd *CBasicObjectDropSource::GenerateAssetCommand(UICDM::CUICDMInstanceHandle inTarget, + EDROPDESTINATION inDestType, + UICDM::CUICDMSlideHandle inSlide) +{ + using namespace Q3DStudio; + using UICDM::ComposerObjectTypes; + using namespace std; + + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + CPt thePoint; + // if ( CHotKeys::IsKeyDown( CHotKeys::KEY_MENU ) ) + // thePoint = GetCurrentPoint(); + + long theStartTime = -1; + if (CHotKeys::IsKeyDown(Qt::ControlModifier)) + theStartTime = theDoc->GetCurrentViewTime(); + + DocumentEditorInsertType::Enum theInsertType(ImportUtils::GetInsertTypeForDropType(inDestType)); + ComposerObjectTypes::Enum theComposerType; + switch (m_ObjectType) { + case OBJTYPE_SCENE: + theComposerType = ComposerObjectTypes::Scene; + break; + case OBJTYPE_LAYER: + theComposerType = ComposerObjectTypes::Layer; + break; + case OBJTYPE_BEHAVIOR: + theComposerType = ComposerObjectTypes::Behavior; + break; + case OBJTYPE_MATERIAL: + theComposerType = ComposerObjectTypes::Material; + break; + case OBJTYPE_CAMERA: + theComposerType = ComposerObjectTypes::Camera; + break; + case OBJTYPE_LIGHT: + theComposerType = ComposerObjectTypes::Light; + break; + case OBJTYPE_MODEL: + theComposerType = ComposerObjectTypes::Model; + break; + case OBJTYPE_GROUP: + theComposerType = ComposerObjectTypes::Group; + break; + case OBJTYPE_IMAGE: + theComposerType = ComposerObjectTypes::Image; + break; + case OBJTYPE_TEXT: + theComposerType = ComposerObjectTypes::Text; + break; + case OBJTYPE_COMPONENT: + theComposerType = ComposerObjectTypes::Component; + break; + case OBJTYPE_ALIAS: + theComposerType = ComposerObjectTypes::Alias; + break; + case OBJTYPE_PATH: + theComposerType = ComposerObjectTypes::Path; + break; + default: + QT3DS_ASSERT(false); + theComposerType = ComposerObjectTypes::Unknown; + break; + } + if (theComposerType != ComposerObjectTypes::Unknown) { + if (theComposerType == ComposerObjectTypes::Text) { + // For Text, we need to check if user already has font file inside fonts folder + CFilePath theFontFile; + CFilePath theFontDir = CFilePath::CombineBaseAndRelative(theDoc->GetDocumentDirectory(), + CFilePath(L"fonts")); + if (!theFontDir.Exists()) { + // Create font dir if necessary + theFontDir.CreateDir(true); + } else { + // Recursively find the first font file in font dir + vector theFiles; + theFontDir.RecursivelyFindFilesOfType(nullptr, theFiles, false); + for (size_t i = 0; i < theFiles.size(); ++i) { + if (CDialogs::IsFontFileExtension(theFiles[i].GetExtension())) { + // Reuse the font in fonts subdirectory + theFontFile = theFiles[i]; + break; + } + } + } + + if (theFontFile == L"") { + // If user doesn't have any font file, copy the default font file from Studio's res + // folder + + CFilePath theResFontFile; + + QDir theResFontDir(resourcePath() + "/Font"); + Q_FOREACH (QFileInfo fontFile, theResFontDir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot)) { + CString ext = CString::fromQString(fontFile.suffix()); + if (CDialogs::IsFontFileExtension(ext)) { + theResFontFile = CString::fromQString(fontFile.absoluteFilePath()); + theFontFile = CFilePath::CombineBaseAndRelative(theFontDir, CString::fromQString(fontFile.fileName())); + break; + } + } + + if (theResFontFile == L"") { + QT3DS_ASSERT(false); + std::shared_ptr theHandler( + theDoc->GetImportFailedHandler()); + if (theHandler) + theHandler->DisplayImportFailed( + theResFontDir.absolutePath(), + QObject::tr("Default Font File Doesn't Exist in the Directory"), + false); + return nullptr; + } + + // Copy the file to project's fonts folder + SFileTools::Copy(theFontFile, + Q3DStudio::FileOpenFlags(Q3DStudio::FileOpenFlagValues::Create), + theResFontFile); + // Force the text renderer to refresh + if (theDoc->GetSceneGraph() && theDoc->GetSceneGraph()->GetTextRenderer()) + theDoc->GetSceneGraph()->GetTextRenderer()->ReloadFonts(); + } + + // Lastly, we use the font file to create the Text object. This is similar to drag-drop + // the font file from Project Palette to Scene. + SCOPED_DOCUMENT_EDITOR(*theDoc, QObject::tr("Add Text")) + ->ImportFile(DocumentEditorFileType::Font, theFontFile, inTarget, inSlide, + CDialogs::GetImportFileExtension(), + Q3DStudio::ImportUtils::GetInsertTypeForDropType(inDestType), thePoint, + theStartTime); + } else { + SCOPED_DOCUMENT_EDITOR(*theDoc, QObject::tr("Add Instance")) + ->CreateSceneGraphInstance(theComposerType, inTarget, inSlide, theInsertType, + thePoint, (EPrimitiveType)m_PrimitiveType, theStartTime); + } + } + return nullptr; +} diff --git a/src/Authoring/Studio/DragAndDrop/BasicObjectDropSource.h b/src/Authoring/Studio/DragAndDrop/BasicObjectDropSource.h new file mode 100644 index 00000000..454fce9e --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/BasicObjectDropSource.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** 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 __BasicObjectDropSource_H__ +#define __BasicObjectDropSource_H__ + +//============================================================================== +// Includes +//============================================================================== +#include "DropSource.h" +#include "StudioObjectTypes.h" + +class CStudioApp; +class CDropTarget; + +class CBasicObjectDropSource : public CDropSource +{ +public: + CBasicObjectDropSource(long inFlavor, IDragable *inDragable); + + // CDropSource + bool CanMove() override; + bool CanCopy() override; + bool ValidateTarget(CDropTarget *inTarget) override; + + CCmd *GenerateAssetCommand(UICDM::CUICDMInstanceHandle inTarget, + EDROPDESTINATION inDestType, + UICDM::CUICDMSlideHandle inSlide) override; + +protected: + EPrimitiveType m_PrimitiveType; + bool m_IsIndependent; +}; + +#endif // #ifndef __BasicObjectDropSource_H__ diff --git a/src/Authoring/Studio/DragAndDrop/DropContainer.cpp b/src/Authoring/Studio/DragAndDrop/DropContainer.cpp new file mode 100644 index 00000000..b1ed7a6c --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/DropContainer.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 "StudioApp.h" +#include "DropContainer.h" +#include "HotKeys.h" +#include "MouseCursor.h" +#include "FileDropSource.h" +#include "ResourceCache.h" + +//=============================================================================== +/** + * A derived object will call this to subscribe to Drop Flavors. + * @param inMainFlavor the Flavor to add. + * @see CDropSource.h + */ +void CDropContainer::AddMainFlavor(long inMainFlavor) +{ + m_Flavors.push_back(inMainFlavor); +} + +//=============================================================================== +/** + * This an accessor to get the begining of the iterator. + * @return the Iterator + */ +CDropContainer::TFlavorItr CDropContainer::GetFlavorBegin() +{ + return m_Flavors.begin(); +} + +//=============================================================================== +/** + * This is an iterator to the end. + * @return the Iterator + */ +CDropContainer::TFlavorItr CDropContainer::GetFlavorEnd() +{ + return m_Flavors.end(); +} + +//=============================================================================== +/** + * Constructor to build the container. + * This also sets up the DropProxy. + * @see CDropProxy + */ +CWinDropContainer::CWinDropContainer() + : m_DropProxy(this) +{ +} +//=============================================================================== +/** + * Destructor + */ +CWinDropContainer::~CWinDropContainer() +{ +} + +//=============================================================================== +/** + * This is so the Window that is derived from CWinContainer can receive drags. + * @param inWindow the outer to drag. + */ +void CWinDropContainer::RegiserForDnd(QWidget *inWindow) +{ + // This passes the inWindow down to the COLEDropSource. + m_DropProxy.Register(inWindow); +} diff --git a/src/Authoring/Studio/DragAndDrop/DropContainer.h b/src/Authoring/Studio/DragAndDrop/DropContainer.h new file mode 100644 index 00000000..808a5bf4 --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/DropContainer.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2003 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_DROPCONTAINER +#define INCLUDED_DROPCONTAINER + +//============================================================================== +// Includes +//============================================================================== +#include "DropProxy.h" +#include "DropSource.h" +#include + +class CStudioApp; + +class CDropContainer +{ +public: + typedef std::vector TFlavor; + typedef TFlavor::iterator TFlavorItr; + +protected: + TFlavor m_Flavors; ///< This is a list of flavors handled by this container. + +public: + CDropContainer() {} + virtual ~CDropContainer() {} + + CDropContainer::TFlavorItr GetFlavorBegin(); + CDropContainer::TFlavorItr GetFlavorEnd(); + + void AddMainFlavor(long inMainFlavor); + + // These need to get implemented by the Cross platform Container. + virtual bool OnDragWithin(CDropSource &inSource) = 0; + virtual bool OnDragReceive(CDropSource &inSource) = 0; + virtual void OnDragLeave() = 0; + virtual void OnReflectMouse(CPt &inPoint, Qt::KeyboardModifiers inFlags) = 0; +}; + +class CWinDropContainer : public CDropContainer +{ +public: + CWinDropContainer(); + virtual ~CWinDropContainer(); + + void RegiserForDnd(QWidget *inWindow); + long ReflectMouse(long inX, long inY); + +protected: + // These are utility functions. + CDropProxy m_DropProxy; ///< The COLEDropSource pass through. +}; + +#endif \ No newline at end of file diff --git a/src/Authoring/Studio/DragAndDrop/DropSource.cpp b/src/Authoring/Studio/DragAndDrop/DropSource.cpp new file mode 100644 index 00000000..06a3fc8a --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/DropSource.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2003 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "DropTarget.h" +#include "StudioObjectTypes.h" +#include "HotKeys.h" +#include "Doc.h" +#include "IDragable.h" +#include "FileDropSource.h" +#include "ExplorerFileDropSource.h" +#include "TimelineDropSource.h" +#include "BasicObjectDropSource.h" +#include "ListBoxDropSource.h" + +CDropSource::CDropSource(long inFlavor, unsigned long inSize) + : m_Flavor(inFlavor) + , m_Size(inSize) + , m_ObjectType(0) + , m_HasValidTarget(false) + , m_CurrentFlags(0) +{ +} + +CDropSource::~CDropSource() +{ +} + +CDropSource *CDropSourceFactory::Create(long inFlavor, void *inData, unsigned long inSize) +{ + CDropSource *theDropSource(nullptr); + switch (inFlavor) { + + case EUIC_FLAVOR_FILE: { + theDropSource = new CExplorerFileDropSource(inFlavor, inData, inSize); + } break; + case EUIC_FLAVOR_TEXT: + // Don't do anythiing for this + break; + + case EUIC_FLAVOR_ASSET_UICFILE: + // make an Aset out of this. + theDropSource = new CFileDropSource(inFlavor, inData, inSize); + break; + } + + return theDropSource; +} + +CDropSource *CDropSourceFactory::Create(long inFlavor, IDragable *inDragable) +{ + CDropSource *theDropSource(nullptr); + switch (inFlavor) { + case EUIC_FLAVOR_LISTBOX: + theDropSource = new CListBoxDropSource(inFlavor, inDragable); + break; + + case EUIC_FLAVOR_BASIC_OBJECTS: + theDropSource = new CBasicObjectDropSource(inFlavor, inDragable); + break; + + case EUIC_FLAVOR_ASSET_TL: + theDropSource = new CTimeLineDropSource(inFlavor, inDragable); + break; + + default: + theDropSource = Create(inFlavor, reinterpret_cast(inDragable), sizeof(inDragable)); + } + + return theDropSource; +} + +CDropSource *CDropSourceFactory::Extract(long inFlavor, void *inData, unsigned long /*inSize*/) +{ + CDropSource *theDropSource(nullptr); + switch (inFlavor) { + // For all of the Studio Flavors we just need to extract the dropsource out of it. + case EUIC_FLAVOR_LISTBOX: + // make an Aset out of this. + theDropSource = static_cast(inData); + break; + + case EUIC_FLAVOR_BASIC_OBJECTS: + // make an Aset out of this. + theDropSource = static_cast(inData); + break; + + case EUIC_FLAVOR_ASSET_TL: + // cast it to the right type just so we don't loose the virtual table. + theDropSource = static_cast(inData); + break; + + case EUIC_FLAVOR_ASSET_UICFILE: + theDropSource = static_cast(inData); + + break; + default: + theDropSource = nullptr; + } + + return theDropSource; +} diff --git a/src/Authoring/Studio/DragAndDrop/DropSource.h b/src/Authoring/Studio/DragAndDrop/DropSource.h new file mode 100644 index 00000000..542b14ac --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/DropSource.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2003 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 +//============================================================================== +#ifndef INCLUDED_DROPSOURCE +#define INCLUDED_DROPSOURCE + +#include "UICDMHandles.h" +#include "Pt.h" +#include "Cmd.h" + +#include + +typedef enum _EDROPDESTINATION { + EDROPDESTINATION_ON, ///< drop occurs on the target asset + EDROPDESTINATION_ABOVE, ///< drop occurs above the target asset + EDROPDESTINATION_BELOW ///< drop occurs below the target asset +} EDROPDESTINATION; + +class CDropTarget; +class IDragable; +class CStudioApp; + +class CDropSource : public QMimeData +{ +protected: + long m_Flavor; + unsigned long m_Size; + + UICDM::TInstanceHandleList m_Instances; + long m_ObjectType; + bool m_HasValidTarget; + CPt m_CurrentPoint; + Qt::KeyboardModifiers m_CurrentFlags; + +public: + CDropSource(long inFlavor, unsigned long inSize); + virtual ~CDropSource(); + + virtual bool CanMove() = 0; + virtual bool CanCopy() = 0; + long GetObjectType() const { return m_ObjectType; } + long GetFlavor() const { return m_Flavor; } + virtual bool ValidateTarget(CDropTarget *) = 0; + + virtual bool GetHasValidTarget() const { return m_HasValidTarget; } + virtual void SetHasValidTarget(bool inValid) { m_HasValidTarget = inValid; } + virtual void InterpretKeyFlags(long) {} + + virtual void SetCurrentPoint(CPt &inPoint) { m_CurrentPoint = inPoint; } + virtual CPt GetCurrentPoint() const { return m_CurrentPoint; } + + virtual void SetCurrentFlags(Qt::KeyboardModifiers inFlags) { m_CurrentFlags = inFlags; } + virtual Qt::KeyboardModifiers GetCurrentFlags() const { return m_CurrentFlags; } + + virtual CCmd *GenerateAssetCommand(UICDM::CUICDMInstanceHandle, EDROPDESTINATION, + UICDM::CUICDMSlideHandle) + { + return nullptr; + } + virtual CCmd *GenerateSlideCommand(long) { return nullptr; } +}; + +class CDropSourceFactory +{ +public: + static CDropSource *Create(long inFlavor, IDragable *inDragable); + static CDropSource *Create(long inFlavor, void *inData, unsigned long inSize); + static CDropSource *Extract(long inFlavor, void *inData, unsigned long inSize); +}; + +#endif diff --git a/src/Authoring/Studio/DragAndDrop/DropTarget.cpp b/src/Authoring/Studio/DragAndDrop/DropTarget.cpp new file mode 100644 index 00000000..2ca783e5 --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/DropTarget.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2003 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "StudioApp.h" +#include "Core.h" +#include "Doc.h" +#include "UICDMStudioSystem.h" +#include "UICDMSlides.h" +#include "DropTarget.h" + +CDropTarget::CDropTarget() + : m_Instance(0) + , m_ObjectType(OBJTYPE_UNKNOWN) +{ +} + +bool CDropTarget::CanAddToMaster() +{ + long theTargetObjectType = GetObjectType(); + if (theTargetObjectType == OBJTYPE_SCENE || theTargetObjectType == OBJTYPE_COMPONENT) + return true; + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + UICDM::ISlideSystem *theSlideSystem = theDoc->GetStudioSystem()->GetSlideSystem(); + UICDM::CUICDMSlideHandle theTargetSlide = theSlideSystem->GetAssociatedSlide(GetInstance()); + return theTargetSlide && theSlideSystem->IsMasterSlide(theTargetSlide); +} diff --git a/src/Authoring/Studio/DragAndDrop/DropTarget.h b/src/Authoring/Studio/DragAndDrop/DropTarget.h new file mode 100644 index 00000000..7bbec133 --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/DropTarget.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2003 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_DROPTARGET +#define INCLUDED_DROPTARGET + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "StudioObjectTypes.h" +#include "UICDMHandles.h" + +class CDropSource; +class CStudioApp; + +class CDropTarget +{ +protected: + UICDM::CUICDMInstanceHandle m_Instance; + long m_ObjectType; + +public: + CDropTarget(); + virtual ~CDropTarget() {} + + virtual bool Accept(CDropSource &inSource) = 0; + virtual bool Drop(CDropSource &inSource) = 0; + virtual long GetObjectType() = 0; + + virtual void SetInstance(UICDM::CUICDMInstanceHandle inInstance) { m_Instance = inInstance; } + virtual UICDM::CUICDMInstanceHandle GetInstance() { return m_Instance; } + + virtual bool IsRelative(UICDM::CUICDMInstanceHandle) { return false; } + virtual bool IsSelf(UICDM::CUICDMInstanceHandle) { return false; } + virtual bool IsMaster() { return false; } + virtual bool CanAddToMaster(); +}; + +#endif \ No newline at end of file diff --git a/src/Authoring/Studio/DragAndDrop/ExplorerFileDropSource.cpp b/src/Authoring/Studio/DragAndDrop/ExplorerFileDropSource.cpp new file mode 100644 index 00000000..f32cbe9b --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/ExplorerFileDropSource.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** 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 +//============================================================================== + +//============================================================================== +// Includes +//============================================================================== +#include "stdafx.h" +#include "qtAuthoring-config.h" +#include "ExplorerFileDropSource.h" +#include "Dialogs.h" +#include "DropTarget.h" +#include "StudioObjectTypes.h" +#include "IDragable.h" +#include "UICFileTools.h" +#include "ImportUtils.h" + +bool CExplorerFileDropSource::s_FileHasValidTarget = false; + +//=============================================================================== +/** + * + */ +bool CExplorerFileDropSource::ValidateTarget(CDropTarget *inTarget) +{ + // Check the type is valid and if target can accept + bool theValidTarget = + ((m_ObjectType != OBJTYPE_UNKNOWN) && (inTarget->GetObjectType() == EUIC_FLAVOR_FILE)); + SetHasValidTarget(theValidTarget); + + return theValidTarget; +} + +//=============================================================================== +/** + * + */ +CExplorerFileDropSource::CExplorerFileDropSource(long inFlavor, void *inData, unsigned long inSize) + : CDropSource(inFlavor, inSize) + , m_File("") +{ + // Pull out all of the SDropItemData and build a file. + m_File = *(CUICFile *)inData; + Q3DStudio::CFilePath thePath(m_File.GetAbsolutePath()); + m_ObjectType = Q3DStudio::ImportUtils::GetObjectFileTypeForFile(thePath).m_IconType; + // Fix because DAE files are the *only* thing you can drop onto the project + if (thePath.GetExtension().Compare(CDialogs::GetWideDAEFileExtension(), + Q3DStudio::CString::ENDOFSTRING, false)) { + m_ObjectType = OBJTYPE_GROUP; + } +#ifdef QT_3DSTUDIO_FBX + else if (thePath.GetExtension().Compare(CDialogs::GetWideFbxFileExtension(), + Q3DStudio::CString::ENDOFSTRING, false)) { + m_ObjectType = OBJTYPE_GROUP; + } +#endif +} + +//=============================================================================== +/** + * + */ +void CExplorerFileDropSource::SetHasValidTarget(bool inValid) +{ + m_HasValidTarget = inValid; + CExplorerFileDropSource::s_FileHasValidTarget = inValid; +} + +//=============================================================================== +/** + * + */ +bool CExplorerFileDropSource::GetHasValidTarget() +{ + return CExplorerFileDropSource::s_FileHasValidTarget; +} + +//=============================================================================== +/** + * + */ +bool CExplorerFileDropSource::CanMove() +{ + return false; +} + +//=============================================================================== +/** + * + */ +bool CExplorerFileDropSource::CanCopy() +{ + return true; +} diff --git a/src/Authoring/Studio/DragAndDrop/ExplorerFileDropSource.h b/src/Authoring/Studio/DragAndDrop/ExplorerFileDropSource.h new file mode 100644 index 00000000..03269aaf --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/ExplorerFileDropSource.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** 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 __EXPLORERFILEDROPSOURCE_H__ +#define __EXPLORERFILEDROPSOURCE_H__ + +//============================================================================== +// Includes +//============================================================================== +#include "DropSource.h" +#include "UICFile.h" + +class CStudioApp; +class CDropTarget; + +//============================================================================== +/** + * @class CExplorerFileDropSource + * @brief Drop Source for EUIC_FLAVOR_UICFILE + * + * This class is meant to handle drag and drop for EUIC_FLAVOR_UICFILE, + * for example when user drags a file from Explorer Window (outside Studio). + */ +class CExplorerFileDropSource : public CDropSource +{ +protected: + CUICFile m_File; + static bool s_FileHasValidTarget; + +public: + CExplorerFileDropSource(long inFlavor, void *inData, unsigned long inSize); + + bool CanMove() override; + bool CanCopy() override; + bool ValidateTarget(CDropTarget *inTarget) override; + bool GetHasValidTarget(); + void SetHasValidTarget(bool inValid) override; + CUICFile GetFile() const { return m_File; } +}; + +#endif // #ifndef __EXPLORERFILEDROPSOURCE_H__ diff --git a/src/Authoring/Studio/DragAndDrop/FileDropSource.cpp b/src/Authoring/Studio/DragAndDrop/FileDropSource.cpp new file mode 100644 index 00000000..a4164e02 --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/FileDropSource.cpp @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** 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 +//============================================================================== + +//============================================================================== +// Includes +//============================================================================== +#include "stdafx.h" +#include "Dialogs.h" +#include "FileDropSource.h" +#include "DropTarget.h" +#include "StudioObjectTypes.h" +#include "HotKeys.h" +#include "Doc.h" +#include "StudioApp.h" +#include "Core.h" +#include "UICDMStudioSystem.h" +#include "ClientDataModelBridge.h" +#include "IDocumentEditor.h" +#include "UICFileTools.h" +#include "ImportUtils.h" + +bool CFileDropSource::s_FileHasValidTarget = false; + +//=============================================================================== +/** + * + */ +bool CFileDropSource::ValidateTarget(CDropTarget *inTarget) +{ + using namespace Q3DStudio; + + EStudioObjectType targetType = (EStudioObjectType)inTarget->GetObjectType(); + bool theValidTarget = false; + + // the only thing we want to do from here is check the type. + theValidTarget = CStudioObjectTypes::AcceptableParent( + (EStudioObjectType)m_ObjectType, (EStudioObjectType)inTarget->GetObjectType()); + + if (!theValidTarget) { + SetHasValidTarget(theValidTarget); + return theValidTarget; + } else { + if (CHotKeys::IsKeyDown(Qt::AltModifier) && targetType != OBJTYPE_SCENE + && targetType != OBJTYPE_COMPONENT) { + UICDM::CUICDMInstanceHandle theTarget = inTarget->GetInstance(); + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + IDocumentReader &theReader(theDoc->GetDocumentReader()); + UICDM::CUICDMSlideHandle toSlide = theReader.GetAssociatedSlide(theTarget); + ; + + if (!theReader.IsMasterSlide(toSlide)) + theValidTarget = false; + } + + SetHasValidTarget(theValidTarget); + return theValidTarget; + } +} + +//=============================================================================== +/** + * + */ +CFileDropSource::CFileDropSource(long inFlavor, void *inData, unsigned long inSize) + : CDropSource(inFlavor, inSize) + , m_File("") +{ + // Pull out all of the SDropItemData and build a file. + m_File = *(CUICFile *)inData; + m_ObjectType = + Q3DStudio::ImportUtils::GetObjectFileTypeForFile(m_File.GetAbsolutePath()).m_ObjectType; +} + +//=============================================================================== +/** + * + */ +void CFileDropSource::SetHasValidTarget(bool inValid) +{ + m_HasValidTarget = inValid; + CFileDropSource::s_FileHasValidTarget = inValid; +} + +//=============================================================================== +/** + * + */ +bool CFileDropSource::GetHasValidTarget() +{ + return CFileDropSource::s_FileHasValidTarget; +} + +//=============================================================================== +/** + * + */ +bool CFileDropSource::CanMove() +{ + return false; +} + +//=============================================================================== +/** + * + */ +bool CFileDropSource::CanCopy() +{ + return true; +} + +CCmd *CFileDropSource::GenerateAssetCommand(UICDM::CUICDMInstanceHandle inTarget, + EDROPDESTINATION inDestType, + UICDM::CUICDMSlideHandle inSlide) +{ + UICDM::CUICDMInstanceHandle theTarget = inTarget; + + CDoc &theDoc(*g_StudioApp.GetCore()->GetDoc()); + Q3DStudio::CFilePath theFilePath(m_File.GetAbsolutePath()); + CPt thePoint; + // if ( CHotKeys::IsKeyDown( Qt::AltModifier ) ) + // thePoint = GetCurrentPoint(); + + long theStartTime = -1; + if (CHotKeys::IsKeyDown(Qt::ControlModifier)) + theStartTime = theDoc.GetCurrentViewTime(); + + if (theFilePath.IsFile()) { + Q3DStudio::DocumentEditorFileType::Enum theDocType( + Q3DStudio::ImportUtils::GetObjectFileTypeForFile(theFilePath).m_FileType); + QString theCommandName; + // TODO: internationalize + switch (theDocType) { + case Q3DStudio::DocumentEditorFileType::DAE: + theCommandName = QObject::tr("File Drop DAE File"); + break; + case Q3DStudio::DocumentEditorFileType::Import: + theCommandName = QObject::tr("File Drop Import File"); + break; + case Q3DStudio::DocumentEditorFileType::Image: + theCommandName = QObject::tr("File Drop Image File"); + break; + case Q3DStudio::DocumentEditorFileType::Behavior: + theCommandName = QObject::tr("File Drop Behavior File"); + break; + case Q3DStudio::DocumentEditorFileType::Mesh: + theCommandName = QObject::tr("File Drop Mesh File"); + break; + case Q3DStudio::DocumentEditorFileType::Font: + theCommandName = QObject::tr("File Drop Font File"); + break; + case Q3DStudio::DocumentEditorFileType::Effect: + theCommandName = QObject::tr("File Drop Effect File"); + break; + case Q3DStudio::DocumentEditorFileType::Material: + theCommandName = QObject::tr("File Drop Material File"); + break; + case Q3DStudio::DocumentEditorFileType::Path: + theCommandName = QObject::tr("File Drop Path File"); + break; + } + + Q3DStudio::SCOPED_DOCUMENT_EDITOR(theDoc, theCommandName) + ->ImportFile(theDocType, theFilePath, theTarget, inSlide, + CDialogs::GetImportFileExtension(), + Q3DStudio::ImportUtils::GetInsertTypeForDropType(inDestType), thePoint, + theStartTime); + } + return nullptr; +} diff --git a/src/Authoring/Studio/DragAndDrop/FileDropSource.h b/src/Authoring/Studio/DragAndDrop/FileDropSource.h new file mode 100644 index 00000000..57127b0d --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/FileDropSource.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 __FILEDROPSOURCE_H__ +#define __FILEDROPSOURCE_H__ + +//============================================================================== +// Includes +//============================================================================== +// This should go into its own FileDropSourceFile. +#include "DropSource.h" +#include "UICFile.h" + +class CStudioApp; +class CDropTarget; + +//============================================================================== +/** + * @class CFileDropSource + * @brief Drop Source for EUIC_FLAVOR_ASSET_UICFILE + * + * This class is meant to handle drag and drop for EUIC_FLAVOR_ASSET_UICFILE, + * for example when user drags a file from within Studio. + */ +class CFileDropSource : public CDropSource +{ +protected: + CUICFile m_File; + static bool s_FileHasValidTarget; + +public: + CFileDropSource(long inFlavor, void *inData, unsigned long inSize); + + bool CanMove() override; + bool CanCopy() override; + bool ValidateTarget(CDropTarget *inTarget) override; + bool GetHasValidTarget(); + void SetHasValidTarget(bool inValid) override; + + CCmd *GenerateAssetCommand(UICDM::CUICDMInstanceHandle inTarget, + EDROPDESTINATION inDestType, + UICDM::CUICDMSlideHandle inSlide) override; +}; + +#endif // #ifndef __FILEDROPSOURCE_H__ diff --git a/src/Authoring/Studio/DragAndDrop/ListBoxDropSource.cpp b/src/Authoring/Studio/DragAndDrop/ListBoxDropSource.cpp new file mode 100644 index 00000000..da602679 --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/ListBoxDropSource.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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 "ListBoxDropSource.h" +#include "DropTarget.h" +#include "ListBoxItem.h" +#include "IDragable.h" + +//=============================================================================== +/** + * Constructor + */ +CListBoxDropSource::CListBoxDropSource(long inFlavor, IDragable *inDragable) + : CDropSource(inFlavor, 0) +{ + m_Item = reinterpret_cast(inDragable); +} + +//=============================================================================== +/** + * Validate that the drop target is EUIC_FLAVOR_LISTBOX type. + * @param inTarget Drop target for validation + * @return true if inTarget is EUIC_FLAVOR_LISTBOX; false if otherwise + */ +bool CListBoxDropSource::ValidateTarget(CDropTarget *inTarget) +{ + bool theValidTarget = (inTarget->GetObjectType() == EUIC_FLAVOR_LISTBOX); + SetHasValidTarget(theValidTarget); + + return theValidTarget; +} + +//=============================================================================== +/** + * @return true + */ +bool CListBoxDropSource::CanMove() +{ + return true; +} + +//=============================================================================== +/** + * @return true + */ +bool CListBoxDropSource::CanCopy() +{ + return true; +} \ No newline at end of file diff --git a/src/Authoring/Studio/DragAndDrop/ListBoxDropSource.h b/src/Authoring/Studio/DragAndDrop/ListBoxDropSource.h new file mode 100644 index 00000000..a28678d4 --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/ListBoxDropSource.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** 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 __ListBoxDropSource_H__ +#define __ListBoxDropSource_H__ + +//============================================================================== +// Includes +//============================================================================== +#include "DropSource.h" + +class CStudioApp; +class CDropTarget; +class CListBoxItem; + +class CListBoxDropSource : public CDropSource +{ +protected: + CListBoxItem *m_Item; + +public: + CListBoxDropSource(long inFlavor, IDragable *inDragable); + + bool CanMove() override; + bool CanCopy() override; + bool ValidateTarget(CDropTarget *inTarget) override; + + CListBoxItem *GetItem() { return m_Item; } +}; + +#endif // #ifndef __ListBoxDropSource_H__ diff --git a/src/Authoring/Studio/DragAndDrop/ListBoxDropTarget.cpp b/src/Authoring/Studio/DragAndDrop/ListBoxDropTarget.cpp new file mode 100644 index 00000000..752cc430 --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/ListBoxDropTarget.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** 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 "ListBoxDropTarget.h" +#include "ListBoxDropSource.h" +#include "IDragable.h" + +//=============================================================================== +/** + * Constructor + */ +CListBoxDropTarget::CListBoxDropTarget() + : m_Item(nullptr) +{ +} + +//=============================================================================== +/** + * This get called on every DragWithin. + * Note: the source will validate the target instead of the otherway around. + * This is because the DropSource knows how to get information from itself without + * creating an asset. This is mainly for DropSources that have a lazy creation idiom. + * like files. + * @param the DropSource in question. + * @return true if the DropSource likes the DropTarget. + */ +bool CListBoxDropTarget::Accept(CDropSource &inSource) +{ + return inSource.ValidateTarget(this); +} + +//=============================================================================== +/** + * This is where is actually happens. + * Note: At this point everything should be verified, and setup in the dropsource. + * The only thing left to do is to get the Assets and move/copy or connect them. + * @param inSource the Object in question. + * @return true if the drop was successful . + */ +bool CListBoxDropTarget::Drop(CDropSource &inSource) +{ + if (m_Item) { + inSource; + /* + CSlideDropSource* theSlideDropSource = static_cast< CSlideDropSource* >( + &inSource ); + CSlideControl* theSlideControl = theSlideDropSource->GetSlide( ); + CTimeContext* theTimeContext = theSlideControl->GetTimeContext( ); + + // Reorder this slide to the position held by this drop target. + CCmdRearrangeTimeContext* theCommand = new CCmdRearrangeTimeContext( theTimeContext, + m_SlideInsert->GetInsertIndex( ) ); + if ( theCommand ) + { + theTimeContext->GetAsset( )->ExecuteCommand( theCommand, false ); + } + */ + } + + // we are always successful + return true; +} + +//=============================================================================== +/** + * This will get the objec ttype from the Asset. + * Note: The asset can change all of the time, so i always ask the asset for its type. + * @return the Studio object type. + */ +long CListBoxDropTarget::GetObjectType() +{ + return EUIC_FLAVOR_LISTBOX; +} + +//=============================================================================== +/** + * Set the SlideInsertionControl that is the drop target + */ +void CListBoxDropTarget::SetItem(CListBoxItem *inItem) +{ + m_Item = inItem; +} \ No newline at end of file diff --git a/src/Authoring/Studio/DragAndDrop/ListBoxDropTarget.h b/src/Authoring/Studio/DragAndDrop/ListBoxDropTarget.h new file mode 100644 index 00000000..44199092 --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/ListBoxDropTarget.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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 __ListBoxDropTarget_H__ +#define __ListBoxDropTarget_H__ + +//============================================================================== +// Includes +//============================================================================== +#include "DropTarget.h" + +class CDropSource; +class CListBoxItem; + +//============================================================================== +/** + * @class + * @brief justin.ebert needs to enter a brief description here. + * + * justin.ebert needs to enter a long description here. + */ +class CListBoxDropTarget : public CDropTarget +{ +protected: + CListBoxItem *m_Item; ///< The list item that we can drop on + +public: + CListBoxDropTarget(); + bool Accept(CDropSource &inSource) override; + bool Drop(CDropSource &inSource) override; + long GetObjectType() override; + + void SetItem(CListBoxItem *inItem); +}; + +#endif // #ifndef __ListBoxDropTarget_H__ diff --git a/src/Authoring/Studio/DragAndDrop/ProjectDropTarget.cpp b/src/Authoring/Studio/DragAndDrop/ProjectDropTarget.cpp new file mode 100644 index 00000000..5344d459 --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/ProjectDropTarget.cpp @@ -0,0 +1,229 @@ +/**************************************************************************** +** +** 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 "qtAuthoring-config.h" +#include "ProjectDropTarget.h" +#include "DropSource.h" +#include "ExplorerFileDropSource.h" +#include "IDragable.h" +#include "StudioApp.h" +#include "Core.h" +#include "Dialogs.h" +#include "Doc.h" +#include "UICFile.h" +#include "UICFileTools.h" +#include "UICImportPerformImport.h" +#include "UICImportTranslation.h" +#include "IDocumentEditor.h" +#include "PathImportTranslator.h" + +//=============================================================================== +/** + * Constructor + */ +CProjectDropTarget::CProjectDropTarget(const Q3DStudio::CFilePath &inTargetDir) + : m_TargetDir(inTargetDir) +{ +} + +//=============================================================================== +/** + * This get called on every DragWithin. + * Note: the source will validate the target instead of the otherway around. + * This is because the DropSource knows how to get information from itself without + * creating an asset. This is mainly for DropSources that have a lazy creation idiom. + * like files. + * @param the DropSource in question. + * @return true if the DropSource likes the DropTarget. + */ +bool CProjectDropTarget::Accept(CDropSource &inSource) +{ + return inSource.ValidateTarget(this); +} + +//=============================================================================== +/** + * This is where is actually happens. + * Note: At this point everything should be verified, and setup in the dropsource. + * The only thing left to do is to get the Assets and move/copy or connect them. + * @param inSource the Object in question. + * @return true if the drop was successful . + */ +bool CProjectDropTarget::Drop(CDropSource &inSource) +{ + 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 (inSource.GetFlavor() == EUIC_FLAVOR_FILE) { + // Create target directory if it doesn't exist + if (!m_TargetDir.Exists()) + m_TargetDir.CreateDir(true); + // also make sure that target directory is a directory, not a file + else if (m_TargetDir.IsFile()) + m_TargetDir = m_TargetDir.GetDirectory(); + + // Sanity check + ASSERT(m_TargetDir.IsDirectory()); + + // Get the Source file to be copied + CExplorerFileDropSource *theFileDropSource = + static_cast(&inSource); + CFilePath theSourceFile(theFileDropSource->GetFile().GetAbsolutePath()); + + if (theSourceFile.IsFile() && m_TargetDir.IsDirectory()) { + // Get the file extension + Q3DStudio::CString theExtension(theSourceFile.GetExtension()); + + Q3DStudio::CString theFileStem = theSourceFile.GetFileStem(); + Q3DStudio::CString outputFileName(theFileStem + L"." + + CDialogs::GetImportFileExtension()); + + if (theExtension.Compare(CDialogs::GetWideDAEFileExtension(), + Q3DStudio::CString::ENDOFSTRING, false)) { + SColladaTranslator theTranslator(theSourceFile.toQString()); + + CFilePath theOutputDir = + SFileTools::FindUniqueDestDirectory(m_TargetDir, theFileStem); + CFilePath theFullOutputFile( + CFilePath::CombineBaseAndRelative(theOutputDir, outputFileName)); + SImportResult theImportResult = + CPerformImport::TranslateToImportFile(theTranslator, theFullOutputFile); + bool forceError = theFullOutputFile.IsFile() == false; + IDocumentEditor::DisplayImportErrors( + theSourceFile.toQString(), theImportResult.m_Error, + g_StudioApp.GetCore()->GetDoc()->GetImportFailedHandler(), + theTranslator.m_TranslationLog, forceError); +#ifdef QT_3DSTUDIO_FBX + } else if (theExtension.Compare(CDialogs::GetWideFbxFileExtension(), + Q3DStudio::CString::ENDOFSTRING, false)) { + SFbxTranslator theTranslator(theSourceFile.toQString()); + + CFilePath theOutputDir = + SFileTools::FindUniqueDestDirectory(m_TargetDir, theFileStem); + CFilePath theFullOutputFile( + CFilePath::CombineBaseAndRelative(theOutputDir, outputFileName)); + SImportResult theImportResult = + CPerformImport::TranslateToImportFile(theTranslator, theFullOutputFile); + bool forceError = theFullOutputFile.IsFile() == false; + IDocumentEditor::DisplayImportErrors( + theSourceFile.toQString(), theImportResult.m_Error, + g_StudioApp.GetCore()->GetDoc()->GetImportFailedHandler(), + theTranslator.m_TranslationLog, forceError); +#endif + } else if (theExtension.Compare(L"svg", Q3DStudio::CString::ENDOFSTRING, false)) { + IDocumentReader &theReader(g_StudioApp.GetCore()->GetDoc()->GetDocumentReader()); + SPathImportTranslator theTranslator(theSourceFile.toQString(), *theReader.GetLuaContext(), + theReader.GetFoundation()); + CFilePath theOutputDir = + SFileTools::FindUniqueDestDirectory(m_TargetDir, theFileStem); + CFilePath theFullOutputFile( + CFilePath::CombineBaseAndRelative(theOutputDir, outputFileName)); + SImportResult theImportResult = + CPerformImport::TranslateToImportFile(theTranslator, theFullOutputFile); + bool forceError = theFullOutputFile.IsFile() == false; + IDocumentEditor::DisplayImportErrors( + theSourceFile.toQString(), theImportResult.m_Error, + g_StudioApp.GetCore()->GetDoc()->GetImportFailedHandler(), + theTranslator.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. + SFileErrorCodeFileNameAndNumBytes theCopyResult = SFileTools::FindAndCopyDestFile( + m_TargetDir, CFilePath::GetAbsolutePath(theSourceFile)); + + // Sanity check + ASSERT(theCopyResult.m_Error == Q3DStudio::FileErrorCodes::NoError); + ASSERT(theCopyResult.m_DestFilename.Exists()); + + // For effect and custom material files, automatically copy related resources + if (CDialogs::IsEffectFileExtension(theExtension) + || CDialogs::IsMaterialFileExtension(theExtension)) { + std::shared_ptr theHandler( + g_StudioApp.GetCore()->GetDoc()->GetImportFailedHandler()); + CFilePath theShaderFile(theSourceFile); + + if (theShaderFile.GetExtension() != "effect" + && theShaderFile.GetExtension() != "material") { + ASSERT(false); // what file is this? + } else { + } + + std::vector theEffectFileSourcePaths; + g_StudioApp.GetCore() + ->GetDoc() + ->GetDocumentReader() + .ParseSourcePathsOutOfEffectFile( + Q3DStudio::CFilePath::GetAbsolutePath(theSourceFile), + theEffectFileSourcePaths); + + CFilePath theFileDir( + Q3DStudio::CFilePath::GetAbsolutePath(theSourceFile).GetDirectory()); + CFilePath theDocumentDir( + g_StudioApp.GetCore()->GetDoc()->GetDocumentDirectory()); + for (size_t idx = 0; idx < theEffectFileSourcePaths.size(); ++idx) { + CFilePath theSourcePath = CFilePath::CombineBaseAndRelative( + theFileDir, theEffectFileSourcePaths[idx]); + CFilePath theResultPath = CFilePath::CombineBaseAndRelative( + theDocumentDir, theEffectFileSourcePaths[idx]); + CFilePath theResultDir(theResultPath.GetDirectory()); + theResultDir.CreateDir(true); + // If the file already exists, these file flags will ensure it won't get + // overwritten. + SFileTools::Copy(theResultPath, + qt3ds::foundation::FileOpenFlags( + qt3ds::foundation::FileOpenFlagValues::Create + | qt3ds::foundation::FileOpenFlagValues::Write), + theSourcePath); + } + } + } + } + } + + // we are always successful + return true; +} + +//=============================================================================== +/** + * This will get the objec ttype from the Asset. + * Note: The asset can change all of the time, so i always ask the asset for its type. + * @return the Studio object type. + */ +long CProjectDropTarget::GetObjectType() +{ + return EUIC_FLAVOR_FILE; +} diff --git a/src/Authoring/Studio/DragAndDrop/ProjectDropTarget.h b/src/Authoring/Studio/DragAndDrop/ProjectDropTarget.h new file mode 100644 index 00000000..234c30ed --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/ProjectDropTarget.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** 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 __PROJECTDROPTARGET_H__ +#define __PROJECTDROPTARGET_H__ + +//============================================================================== +// Includes +//============================================================================== +#include "DropTarget.h" +#include "UICFileTools.h" + +class CDropSource; + +//============================================================================== +/** + * @class CProjectDropTarget + * @brief Drop Target for Project Palette + */ +class CProjectDropTarget : public CDropTarget +{ +public: + CProjectDropTarget(const Q3DStudio::CFilePath &inTargetDir); + + bool Accept(CDropSource &inSource) override; + bool Drop(CDropSource &inSource) override; + long GetObjectType() override; + +protected: + Q3DStudio::CFilePath m_TargetDir; ///< The target directory to copy file to. +}; + +#endif // #ifndef __PROJECTDROPTARGET_H__ diff --git a/src/Authoring/Studio/DragAndDrop/SceneDropTarget.cpp b/src/Authoring/Studio/DragAndDrop/SceneDropTarget.cpp new file mode 100644 index 00000000..47850e80 --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/SceneDropTarget.cpp @@ -0,0 +1,242 @@ +/**************************************************************************** +** +** 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 "SceneDropTarget.h" +#include "DropTarget.h" +#include "DropSource.h" + +#include "StudioApp.h" +#include "Doc.h" + +#include "HotKeys.h" +#include "IDropTargetHelper.h" +#include "Core.h" +#include "GraphUtils.h" +#include "UICDMStudioSystem.h" +#include "ClientDataModelBridge.h" +#include "UICDMDataCore.h" +#include "UICDMSlides.h" + +// Sceneview stuff +//=============================================================================== +/** + * Constructor. + */ +CSceneViewDropTarget::CSceneViewDropTarget() + : m_DropTime(-1) +{ + m_ObjectType = OBJTYPE_LAYER; + m_DropSourceObjectType = OBJTYPE_UNKNOWN; +} + +//=============================================================================== +/** + * This will get the objec ttype from the Asset. + * Note: The asset can change all of the time, so i always ask the asset for its type. + * @return the Studio object type. + */ +long CSceneViewDropTarget::GetObjectType() +{ + UICDM::CUICDMInstanceHandle theInstance = GetInstance(); + + if (theInstance.Valid()) { + CClientDataModelBridge *theBridge = + g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetClientDataModelBridge(); + m_ObjectType = theBridge->GetObjectType(theInstance); + return m_ObjectType; + } + return OBJTYPE_UNKNOWN; +} + +//=============================================================================== +/** + * This get called on every DragWithin. + * Note: the source will validate the target instead of the otherway around. + * This is because the DropSource knows how to get information from itself without + * creating an asset. This is mainly for DropSources that have a lazy creation idiom. + * like files. + * Dropping into "locked" layers are not allowed. + * @param inSource the DropSource in question. + * @return true if the DropSource likes the DropTarget. + */ +bool CSceneViewDropTarget::Accept(CDropSource &inSource) +{ + CClientDataModelBridge *theBridge = + g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetClientDataModelBridge(); + + // We have to set this so we can adjust the Target to accept this source. + SetDropSourceObjectType(inSource.GetObjectType()); + + bool theAcceptable = false; + + // We don't want to generate an asset right now so let the DropSource ask us if it can drop. + theAcceptable = inSource.ValidateTarget(this); + + // The DropSource already generated the asset for this in the above. + if (theAcceptable && m_Instance.Valid()) { + theAcceptable = !theBridge->IsLockedAtAll(m_Instance); + } + + return theAcceptable; +} + +//=============================================================================== +/** + * This is so the questioned object type can be cached so we can get the correct asset. + * @param inObjType the object type of the Questioned object. + */ +void CSceneViewDropTarget::SetDropSourceObjectType(long inObjType) +{ + m_DropSourceObjectType = inObjType; +} + +//=============================================================================== +/** + * This is where is actually happens. + * Note: At this point either everything should be verified, and setup in the dropsource. + * Then the only thing left to do is to get the Assets and move/copy or connect them. + * Or the dropsource needs the target to perform the actual drop. + * Note that if the Control key is depressed, the start time follows the current view time( + *i.e. playhead position ) + * And if the Alt key (KEY_MENU) is depressed, the object is dropped at the mouse location. + * + * @param inSource the Object in question. + * @return true if the drop was successful . + */ +bool CSceneViewDropTarget::Drop(CDropSource &inSource) +{ + // The Parent is a tree control item, so iwe know it can be converted to an Asset. + + // We have to set this so we can adjust the Target to accept this source. + SetDropSourceObjectType(inSource.GetObjectType()); + + UICDM::CUICDMInstanceHandle theTargetInstance = GetInstance(); + if (theTargetInstance.Valid()) { + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + UICDM::ISlideSystem *theSlideSystem = theDoc->GetStudioSystem()->GetSlideSystem(); + UICDM::CUICDMSlideHandle theSlide = theDoc->GetActiveSlide(); + if (!theSlideSystem->IsMasterSlide(theSlide) + && (inSource.GetCurrentFlags() & CHotKeys::MODIFIER_ALT)) { + if (CanAddToMaster()) { + UICDM::CUICDMSlideHandle theMasterSlideHandle = + theSlideSystem->GetMasterSlide(theSlide); + if (theMasterSlideHandle.Valid()) + theSlide = theMasterSlideHandle; + } + } + CCmd *command = + inSource.GenerateAssetCommand(theTargetInstance, EDROPDESTINATION_ON, theSlide); + if (command != nullptr) + theDoc->GetCore()->ExecuteCommand(command); + } + + return true; +} + +//=============================================================================== +/** + * @return the Asset that we would like the DropSource to drop on to. + */ +UICDM::CUICDMInstanceHandle CSceneViewDropTarget::GetInstance() +{ + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + UICDM::CUICDMInstanceHandle theRootObject = theDoc->GetActiveRootInstance(); + EStudioObjectType theRootObjType = + theDoc->GetStudioSystem()->GetClientDataModelBridge()->GetObjectType(theRootObject); + + // Check if the inObjectType can just go ahead and drop onto the Root object. + if (CStudioObjectTypes::AcceptableParent((EStudioObjectType)m_DropSourceObjectType, + theRootObjType)) { + m_Instance = theRootObject; + } else if (theRootObject == theDoc->GetSceneInstance() + && CStudioObjectTypes::AcceptableParent((EStudioObjectType)m_DropSourceObjectType, + OBJTYPE_LAYER)) { + m_Instance = theDoc->GetActiveLayer(); + } + + return m_Instance; +} + +//=============================================================================== +/** + * Check to see if the Asset is a relative of our asset. + * @return true if the inAsset is a parent grandparent...etc. of this asset. + */ +bool CSceneViewDropTarget::IsRelative(UICDM::CUICDMInstanceHandle inInstance) +{ + bool theReturn = false; + + UICDM::CUICDMInstanceHandle theThisInstance = GetInstance(); + // This will check to see if the inAsset is already a parent, grandparent....etc. + if (theThisInstance.Valid()) + theReturn = IsAscendant(theThisInstance, inInstance, + g_StudioApp.GetCore()->GetDoc()->GetAssetGraph()); + return theReturn; +} + +//=============================================================================== +/** + * Check to see if the inAsset is our asset. + * @param inAsset The Asset to check. + * @return true if we are the same. + */ +bool CSceneViewDropTarget::IsSelf(UICDM::CUICDMInstanceHandle inInstance) +{ + UICDM::CUICDMInstanceHandle theThisInstance = GetInstance(); + return (theThisInstance == inInstance); +} + +//=============================================================================== +/** + * Set the Drop time for all sources. + * @param inDropTime The time to drop the source. + */ +void CSceneViewDropTarget::SetDropTime(long inDropTime) +{ + m_DropTime = inDropTime; +} + +//=============================================================================== +/** + * @return The time that all sources will be droped. + */ +long CSceneViewDropTarget::GetDropTime() +{ + return m_DropTime; +} + +// Last Sceneview related stuff. diff --git a/src/Authoring/Studio/DragAndDrop/SceneDropTarget.h b/src/Authoring/Studio/DragAndDrop/SceneDropTarget.h new file mode 100644 index 00000000..cdcb7afc --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/SceneDropTarget.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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef __SCENEDROPTARGET_H__ +#define __SCENEDROPTARGET_H__ + +//============================================================================== +// Includes +//============================================================================== +#include "DropTarget.h" + +//============================================================================== +/** + * @class + * @brief LEONARD.PONCE needs to enter a brief description here. + * + * LEONARD.PONCE needs to enter a long description here. + */ +class CSceneViewDropTarget : public CDropTarget +{ +protected: + long m_DropTime; ///< The Time to drop any thing. + long m_DropSourceObjectType; + +public: + CSceneViewDropTarget(); + bool Accept(CDropSource &inSource) override; + bool Drop(CDropSource &inSource) override; + UICDM::CUICDMInstanceHandle GetInstance() override; + + bool IsRelative(UICDM::CUICDMInstanceHandle inInstance) override; + bool IsSelf(UICDM::CUICDMInstanceHandle inInstance) override; + long GetObjectType() override; + void SetDropSourceObjectType(long inObjType); + void SetDropTime(long inDropTime); + long GetDropTime(); +}; +#endif // #ifndef __SCENEDROPTARGET_H__ diff --git a/src/Authoring/Studio/DragAndDrop/TimelineDropSource.cpp b/src/Authoring/Studio/DragAndDrop/TimelineDropSource.cpp new file mode 100644 index 00000000..cf664825 --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/TimelineDropSource.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** 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 "TimelineDropSource.h" +#include "FileDropSource.h" +#include "Dispatch.h" +#include "DropTarget.h" +#include "StudioObjectTypes.h" +#include "HotKeys.h" +#include "Core.h" +#include "Doc.h" +#include "UICDMStudioSystem.h" +#include "ClientDataModelBridge.h" +#include "UICDMSlides.h" +#include "Bindings/UICDMTimelineItemBinding.h" +#include "IDocumentEditor.h" +#include "ImportUtils.h" + +#pragma warning(disable : 4100) + +using namespace Q3DStudio; + +//=============================================================================== +/** + * + */ +CTimeLineDropSource::CTimeLineDropSource(long inFlavor, IDragable *inDraggable) + : CDropSource(inFlavor, sizeof(inDraggable)) +{ + m_Copy = true; + + m_Instances = g_StudioApp.GetCore()->GetDoc()->GetSelectedValue().GetSelectedInstances(); + if (m_Instances.size()) + m_ObjectType = g_StudioApp.GetCore() + ->GetDoc() + ->GetStudioSystem() + ->GetClientDataModelBridge() + ->GetObjectType(m_Instances[0]); + else + m_ObjectType = OBJTYPE_UNKNOWN; +} + +//=============================================================================== +/** + * + */ +bool CTimeLineDropSource::CanMove() +{ + return !m_Copy; +} + +//=============================================================================== +/** + * + */ +bool CTimeLineDropSource::CanCopy() +{ + bool theReturn = false; + // This is here because some Assets can not be copied ( scene, material ) + theReturn = m_Copy && g_StudioApp.GetCore()->GetDoc()->CanCopyObject(m_Instances); + + return theReturn; +} + +//=============================================================================== +/** + * + */ +void CTimeLineDropSource::InterpretKeyFlags(long inModifyerKeys) +{ + m_Copy = ((inModifyerKeys & CHotKeys::MODIFIER_CONTROL) != 0); +} + +//=============================================================================== +/** + * + */ +bool CTimeLineDropSource::ValidateTarget(CDropTarget *inTarget) +{ + // the only thing we want to do from here is check the type. + bool theValidTarget = CStudioObjectTypes::AcceptableParent( + (EStudioObjectType)GetObjectType(), (EStudioObjectType)inTarget->GetObjectType()); + + for (size_t idx = 0, end = m_Instances.size(); idx < end && theValidTarget; ++idx) { + UICDM::CUICDMInstanceHandle theHandle(m_Instances[idx]); + + if (theValidTarget && theHandle.Valid()) { + theValidTarget &= (!inTarget->IsSelf(theHandle) && !inTarget->IsRelative(theHandle)); + UICDM::ISlideSystem *theSlideSystem = + g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetSlideSystem(); + UICDM::CUICDMSlideHandle theSlide = theSlideSystem->GetAssociatedSlide(theHandle); + bool theIsMaster = theSlideSystem->IsMasterSlide(theSlide); + + theValidTarget &= !(theIsMaster && !inTarget->IsMaster()); + } + } + + SetHasValidTarget(theValidTarget); + + return theValidTarget; +} + +using namespace UICDM; +using namespace Q3DStudio; + +inline void Rearrange(CDoc &inDoc, const UICDM::TInstanceHandleList &inInstances, + CUICDMInstanceHandle inTarget, DocumentEditorInsertType::Enum inInsertType) +{ + SCOPED_DOCUMENT_EDITOR(inDoc, QObject::tr("Rearrange Object")) + ->RearrangeObjects(inInstances, inTarget, inInsertType); +} + +CCmd *CTimeLineDropSource::GenerateAssetCommand(UICDM::CUICDMInstanceHandle inTarget, + EDROPDESTINATION inDestType, + UICDM::CUICDMSlideHandle inSlide) +{ + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + CClientDataModelBridge *theBridge = theDoc->GetStudioSystem()->GetClientDataModelBridge(); + + if (CanCopy()) { + SCOPED_DOCUMENT_EDITOR(*theDoc, QObject::tr("Duplicate Object")) + ->DuplicateInstances(m_Instances, inTarget, + ImportUtils::GetInsertTypeForDropType(inDestType)); + } else { + // We can't do the rearrange inline because it deletes a timeline item. + // So we will effectively postmessage and do it out of line. + theDoc->GetCore()->GetDispatch()->FireOnAsynchronousCommand( + std::bind(Rearrange, std::ref(*theDoc), m_Instances, inTarget, + ImportUtils::GetInsertTypeForDropType(inDestType))); + } + + return nullptr; +} diff --git a/src/Authoring/Studio/DragAndDrop/TimelineDropSource.h b/src/Authoring/Studio/DragAndDrop/TimelineDropSource.h new file mode 100644 index 00000000..3a385518 --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/TimelineDropSource.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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 __TIMELINEDROPSOURCE_H__ +#define __TIMELINEDROPSOURCE_H__ + +//============================================================================== +// Includes +//============================================================================== +#include "StudioApp.h" +#include "DropSource.h" + +//============================================================================== +// Forward +//============================================================================== +class CDropTarget; +class IDragable; + +class CTimeLineDropSource : public CDropSource +{ +protected: + bool m_Copy; + +public: + CTimeLineDropSource(long inFlavor, IDragable *inDraggable); + + bool CanMove() override; + bool CanCopy() override; + bool ValidateTarget(CDropTarget *inTarget) override; + void InterpretKeyFlags(long inModifyerKeys) override; + + CCmd *GenerateAssetCommand(UICDM::CUICDMInstanceHandle inTarget, + EDROPDESTINATION inDestType, + UICDM::CUICDMSlideHandle inSlide) override; +}; + +#endif // #ifndef __TIMELINEDROPSOURCE_H__ diff --git a/src/Authoring/Studio/DragAndDrop/TimelineDropTarget.cpp b/src/Authoring/Studio/DragAndDrop/TimelineDropTarget.cpp new file mode 100644 index 00000000..25a1352b --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/TimelineDropTarget.cpp @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** 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 +//============================================================================== + +//============================================================================== +// Includes +//============================================================================== +#include "stdafx.h" +#include "TimelineDropTarget.h" +#include "StudioApp.h" +#include "DropSource.h" +#include "HotKeys.h" +#include "Core.h" +#include "Doc.h" +#include "IDropTargetHelper.h" +#include "GraphUtils.h" +#include "UICDMStudioSystem.h" +#include "ClientDataModelBridge.h" +#include "UICDMSlides.h" + +// Timeline stuff + +//=============================================================================== +/** + * This get called on every DragWithin. + * Note: the source will validate the target instead of the otherway around. + * This is because the DropSource knows how to get information from itself without + * creating an asset. This is mainly for DropSources that have a lazy creation idiom. + * like files. + * @param the DropSource in question. + * @return true if the DropSource likes the DropTarget. + */ +bool CTimeLineDropTarget::Accept(CDropSource &inSource) +{ + bool theDropFlag = inSource.ValidateTarget(this); + return theDropFlag; +} + +//=============================================================================== +/** + * This is where is actually happens. + * Note: At this point either everything should be verified, and setup in the dropsource. + * Then the only thing left to do is to get the Assets and move/copy or connect them. + * Or the dropsource needs the target to perform the actual drop. + * Note that if the Control key is depressed, the start time follows the current view time( + *i.e. playhead position ) + * + * @param inSource the Object in question. + * @return true if the drop was successful . + */ +bool CTimeLineDropTarget::Drop(CDropSource &inSource) +{ + UICDM::CUICDMInstanceHandle theTargetInstance = GetInstance(); + + if (theTargetInstance.Valid()) { + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + UICDM::ISlideSystem *theSlideSystem = theDoc->GetStudioSystem()->GetSlideSystem(); + UICDM::CUICDMSlideHandle theSlide = theDoc->GetActiveSlide(); + if (!theSlideSystem->IsMasterSlide(theSlide) + && (inSource.GetCurrentFlags() & CHotKeys::MODIFIER_ALT)) { + if (CanAddToMaster()) { + UICDM::CUICDMSlideHandle theMasterSlideHandle = + theSlideSystem->GetMasterSlide(theSlide); + if (theMasterSlideHandle.Valid()) + theSlide = theMasterSlideHandle; + } + } + CCmd *theCmd = inSource.GenerateAssetCommand(theTargetInstance, m_Destination, theSlide); + if (theCmd) + g_StudioApp.GetCore()->ExecuteCommand(theCmd); + } + + return true; +} + +//=============================================================================== +/** + * This will get the objec ttype from the Asset. + * Note: The asset can change all of the time, so i always ask the asset for its type. + * @return the Studio object type. + */ +long CTimeLineDropTarget::GetObjectType() +{ + UICDM::CUICDMInstanceHandle theTargetInstance = GetTargetInstance(); + if (theTargetInstance.Valid()) { + CClientDataModelBridge *theBridge = + g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetClientDataModelBridge(); + return theBridge->GetObjectType(theTargetInstance); + } + + return m_ObjectType; +} + +//=============================================================================== +/** + * Check to see if the Asset is a relative of our asset. + * @return true if the inAsset is a parent grandparent...etc. of this asset. + */ +bool CTimeLineDropTarget::IsRelative(UICDM::CUICDMInstanceHandle inInstance) +{ + bool theReturn = false; ///< Default return value. + UICDM::CUICDMInstanceHandle theThisInstance = GetInstance(); + + // This will check to see if the inAsset is already some sort of parent grandparent....etc. + if (theThisInstance.Valid()) + theReturn = IsAscendant(theThisInstance, inInstance, + g_StudioApp.GetCore()->GetDoc()->GetAssetGraph()); + + return theReturn; +} + +//=============================================================================== +/** + * Check to see if the inAsset is our asset. + * @param inAsset The Asset to check. + * @return true if we are the same. + */ +bool CTimeLineDropTarget::IsSelf(UICDM::CUICDMInstanceHandle inInstance) +{ + UICDM::CUICDMInstanceHandle theThisInstance = GetInstance(); + // true if self..... + return (theThisInstance == inInstance); +} + +//=============================================================================== +/** + * This method is used to detirmine validity for dropping on Master items. + * We do not allow Master items to be dropped on non-master targets because + * it does not make any hierarchical sense. Also checks for NULL and Scene object. + * (The scene object reports as a master object so that we can re-arrange layers (On the master + *slide).) + * Changed checking for scene to checking for root object, which may be a component. This + * would allow for the root component (as in edit component) to re-arrange its children, even if + *either + * party is not a master. + * @param inAsset The Asset to check. + * @return true if we are the same. + */ +bool CTimeLineDropTarget::IsMaster() +{ + if (!m_Instance.Valid()) + return true; + else if (m_Instance == g_StudioApp.GetCore()->GetDoc()->GetActiveRootInstance()) + return true; + else { + UICDM::ISlideSystem *theSlideSystem = + g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetSlideSystem(); + UICDM::CUICDMSlideHandle theSlide = theSlideSystem->GetAssociatedSlide(m_Instance); + return theSlideSystem->IsMasterSlide(theSlide); + } +} + +void CTimeLineDropTarget::SetDestination(EDROPDESTINATION inDestination) +{ + m_Destination = inDestination; +} + +EDROPDESTINATION CTimeLineDropTarget::GetDestination() const +{ + return m_Destination; +} + +//=============================================================================== +/** + * Figure out the destination (parent) asset that the drop is to occur. + * In the case that the drop occurs ON this asset, then the to-be-dropped asset becomes a child + *of m_Asset + * Otherwise, this m_Asset ends up being a sibling + */ +UICDM::CUICDMInstanceHandle CTimeLineDropTarget::GetTargetInstance() +{ + UICDM::CUICDMInstanceHandle theInstance = GetInstance(); + if (!theInstance.Valid()) + return 0; + + CClientDataModelBridge *theBridge = + g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetClientDataModelBridge(); + bool theIsActiveComponent = false; + bool theIsComponent = (theBridge->GetObjectType(theInstance) == OBJTYPE_COMPONENT); + if (theIsComponent) + theIsActiveComponent = theBridge->IsActiveComponent(theInstance); + + // If the drop destination is ON, it will be valid if this is not a component or it's in the + // component timeline + if (m_Destination == EDROPDESTINATION_ON) { + if (!theIsComponent || theIsActiveComponent) + return theInstance; + else + return 0; + } + + // if target is a component, and we want to insert it above/below, and we are viewing this + // component, then it's an invalid operation + // thus set the target to 0. + if (theIsActiveComponent) + return 0; + + return theBridge->GetParentInstance(theInstance); +} + +// LASTTIMELINE RELATED CODE \ No newline at end of file diff --git a/src/Authoring/Studio/DragAndDrop/TimelineDropTarget.h b/src/Authoring/Studio/DragAndDrop/TimelineDropTarget.h new file mode 100644 index 00000000..29133afd --- /dev/null +++ b/src/Authoring/Studio/DragAndDrop/TimelineDropTarget.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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 __TIMELINEDROPTARGET_H__ +#define __TIMELINEDROPTARGET_H__ + +//============================================================================== +// Includes +//============================================================================== +#include "DropTarget.h" +#include "DropSource.h" + +class CControl; +class CDropSource; + +//============================================================================== +/** + * @class + * @brief LEONARD.PONCE needs to enter a brief description here. + * + * LEONARD.PONCE needs to enter a long description here. + */ +class CTimeLineDropTarget : public CDropTarget +{ + +public: + CTimeLineDropTarget() + : m_Destination(EDROPDESTINATION_ON) + , m_InsertionMarkedRow(nullptr) + , m_InsertionMarkedIndent(0) + { + } + bool Accept(CDropSource &inSource) override; + bool Drop(CDropSource &inSource) override; + long GetObjectType() override; + + bool IsRelative(UICDM::CUICDMInstanceHandle inInstance) override; + bool IsSelf(UICDM::CUICDMInstanceHandle inInstance) override; + bool IsMaster() override; + + void SetDestination(EDROPDESTINATION inDestination); + EDROPDESTINATION GetDestination() const; + + // Return info where the insertion markers is supposed to be drawn at. + CControl *GetInsertionMarkerRow() const { return m_InsertionMarkedRow; } + void SetInsertionMarkerRow(CControl *inControl) { m_InsertionMarkedRow = inControl; } + long GetInsertionMarkerIndent() const { return m_InsertionMarkedIndent; } + void SetInsertionMarkerIndent(long inIndent) { m_InsertionMarkedIndent = inIndent; } + +protected: + UICDM::CUICDMInstanceHandle GetTargetInstance(); + +protected: + EDROPDESTINATION m_Destination; + CControl *m_InsertionMarkedRow; + long m_InsertionMarkedIndent; +}; + +#endif // #ifndef __TIMELINEDROPTARGET_H__ diff --git a/src/Authoring/Studio/English.lproj/Strings/Static.stri b/src/Authoring/Studio/English.lproj/Strings/Static.stri new file mode 100644 index 00000000..d65e7fa7 Binary files /dev/null and b/src/Authoring/Studio/English.lproj/Strings/Static.stri differ diff --git a/src/Authoring/Studio/English.lproj/Strings/Static.stro b/src/Authoring/Studio/English.lproj/Strings/Static.stro new file mode 100644 index 00000000..0b3577f6 Binary files /dev/null and b/src/Authoring/Studio/English.lproj/Strings/Static.stro differ diff --git a/src/Authoring/Studio/English.lproj/Strings/Strings.h b/src/Authoring/Studio/English.lproj/Strings/Strings.h new file mode 100644 index 00000000..ef70db6e --- /dev/null +++ b/src/Authoring/Studio/English.lproj/Strings/Strings.h @@ -0,0 +1,301 @@ + +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//=============================================================================================================================== +// CODEGEN -- FILE CREATED BY STUDIO CODE GENERATION SYSTEM +// +// Do not modify the contents of this file. Your changes will be destroyed by +// code generation. +// +// Please see the CodeGen folder for more information or to make changes. +// StringsReadme.htm +//=============================================================================================================================== +//{{AFX_INSERT_LOCATION}} + +#ifndef STUDIOSTRINGSH +#define STUDIOSTRINGSH + +#define STRING_RESOURCE_COUNT 254 +#define IDS_PREFS_PRESENTATIONWIDTH 1 +#define IDS_PREFS_PRESENTATIONHEIGHT 2 +#define IDS_PREFS_PRESENTATIONASPECTRATIO 3 +#define IDS_PREFS_AUTHORNAME 4 +#define IDS_PREFS_COMPANYNAME 5 +#define IDS_PREFS_NUDGEAMOUNT 6 +#define IDS_PREFS_SNAPRANGE 7 +#define IDS_PREFS_INTERPOLATIONDEFAULT 8 +#define IDS_PREFS_TIMELINEGRIDSNAPPING 9 +#define IDS_PREFS_TIMELINEGRIDRESOLUTION 10 +#define IDS_PREFS_RESTOREDEFAULTS 11 +#define IDS_PREFS_REFERENCECONTROLS 12 +#define IDS_WEBSITELINK 13 +#define IDS_SUPPORTEMAIL_TEXT 14 +#define IDS_SUPPORTEMAIL 15 +#define IDS_PALETTE_TIMELINE 16 +#define IDS_PALETTE_INSPECTOR 17 +#define IDS_PALETTE_SLIDE 18 +#define IDS_PALETTE_ACTION 19 +#define IDS_PALETTE_BASIC_OBJECTS 20 +#define IDS_PALETTE_PROJECT 21 +#define IDS_OBJTYPE_MASTER 22 +#define IDS_SLIDE_EDIT_MASTER 23 +#define IDS_SLIDE_LEAVE_MASTER 24 +#define IDS_SLIDE_DEFAULT_TITLE 25 +#define IDS_HELP_FILE_NAME 26 +#define IDS_PREF_RESTOREDEFAULT_TITLE 27 +#define IDS_PREF_RESTOREDEFAULT_TEXT 28 +#define IDS_PREF_INTERPOLATION_1 29 +#define IDS_PREF_INTERPOLATION_2 30 +#define IDS_PREF_SNAPRANGE_1 31 +#define IDS_PREF_SNAPRANGE_2 32 +#define IDS_PREF_SNAPRANGE_3 33 +#define IDS_ERROR_REFRESHRESOURCETEXT 34 +#define IDS_ERROR_REFRESHRESOURCETITLE 35 +#define IDS_ERROR_IMPORTRESOURCETEXT 36 +#define IDS_ERROR_IMPORTRESOURCETEXT_CHECKFILE 37 +#define IDS_ERROR_IMPORTRESOURCETEXT_REASON 38 +#define IDS_ERROR_IMPORTRESOURCETEXT_COMPLETEWITHWARNING 39 +#define IDS_ERROR_IMPORTRESOURCETEXT_FAILED 40 +#define IDS_ERROR_IMPORTRESOURCETITLE 41 +#define IDS_ERROR_IMPORTRESOURCETITLE_ERROR 42 +#define IDS_ERROR_IMPORTRESOURCETITLE_WARNING 43 +#define IDS_ERROR_IMPORTLUARESOURCETEXT 44 +#define IDS_ERROR_LOADPRESENTATION 45 +#define IDS_ERROR_LOADFILENOTEXIST 46 +#define IDS_ERROR_LOADPRESENTATION_TITLE 47 +#define IDS_ERROR_EXPORTPRESENTATION 48 +#define IDS_ERROR_MISSING_RESOURCES 49 +#define IDS_ERROR_IMPORTUNSUPPORTEDRESOURCETYPETEXT 50 +#define IDS_ERROR_MSGTITLE 51 +#define IDS_ERROR_CLIENTSAVE 52 +#define IDS_ERROR_PROJECT_VARIABLES_TITLE 53 +#define IDS_ERROR_PROJECT_VARIABLES_MSG 54 +#define IDS_ERROR_OBJECT_RENAME_TITLE 55 +#define IDS_ERROR_OBJECT_RENAME_EMPTY_STRING 56 +#define IDS_ERROR_OBJECT_RENAME_DUPLICATED_STRING 57 +#define IDS_ERROR_PATHOLOGICAL_PASTE_TITLE 58 +#define IDS_ERROR_PATHOLOGICAL_PASTE_MESSAGE 59 +#define IDS_ERROR_MSGPASSING 60 +#define IDS_WARNING_IMPORTLUARESOURCETEXT 61 +#define IDS_WARNING_MSGTITLE 62 +#define IDS_TITLE_WARNING 63 +#define IDS_FILE_DESC_UIP 64 +#define IDS_FILE_EXT_UIP 65 +#define IDS_LIBRARYIMPORT_MODEL 66 +#define IDS_LIBRARYIMPORT_IMAGE 67 +#define IDS_LIBRARYIMPORT_BEHAVIOR 68 +#define IDS_LIBRARYIMPORT_MESH 69 +#define IDS_LIBRARYIMPORT_IMPORT 70 +#define IDS_LIBRARYIMPORT_EFFECT 71 +#define IDS_PROJNAME 72 +#define IDS_REPORTDLG_INFO 73 +#define IDS_REPORTDLG_DESCHEADER 74 +#define IDS_REPORTDLG_EMAILHEADER 75 +#define IDS_REPORTDLG_SYSINFOHEADER 76 +#define IDS_COMMAND_COPYACTION 77 +#define IDS_COMMAND_PASTEACTION 78 +#define IDS_COMMAND_CUTACTION 79 +#define IDS_COMMAND_DELETEACTION 80 +#define IDS_HELP_BEHAVIORREFERENCE 81 +#define IDS_SAVE_READONLY_WARNING 82 +#define IDS_COMMENT_SUGGESTION_TOADDR 83 +#define IDS_COMMENT_BUG_TOADDR 84 +#define IDS_COMMENT_TYPE_SUGGESTION 85 +#define IDS_COMMENT_TYPE_BUG 86 +#define IDS_CM_RENAME_OBJECT 87 +#define IDS_CM_DUPLICATE_OBJECT 88 +#define IDS_CM_DELETE_OBJECT 89 +#define IDS_CM_MAKE_COMPONENT 90 +#define IDS_CM_COPY_OBJECT_PATH 91 +#define IDS_CM_EXTERNALIZE_OBJECT_BUFFER 92 +#define IDS_CM_INTERNALIZE_OBJECT_BUFFER 93 +#define IDS_CM_INSPECT_COMPONENT 94 +#define IDS_TEXTEDIT_CONTEXT_MENU_CUT 95 +#define IDS_TEXTEDIT_CONTEXT_MENU_COPY 96 +#define IDS_TEXTEDIT_CONTEXT_MENU_PASTE 97 +#define IDS_UIC_STUDIO_VERSION 98 +#define IDS_CRASH_REPORT_TOADDR 99 +#define IDS_CRASH_REPORT_FROMADDR 100 +#define IDS_CRASH_REPORT_SERVERADDR 101 +#define IDS_UICOMPOSER_PALETTE_SETTINGS_REGISTRY_KEY 102 +#define IDS_COPYPASTE_FORMAT_NAME 103 +#define IDS_STUDIOFONT_SIZE 104 +#define IDS_STUDIOPREFSTITLE 105 +#define IDS_NOOBJECTSELECTED 106 +#define IDS_CONTEXTKEY_SETINTERPOLATION 107 +#define IDS_CONTEXTKEY_DELETESELECTED 108 +#define IDS_CONTEXTKEY_CUTSELECTED 109 +#define IDS_CONTEXTKEY_COPYSELECTED 110 +#define IDS_CONTEXTKEY_PASTE 111 +#define IDS_CONTEXTKEY_INSERTKEY 112 +#define IDS_CONTEXTKEY_SETKEYFRAMETIME 113 +#define IDS_CONTEXTKEY_DELETECHANNEL 114 +#define IDS_CONTEXTKEY_BARCOLOR 115 +#define IDS_CONTEXTKEY_BARTEXT 116 +#define IDS_CONTEXTKEY_SHOWTIMEBARHANDLES 117 +#define IDS_CONTEXTKEY_HIDETIMEBARHANDLES 118 +#define IDS_CONTEXTKEY_SETTIMEBARTIME 119 +#define IDS_CONTEXTKEY_MAKE_ANIMATION_DYNAMIC 120 +#define IDS_CONTEXTKEY_MAKE_ANIMATION_STATIC 121 +#define IDS_CONTEXTKEY_MAKE_ANIMATIONS_DYNAMIC 122 +#define IDS_CONTEXTKEY_MAKE_ANIMATIONS_STATIC 123 +#define IDS_CONTEXT_SLIDE_NEW 124 +#define IDS_CONTEXT_SLIDE_DELETE 125 +#define IDS_CONTEXT_SLIDE_DUPLICATE 126 +#define IDS_CONTEXT_LINK_STATEWISE 127 +#define IDS_CONTEXT_UNLINK_STATEWISE 128 +#define IDS_HK_CMD 129 +#define IDS_HK_ALPHALOCK 130 +#define IDS_CONTROLS_FLOAT_MINUS 131 +#define IDS_CONTROLS_FLOAT_PERIOD 132 +#define IDS_PROJECT_BEHAVIORLIB_PATH 133 +#define IDS_PROJECT_EFFECTLIB_PATH 134 +#define IDS_PROJECT_FONTLIB_PATH 135 +#define IDS_PROJECT_IMAGELIB_PATH 136 +#define IDS_PROJECT_MATERIALLIB_PATH 137 +#define IDS_PROJECT_MODELLIB_PATH 138 +#define IDS_PROJECT_BUTTON_BEHAVIOR 139 +#define IDS_PROJECT_BUTTON_EFFECT 140 +#define IDS_PROJECT_BUTTON_FONT 141 +#define IDS_PROJECT_BUTTON_IMAGE 142 +#define IDS_PROJECT_BUTTON_MATERIAL 143 +#define IDS_PROJECT_BUTTON_MODEL 144 +#define IDS_PROJECT_CM_SHOW_IN_EXPLORER 145 +#define IDS_PROJECT_CM_COPY_PATH 146 +#define IDS_PROJECT_CM_COPY_FULL_PATH 147 +#define IDS_PROJECT_CM_LOCATE_FOLDER 148 +#define IDS_PROJECT_CM_LOCATE_FILE 149 +#define IDS_PROJECT_FILE_NOT_IN_DOCUMENT_SUBDIR 150 +#define IDS_UNTITLED_DOCUMENT_TITLE 151 +#define IDS_CREATE_NEW_DOCUMENT_TITLE 152 +#define IDS_MENU_WIN_UNDO_FORMAT 153 +#define IDS_MENU_WIN_REDO_FORMAT 154 +#define IDS_MENU_WIN_COPY_FORMAT 155 +#define IDS_MENU_WIN_PASTE_FORMAT 156 +#define IDS_MENU_WIN_CUT_FORMAT 157 +#define IDS_MENU_COPYPASTE_TYPE_ACTION 158 +#define IDS_MENU_COPYPASTE_TYPE_KEYFRAMES 159 +#define IDS_MENU_COPYPASTE_TYPE_OBJECT 160 +#define IDS_PROMPT_FOR_SAVE 161 +#define IDS_PROMPT_FOR_REVERT 162 +#define IDS_WAIT_LOADING 163 +#define IDS_HELP_VISIT_QT 164 +#define IDS_FLTR_TOOLTIP_BEHAVIOR1 165 +#define IDS_FLTR_TOOLTIP_BEHAVIOR2 166 +#define IDS_FLTR_TOOLTIP_PROPERTIES1 167 +#define IDS_FLTR_TOOLTIP_PROPERTIES2 168 +#define IDS_FLTR_TOOLTIP_MATERIALS1 169 +#define IDS_FLTR_TOOLTIP_MATERIALS2 170 +#define IDS_FLTR_TOOLTIP_SHY1 171 +#define IDS_FLTR_TOOLTIP_SHY2 172 +#define IDS_FLTR_TOOLTIP_VISIBLE1 173 +#define IDS_FLTR_TOOLTIP_VISIBLE2 174 +#define IDS_FLTR_TOOLTIP_LOCK1 175 +#define IDS_FLTR_TOOLTIP_LOCK2 176 +#define IDS_TOOLTIP_ANIMATE_TOGGLE 177 +#define IDS_TIME_EDIT_DLG_GO_TO_TIME 178 +#define IDS_TIME_EDIT_DLG_SET_KEYFRAME_TIME 179 +#define IDS_TIME_EDIT_DLG_SET_TIMEBAR_TIME 180 +#define IDS_TIME_EDIT_DLG_START_TIME 181 +#define IDS_TIME_EDIT_DLG_END_TIME 182 +#define IDS_TIME_EDIT_DLG_MIN_SEC_MSEC 183 +#define IDS_REFRESH_IMPORT 184 +#define IDS_COLORCHOOSER_AUTO 185 +#define IDS_COLORCHOOSER_MORE 186 +#define IDS_SPLASH_COPYRIGHT1 187 +#define IDS_SPLASH_COPYRIGHT2 188 +#define IDS_ABOUT_COPYRIGHT 189 +#define IDS_ABOUT_PAINTLIB_CREDIT 190 +#define IDS_ABOUT_FBX_CREDIT 191 +#define IDS_DEFAULT_PALETTE_LAYOUT 192 +#define IDS_BASIC_OBJ_PALETTE_LAYER 193 +#define IDS_BASIC_OBJ_PALETTE_CAMERA 194 +#define IDS_BASIC_OBJ_PALETTE_LIGHT 195 +#define IDS_BASIC_OBJ_PALETTE_GROUP 196 +#define IDS_BASIC_OBJ_PALETTE_CUBE 197 +#define IDS_BASIC_OBJ_PALETTE_CYLINDER 198 +#define IDS_BASIC_OBJ_PALETTE_CONE 199 +#define IDS_BASIC_OBJ_PALETTE_RECTANGLE 200 +#define IDS_BASIC_OBJ_PALETTE_SPHERE 201 +#define IDS_BASIC_OBJ_PALETTE_TEXT 202 +#define IDS_BASIC_OBJ_PALETTE_COMPONENT 203 +#define IDS_BASIC_OBJ_PALETTE_ALIAS 204 +#define IDS_CREATE_NEW_PALETTE 205 +#define IDS_MOVE_PALETTE 206 +#define IDS_GROUP_EXPAND_TOGGLE_TOOLTIP 207 +#define IDS_GROUP_MOVE_UP_TOOLTIP 208 +#define IDS_GROUP_MOVE_DOWN_TOOLTIP 209 +#define IDS_ACTION_DELETE_TOOLTIP 210 +#define IDS_HANDLER_CONTROL_NAME 211 +#define IDS_EVENT_CONTROL_NAME 212 +#define IDS_EVENT_TARGET_OBJ 213 +#define IDS_EVENT_TRIGGER_OBJ 214 +#define IDS_ACTION_LISTEN_FOR_STRING 215 +#define IDS_ACTION_LISTEN_FOR_TELL_STRING 216 +#define IDS_ACTION_LISTEN_TO_FOR_STRING 217 +#define IDS_ACTION_LISTEN_TO_FOR_TELL_STRING 218 +#define IDS_ACTION_NEW 219 +#define IDS_DELETE_ACTION 220 +#define IDS_PROPERTIES_BASIC 221 +#define IDS_PROPERTIES_SHARED 222 +#define IDS_OBJ_REF_PATH 223 +#define IDS_OBJ_REF_PATH_TYPE 224 +#define IDS_OBJ_REF_PATH_ABSOLUTE 225 +#define IDS_OBJ_REF_PATH_RELATIVE 226 +#define IDS_PROP_UNKNOWN_SOURCE 227 +#define IDS_PROP_UNKNOWN_TARGET 228 +#define IDS_PROP_UNKNOWN_PROP 229 +#define IDS_PROP_UNKNOWN_HANDLER 230 +#define IDS_ACTION_ENABLE_STATE 231 +#define IDS_ASSET_NAME_UNKNOWN 232 +#define IDS_DELETE_OBJ_CONFIRM_TITLE 233 +#define IDS_DELETE_OBJ_CONFIRM_MSG 234 +#define IDS_SCENE_CAMERA_VIEW 235 +#define IDS_PROJECT_VARIABLES_FORMAT 236 +#define IDS_CONFIG_EXPORT_PREVIEW 237 +#define IDS_CONFIG_EXPORT_DEPLOY 238 +#define IDS_CONFIG_PREVIEW_TITLE 239 +#define IDS_CONFIG_PREVIEW_ERROR_TITLE 240 +#define IDS_CONFIG_PREVIEW_ERROR_MSG 241 +#define IDS_CONFIG_PREVIEW_ERROR_TEXT 242 +#define IDS_CONFIG_PREVIEW_REDIRECT_ERROR 243 +#define IDS_CONFIG_PREVIEW_INPUT 244 +#define IDS_CONFIG_PREVIEW_OUTPUT 245 +#define IDS_RENAME_OBJ_CONFIRM_TITLE 246 +#define IDS_RENAME_OBJ_CONFIRM_MSG 247 +#define IDS_BUILDCONFIGS_ERROR_TITLE 248 +#define IDS_MISSINGSLIDE 249 +#define IDS_SAVE_UNKNOWN_ERROR 250 +#define IDS_GL_VERSION_ERROR 251 +#define IDS_GL_VERSION_WARNING 252 +#define IDS_PRESENTATION_MODIFIED_EXTERNALLY 253 +#ifdef KDAB_TEMPORARILY_REMOVED +#define placeholder 254 +#endif + +#endif //STUDIOSTRINGSH \ No newline at end of file diff --git a/src/Authoring/Studio/English.lproj/Strings/StringsReadme.htm b/src/Authoring/Studio/English.lproj/Strings/StringsReadme.htm new file mode 100644 index 00000000..78dec4f1 --- /dev/null +++ b/src/Authoring/Studio/English.lproj/Strings/StringsReadme.htm @@ -0,0 +1,124 @@ + + + + + + + +Studio String Files + + + + +

Studio String Files

+

The directory Studio\English.lproj\Strings contain files that help manage the +following ideas:

+
    +
  • the text strings displayed in Studio's user interface and how they are + mapped onto integer-based identifiers in the C++ source code
  • +
  • the process of internationalization (or localization) of the GUI and the + strings that are displayed in non-English versions of Studio
  • +
+

This document provides an overview of the various files and how they are +used.

+
+ Paul Tweedlie, January 27 2005
+

Compile.py

+

The Python script 'compile.py' takes the 2 input files (stri) and generates +the 2 output files (stro) and a C++ header file 'Strings.h'. The 2 stri input +files are ASCII-based and are typically edited by code developers while adding +new GUI and functionality. The 2 stro files generated by the script are 16-bit +Unicode-based files that are designed to be language-independent, see +http://www.unicode.org/. The 2 stro files +form part of the Studio release and are loaded by Studio.exe on start-up. They +are installed on a user's machine in the directory:

+

    C:\Program Files\Qt 3D Studio\res\Strings

+

The stro files may be edited at the end of a development cycle to localize +Studio's GUI from English to another language that may use a different script, +e.g. Japanese.

+

To run the compile.py script, you need a Python interpreter installed on your +machine, get one from http://www.python.org/. +The typical steps for a code developer are:

+
    +
  1. Check out the input files and the output files before running the + script. It's easiest to just check out the entire Strings directory using + Perforce.
  2. +
  3. Make your text changes to the stri file(s)
  4. +
  5. Run the compile.py script
  6. +
  7. Build Studio and verify your changes
  8. +
  9. Go to Perforce and revert unchanged files in the Strings directory
  10. +
  11. Check in the Strings directory back into Perforce
  12. +
+

Strings.h

+

The C++ header file 'Strings.h' is auto-generated and should never be hand +edited. The file contains a bunch of #define statements that set up constant +identifiers where each identifier is assigned a unique integer. For example,

+

    #define IDS_CONTEXT_SLIDE_NEW 570

+

Stri: ASCII Input Files

+
+
+ + + + + +
Static.striAn ASCII text file that specifies the strings that are + displayed in Studio's user interface such as buttons and tooltips. The + file is organized as a mapping of pairs from integer-based + identifiers that are referenced in the C++ source code to text + strings. For example, the mapping for the 'New Slide' button appears as:

    + <string name="IDS_CONTEXT_SLIDE_NEW" value="New Slide" />

+

where the integer identifier 'IDS_CONTEXT_SLIDE_NEW' is used in the + source file SlideContextMenu.cpp and 'New Slide' is the text that appears + in the list of options when the user right-clicks in the Slide palette. +

+

Developers should edit this file when writing new GUI code, e.g. adding + new buttons.

+
+
+

Stro: Unicode Output Files

+
+
+ + + + + +
Static.stroA Unicode file that specifies the strings that are + displayed in Studio's user interface such as buttons and tooltips. The + file is organized into a list of triples: an identifier, a numeric value, + and a Unicode string. For example, the triple representing the 'New Slide' + button appears as:

    <string name="IDS_CONTEXT_SLIDE_NEW" + ID="570" value="New Slide"/>.

+

Language translators should edit the 'value' strings in this file. For + example, the above triple may be translated as follows:

+

   <string name="IDS_CONTEXT_SLIDE_NEW" ID="570" + value="Nouveau Slide"/>.

+
+
+

Localization

+

Studio's user interface uses the Arial font by default and a point side of +13pt. If you want to change the GUI's font and/or the point size, you should +search in the Static.stro file for the following identifiers:

+

   <string name="IDS_STUDIOFONT_FACE" ID="548" value="Arial"/>

+

   <string name="IDS_STUDIOFONT_SIZE" ID="547" value="13"

+

If you want to use a font that supports non-English characters, for instance +Japanese symbols, you should first change the 'Arial' font to something like +'Arial Unicode MS'. For example,

+

   <string name="IDS_STUDIOFONT_FACE" ID="548" value="Arial Unicode +MS"/>

+

Next you substitute all the English strings in the stro files for their +Japanese-translated counterparts. You will need to use an editor such as Notepad +or Wordpad that supports the Unicode format. For example, perhaps the 'New +Slide' option is translated so:

+

   <string name="IDS_CONTEXT_SLIDE_NEW" ID="570" value="キャッシン"/>. +

+

Note from Gim Guan Chua: To see the Japanese symbols in Studio, you may have +to set your machine to Japanese settings (in Control Panel->Regional and +Language Settings->Advance). Studio is considered a "non-Unicode" program in +contrast to Notepad and Wordpad which are Unicode-aware in XP.

+

 

+ + + + diff --git a/src/Authoring/Studio/English.lproj/Strings/compile.py b/src/Authoring/Studio/English.lproj/Strings/compile.py new file mode 100644 index 00000000..255d1f45 --- /dev/null +++ b/src/Authoring/Studio/English.lproj/Strings/compile.py @@ -0,0 +1,245 @@ +''' +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +''' + +'''Compile the string input (stri) into string output (stro) + Strings.h''' +import os, os.path, re +import xml.sax.handler, xml.sax, codecs + + +class CGenericXMLFactory: + '''Generic factory for xml generation''' + def __init__( self ): + self.m_Elements = {} + + def AddTagElement( self, inName, inFunction ): + self.m_Elements[inName] = inFunction + + def CreateObject( self, inName, inAttrs, inParent ): + theElement = self.m_Elements[inName](inName, inAttrs, inParent ) + return theElement + + +class CBaseXMLHandler( xml.sax.handler.ContentHandler ): + """Base xml parsing class. Can be used to form a dom system""" + def __init__( self, inFactory ): + self.m_Objects = [] #stack of objects used for parsing (targets require the latest project) + self.m_Factory = inFactory + self.m_CurrentObject = None + self.m_CharacterHandler = None + self.m_TopObject = None + + def startElement( self, name, attrs ): + theParent = None + if( not len(self.m_Objects) == 0 ): + theParent = self.m_Objects[-1] + self.m_CurrentObject = self.m_Factory.CreateObject( name, attrs, theParent ) + try: + self.m_CurrentObject.startElement( self ) + except AttributeError: + pass #Don't care if the object does not support the method call + self.OnObjectCreated( self.m_CurrentObject ) + + def endElement( self, name ): + theElement = self.m_Objects.pop() + try: + theElement.endElement( self ) + except AttributeError: + pass #Don't care if the object does not support the method call + + if( len( self.m_Objects ) != 0 ): + self.m_CurrentObject = self.m_Objects[-1] + + def characters( self, content ): + if( self.m_CharacterHandler ): + self.m_CharacterHandler( self.m_CurrentObject, content ) + + def SetCharacterHandler( self, inHandler ): + self.m_CharacterHandler = inHandler + + def OnObjectCreated( self, theObject ): + '''Callback every time a factory returns an object''' + self.m_Objects.append( theObject ) + if( len( self.m_Objects ) == 1 ): + self.m_TopObject = self.m_CurrentObject + + def SetFactory( self, inFactory ): + self.m_Factory = inFactory + + def Parse( self, inFilename ): + '''Parse the file, grabbing the extension''' + theDirectory = os.path.dirname( inFilename ) + theFile = os.path.basename( inFilename ) + self.m_BasePath = theDirectory + theReturn = None + theExcept = None + self.m_TopObject = None + self.m_CurrentObject = None + self.m_Objects = [] + theParse = xml.sax.parse( inFilename, self ) + return self.m_TopObject + + +class CStringObject: + '''Basic string object''' + def __init__( self ): + self.m_Name = '' + self.m_Value = '' + + def SetName( self, inName ): + self.m_Name = inName + + def GetName( self ): + return self.m_Name + + def SetValue( self, inValue ): + self.m_Value = inValue + + def GetValue( self ): + return self.m_Value + +def XMLStringObjectInit( inName, inAttrs, inParent ): + '''Create a string object from xml''' + theObject = CStringObject( ) + try: + theObject.SetName( inAttrs['name'] ) + theObject.SetValue( inAttrs['value'] ) + except KeyError: + print 'Failed to parse string object' + inParent.AddObject( theObject ) + return theObject + + +class CStringObjectList: + '''Create a list of string objects''' + def __init__( self ): + self.m_StringObjects = [] + + def AddObject( self, inStringObject ): + self.m_StringObjects.append( inStringObject ) + + def GetObjects( self ): + return self.m_StringObjects + +def XMLStringObjectListInit( inName, inAttrs, inParent ): + '''Create a list from xml''' + theStringList = CStringObjectList() + return theStringList + +def ExportObjects( inFactory ): + inFactory.AddTagElement( 'stringresourceinput', XMLStringObjectListInit ) + inFactory.AddTagElement( 'string', XMLStringObjectInit ) + + + + +###Main Code Below########################################### +theLists = [] +#parse into a named group the matches anything up to the period and an ending of stri +theSourceRegex = re.compile( r'(?P.*)\.stri$' ) # $ means end of line/input +theTotalFiles = os.listdir( '.' ) #List files in the current working directory + + +#Create xml parsing context +theFactory = CGenericXMLFactory() +theHandler = CBaseXMLHandler( theFactory ) +ExportObjects( theFactory ) #Export the dom objects we would like to use + +theStringCount = 0 + +for theFile in theTotalFiles: + theMatch = theSourceRegex.match( theFile ) + if( theMatch ): + theList = None + try: + print 'parsing %s' % ( theFile ) + theList = theHandler.Parse( theFile ) + theLists.append( ( theMatch.group( 'stem' ), theList ) ) #append a touple of the source name + theStringCount += len( theList.GetObjects() ) + except Exception, e: + print 'Failed to parse %s: %s' % ( theFile, e ) + #salvage anything possible + theList = theHandler.m_TopObject + if( theList ): + theLists.append( ( theMatch.group( 'stem' ), theList ) ) #append a touple of the source name + theStringCount += len( theList.GetObjects() ) + +theIndex = 1 +theHeaderName = 'Strings.h' +theHeaderFile = open( 'Strings.h', 'w' ) + +theHeaderLine = ''' +//=============================================================================================================================== +// CODEGEN -- FILE CREATED BY STUDIO CODE GENERATION SYSTEM +// +// Do not modify the contents of this file. Your changes will be destroyed by +// code generation. +// +// Please see the CodeGen folder for more information or to make changes. +// C:\NVIDIA\p4sw\sw\contenttools\UIComposer\ViewComposer\Main\Studio\English.lproj\Strings\StringsReadme.htm\StringsReadme.htm +//=============================================================================================================================== +//{{AFX_INSERT_LOCATION}} + +#ifndef STUDIOSTRINGSH +#define STUDIOSTRINGSH + +#define STRING_RESOURCE_COUNT %s +''' % ( theStringCount ) + +theResultLine = ''' + + + + + + + + + + + +''' + +theHeaderFile.write( theHeaderLine ) +for theName, theList in theLists: + theFileName = theName + '.stro' + print 'write file %s' % ( theFileName ) + theResultFile = codecs.open( theFileName, 'w', 'utf-16' ) + theResultFile.write( theResultLine ) + for theObject in theList.GetObjects(): + theName = theObject.GetName() + theValue = theObject.GetValue() + theResultFile.write( '\t\n' % ( theName, theIndex, theValue ) ) + theHeaderFile.write( '#define %s %s\n' % ( theName, theIndex ) ) + theIndex+= 1 + theResultFile.write( '' ) + theResultFile.close() + +theHeaderFile.write( '\n#endif //STUDIOSTRINGSH' ) +theHeaderFile.close() diff --git a/src/Authoring/Studio/English.lproj/Strings/compile32.py b/src/Authoring/Studio/English.lproj/Strings/compile32.py new file mode 100644 index 00000000..a1be6cab --- /dev/null +++ b/src/Authoring/Studio/English.lproj/Strings/compile32.py @@ -0,0 +1,272 @@ +''' +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +''' +'''Compile the string input (stri) into string output (stro) + Strings.h''' +import os, os.path, re +import xml.sax.handler, xml.sax, codecs + + +class CGenericXMLFactory: + '''Generic factory for xml generation''' + def __init__( self ): + self.m_Elements = {} + + def AddTagElement( self, inName, inFunction ): + self.m_Elements[inName] = inFunction + + def CreateObject( self, inName, inAttrs, inParent ): + theElement = self.m_Elements[inName](inName, inAttrs, inParent ) + return theElement + + +class CBaseXMLHandler( xml.sax.handler.ContentHandler ): + """Base xml parsing class. Can be used to form a dom system""" + def __init__( self, inFactory ): + self.m_Objects = [] #stack of objects used for parsing (targets require the latest project) + self.m_Factory = inFactory + self.m_CurrentObject = None + self.m_CharacterHandler = None + self.m_TopObject = None + + def startElement( self, name, attrs ): + theParent = None + if( not len(self.m_Objects) == 0 ): + theParent = self.m_Objects[-1] + self.m_CurrentObject = self.m_Factory.CreateObject( name, attrs, theParent ) + try: + self.m_CurrentObject.startElement( self ) + except AttributeError: + pass #Don't care if the object does not support the method call + self.OnObjectCreated( self.m_CurrentObject ) + + def endElement( self, name ): + theElement = self.m_Objects.pop() + try: + theElement.endElement( self ) + except AttributeError: + pass #Don't care if the object does not support the method call + + if( len( self.m_Objects ) != 0 ): + self.m_CurrentObject = self.m_Objects[-1] + + def characters( self, content ): + if( self.m_CharacterHandler ): + self.m_CharacterHandler( self.m_CurrentObject, content ) + + def SetCharacterHandler( self, inHandler ): + self.m_CharacterHandler = inHandler + + def OnObjectCreated( self, theObject ): + '''Callback every time a factory returns an object''' + self.m_Objects.append( theObject ) + if( len( self.m_Objects ) == 1 ): + self.m_TopObject = self.m_CurrentObject + + def SetFactory( self, inFactory ): + self.m_Factory = inFactory + + def Parse( self, inFilename ): + '''Parse the file, grabbing the extension''' + theDirectory = os.path.dirname( inFilename ) + theFile = os.path.basename( inFilename ) + self.m_BasePath = theDirectory + theReturn = None + theExcept = None + self.m_TopObject = None + self.m_CurrentObject = None + self.m_Objects = [] + theParse = xml.sax.parse( inFilename, self ) + return self.m_TopObject + + +class CStringObject: + '''Basic string object''' + def __init__( self ): + self.m_Name = '' + self.m_Value = '' + + def SetName( self, inName ): + self.m_Name = inName + + def GetName( self ): + return self.m_Name + + def SetValue( self, inValue ): + self.m_Value = inValue + + def GetValue( self ): + return self.m_Value + +def XMLStringObjectInit( inName, inAttrs, inParent ): + '''Create a string object from xml''' + theObject = CStringObject( ) + try: + theObject.SetName( inAttrs['name'] ) + theObject.SetValue( inAttrs['value'] ) + except KeyError: + print("Failed to parse string object") + + inParent.AddObject( theObject ) + return theObject + + +class CStringObjectList: + '''Create a list of string objects''' + def __init__( self ): + self.m_StringObjects = [] + + def AddObject( self, inStringObject ): + self.m_StringObjects.append( inStringObject ) + + def GetObjects( self ): + return self.m_StringObjects + +def XMLStringObjectListInit( inName, inAttrs, inParent ): + '''Create a list from xml''' + theStringList = CStringObjectList() + return theStringList + +def ExportObjects( inFactory ): + inFactory.AddTagElement( 'stringresourceinput', XMLStringObjectListInit ) + inFactory.AddTagElement( 'string', XMLStringObjectInit ) + + + + +###Main Code Below########################################### +theLists = [] +#parse into a named group the matches anything up to the period and an ending of stri +theSourceRegex = re.compile( r'(?P.*)\.stri$' ) # $ means end of line/input +theTotalFiles = os.listdir( '.' ) #List files in the current working directory + + +#Create xml parsing context +theFactory = CGenericXMLFactory() +theHandler = CBaseXMLHandler( theFactory ) +ExportObjects( theFactory ) #Export the dom objects we would like to use + +theStringCount = 0 + +for theFile in theTotalFiles: + theMatch = theSourceRegex.match( theFile ) + if( theMatch ): + theList = None + try: + print( 'parsing %s' % ( theFile ) ) + theList = theHandler.Parse( theFile ) + theLists.append( ( theMatch.group( 'stem' ), theList ) ) #append a touple of the source name + theStringCount += len( theList.GetObjects() ) + except Exception as e: + print( 'Failed to parse %s: %s' % ( theFile, e ) ) + #salvage anything possible + theList = theHandler.m_TopObject + if( theList ): + theLists.append( ( theMatch.group( 'stem' ), theList ) ) #append a touple of the source name + theStringCount += len( theList.GetObjects() ) + +theIndex = 1 +theHeaderName = 'Strings.h' +theHeaderFile = open( 'Strings.h', 'w' ) + +theHeaderLine = r''' +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//=============================================================================================================================== +// CODEGEN -- FILE CREATED BY STUDIO CODE GENERATION SYSTEM +// +// Do not modify the contents of this file. Your changes will be destroyed by +// code generation. +// +// Please see the CodeGen folder for more information or to make changes. +// StringsReadme.htm +//=============================================================================================================================== +//{{AFX_INSERT_LOCATION}} + +#ifndef STUDIOSTRINGSH +#define STUDIOSTRINGSH + +#define STRING_RESOURCE_COUNT %s +''' % ( theStringCount ) + +theResultLine = r''' + + + + + + + + + + + +''' + +theHeaderFile.write( theHeaderLine ) +for theName, theList in theLists: + theFileName = theName + '.stro' + print('write file %s' % ( theFileName )) + theResultFile = codecs.open( theFileName, 'w', 'utf-16' ) + theResultFile.write( theResultLine ) + for theObject in theList.GetObjects(): + theName = theObject.GetName() + theValue = theObject.GetValue() + theResultFile.write( '\t\n' % ( theName, theIndex, theValue ) ) + theHeaderFile.write( '#define %s %s\n' % ( theName, theIndex ) ) + theIndex+= 1 + theResultFile.write( '' ) + theResultFile.close() + +theHeaderFile.write( '\n#endif //STUDIOSTRINGSH' ) +theHeaderFile.close() diff --git a/src/Authoring/Studio/MainFrm.cpp b/src/Authoring/Studio/MainFrm.cpp new file mode 100644 index 00000000..9db47a65 --- /dev/null +++ b/src/Authoring/Studio/MainFrm.cpp @@ -0,0 +1,2049 @@ +/**************************************************************************** +** +** 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 "MainFrm.h" +#include "ui_MainFrm.h" + +#include "StudioConst.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Bindings/TimelineTranslationManager.h" +#include "Bindings/UICDMTimelineItemBinding.h" +#include "Bindings/ITimelineTimebar.h" +#include "SceneView.h" +#include "Strings.h" +#include "StringLoader.h" +#include "StudioApp.h" +#include "TimelineControl.h" +#include "UICOptions.h" +#include "UICColor.h" + +#include "Doc.h" +#include "IKeyframesManager.h" +#include "Dispatch.h" +#include "Dialogs.h" +#include "StudioPreferencesPropSheet.h" +#include "StudioProjectSettings.h" +#include "StudioPreferences.h" +#include "Views.h" +#include "HotKeys.h" +#include "RecentItems.h" +#include "PaletteManager.h" +#include "Core.h" +#include "ITickTock.h" +#include "IStudioRenderer.h" +#include "SubPresentationsDlg.h" +#include "StudioTutorialWidget.h" +#include "remoteproject.h" + +#include "InspectorControlView.h" + +#include +#include +#include +#include +#include +#include +#include + +// Constants +const long PLAYBACK_TIMER_TIMEOUT = 10; // 10 milliseconds + +#ifdef KDAB_TEMPORARILY_REMOVED +ON_MESSAGE(WM_STUDIO_MESSAGE_ROUTER, OnMsgRouterMsg) +#endif + +//============================================================================== +/** + * Constructor + */ +CMainFrame::CMainFrame() + : m_ui(new Ui::MainFrame) +{ + m_ui->setupUi(this); + + OnCreate(); + + g_StudioApp.GetCore()->GetDispatch()->AddPresentationChangeListener(this); + g_StudioApp.GetCore()->GetDispatch()->AddFileOpenListener(this); + g_StudioApp.GetCore()->GetDispatch()->AddClientPlayChangeListener(this); + g_StudioApp.SetupTimer(WM_STUDIO_TIMER, this); + + m_remoteProject = new RemoteProject(this); + + // File Menu + connect(m_ui->action_Open, &QAction::triggered, this, &CMainFrame::OnFileOpen); + connect(m_ui->action_Save, &QAction::triggered, this, &CMainFrame::OnFileSave); + connect(m_ui->action_New, &QAction::triggered, this, &CMainFrame::OnFileNew); + connect(m_ui->actionSave_As, &QAction::triggered, this, &CMainFrame::OnFileSaveAs); + connect(m_ui->actionSave_a_Copy, &QAction::triggered, this, &CMainFrame::OnFileSaveCopy); + connect(m_ui->action_Revert, &QAction::triggered, this, &CMainFrame::OnFileRevert); + connect(m_ui->action_Connect_to_Device, &QAction::triggered, this, + &CMainFrame::OnFileConnectToDevice); + connect(m_remoteProject, &RemoteProject::connectionChanged, + m_ui->action_Connect_to_Device, &QAction::setChecked); + connect(m_ui->action_Exit, &QAction::triggered, this, &CMainFrame::close); + + m_RecentItems = new CRecentItems(m_ui->menuRecent_Projects, 0); + connect(m_RecentItems, &CRecentItems::openRecent, this, &CMainFrame::OnFileOpenRecent); + //ON_COMMAND_RANGE(WM_STUDIO_OPEN_RECENT_MIN, WM_STUDIO_OPEN_RECENT_MAX, OnFileOpenRecent) + + // Edit Menu + connect(m_ui->action_Undo, &QAction::triggered, this, &CMainFrame::OnEditUndo); + connect(m_ui->action_Redo, &QAction::triggered, this, &CMainFrame::OnEditRedo); + connect(m_ui->action_Copy, &QAction::triggered, this, &CMainFrame::OnEditCopy); + connect(m_ui->action_Cut, &QAction::triggered, this, &CMainFrame::OnEditCut); + connect(m_ui->actionAutoset_Keyframes, &QAction::triggered, this, &CMainFrame::OnToolAutosetkeys); + connect(m_ui->action_Paste, &QAction::triggered, this, &CMainFrame::OnEditPaste); + connect(m_ui->actionStudio_Preferences, &QAction::triggered, this, &CMainFrame::OnEditApplicationPreferences); + connect(m_ui->actionPresentation_Settings, &QAction::triggered, this, &CMainFrame::OnEditPresentationPreferences); + connect(m_ui->actionSubpresentations, &QAction::triggered, this, + &CMainFrame::OnEditSubPresentations); + connect(m_ui->action_Duplicate_Object, &QAction::triggered, this, &CMainFrame::OnEditDuplicate); + + // Timeline Menu + connect(m_ui->actionDelete_Selected_Keyframe_s, &QAction::triggered, this, &CMainFrame::OnTimelineDeleteSelectedKeyframes); + connect(m_ui->actionSet_Interpolation, &QAction::triggered, this, &CMainFrame::OnTimelineSetInterpolation); + connect(m_ui->actionChange_Time_Bar_Color, &QAction::triggered, this, &CMainFrame::OnTimelineSetTimeBarColor); + connect(m_ui->actionSet_Changed_Keyframes, &QAction::triggered, this, &CMainFrame::OnTimelineSetChangedKeyframe); + + // View Menu + connect(m_ui->actionBounding_Boxes, &QAction::triggered, this, &CMainFrame::OnViewBoundingBoxes); + connect(m_ui->actionPivot_Point, &QAction::triggered, this, &CMainFrame::OnViewPivotPoint); + connect(m_ui->actionWireframe, &QAction::triggered, this, &CMainFrame::OnViewWireframe); + connect(m_ui->actionTooltips, &QAction::triggered, this, &CMainFrame::OnViewTooltips); + + // Tools Menu + connect(m_ui->actionTimeline, &QAction::triggered, this, &CMainFrame::OnViewTimeline); + connect(m_ui->actionAction, &QAction::triggered, this, &CMainFrame::OnViewAction); + connect(m_ui->actionBasic_Objects, &QAction::triggered, this, &CMainFrame::OnViewBasicObjects); + connect(m_ui->actionProject, &QAction::triggered, this, &CMainFrame::OnViewProject); + connect(m_ui->actionSlide, &QAction::triggered, this, &CMainFrame::OnViewSlide); + connect(m_ui->actionInspector, &QAction::triggered, this, &CMainFrame::OnViewInspector); + + // Help Menu + connect(m_ui->action_Reference_Manual, &QAction::triggered, this, &CMainFrame::OnHelpIndex); + connect(m_ui->action_Visit_Qt_Web_Site, &QAction::triggered, this, &CMainFrame::OnHelpVisitQt); + connect(m_ui->action_About_Qt_3D_Studio, &QAction::triggered, []() { g_StudioApp.OnAppAbout(); }); + connect(m_ui->action_Open_Tutorial, &QAction::triggered, this, &CMainFrame::OnHelpOpenTutorial); + + + connect(m_ui->actionItem_Select_Tool, &QAction::triggered, m_SceneView, &CSceneView::OnToolItemSelection); + connect(m_ui->actionGroup_Select_Tool, &QAction::triggered, m_SceneView, &CSceneView::OnToolGroupSelection); + + // Playback toolbar + connect(m_ui->actionPlay, &QAction::triggered, this, &CMainFrame::OnPlaybackPlay); + connect(m_ui->actionRewind, &QAction::triggered, this, &CMainFrame::OnPlaybackRewind); + connect(m_ui->actionStop, &QAction::triggered, this, &CMainFrame::OnPlaybackStop); + connect(m_ui->actionPreview, &QAction::triggered, this, &CMainFrame::OnPlaybackPreview); + + // Tool mode toolbar + connect(m_ui->actionPosition_Tool, &QAction::triggered, this, &CMainFrame::OnToolMove); + connect(m_ui->actionRotation_Tool, &QAction::triggered, this, &CMainFrame::OnToolRotate); + connect(m_ui->actionScale_Tool, &QAction::triggered, this, &CMainFrame::OnToolScale); + connect(m_ui->actionLocal_Global_Manipulators, &QAction::triggered, this, &CMainFrame::OnToolGlobalManipulators); + + // Edit Camera toolbar + connect(m_ui->actionFit_Selected, &QAction::triggered, this, &CMainFrame::OnEditCameraZoomExtent); + connect(m_ui->actionPan_Tool, &QAction::triggered, this, &CMainFrame::OnEditCameraPan); + connect(m_ui->actionOrbit_Tool, &QAction::triggered, this, &CMainFrame::OnEditCameraRotate); + connect(m_ui->actionZoom_Tool, &QAction::triggered, this, &CMainFrame::OnEditCameraZoom); + connect(m_ui->actionShading_Mode, &QAction::triggered, this, &CMainFrame::OnEditViewFillMode); + connect(m_ui->actionRulers_Guides, &QAction::triggered, this, &CMainFrame::OnViewGuidesRulers); + connect(m_ui->actionClear_Guides, &QAction::triggered, this, &CMainFrame::OnClearGuides); + connect(m_ui->actionLock_Guides, &QAction::triggered, this, &CMainFrame::OnLockGuides); + + // TODO: better solution? + QTimer* updateUITimer = new QTimer; + updateUITimer->start(500); + connect(updateUITimer, &QTimer::timeout, [&]() { + if (QApplication::activeWindow() != this) + return; + + OnUpdateFileSave(); + OnUpdateEditUndo(); + OnUpdateEditRedo(); + OnUpdateEditCopy(); + OnUpdateEditCut(); + OnUpdateToolAutosetkeys(); + OnUpdateEditPaste(); + OnUpdateEditDuplicate(); + OnUpdateTimelineDeleteSelectedKeyframes(); + OnUpdateTimelineSetInterpolation(); + OnUpdateTimelineSetTimeBarColor(); + OnUpdateViewBoundingBoxes(); + OnUpdateViewPivotPoint(); + OnUpdateViewWireframe(); + OnUpdateViewTooltips(); + OnUpdateViewTimeline(); + OnUpdateViewInspector(); + OnUpdateViewAction(); + OnUpdateViewBasicObjects(); + OnUpdateViewProject(); + OnUpdateViewSlide(); + OnUpdateHelpIndex(); + OnUpdatePlaybackPlay(); + OnUpdatePlaybackRewind(); + OnUpdatePlaybackStop(); + OnUpdatePlaybackPreview(); + OnUpdateToolMove(); + OnUpdateToolRotate(); + OnUpdateToolScale(); + OnUpdateToolGlobalManipulators(); + OnUpdateToolGroupSelection(); + OnUpdateToolItemSelection(); + OnUpdateCameraZoomExtentAndAuthorZoom(); + OnUpdateEditCameraPan(); + OnUpdateEditCameraRotate(); + OnUpdateEditCameraZoom(); + OnUpdateEditViewFillMode(); + OnUpdateViewGuidesRulers(); + OnUpdateClearGuides(); + OnUpdateLockGuides(); + }); + + m_playbackTimer.setInterval(PLAYBACK_TIMER_TIMEOUT); + connect(&m_playbackTimer, &QTimer::timeout, this, &CMainFrame::onPlaybackTimeout); + qApp->installEventFilter(this); +} + +//============================================================================== +/** + * Destructor + */ +CMainFrame::~CMainFrame() +{ +} + +//============================================================================== +/** + * Timer callback + */ +void CMainFrame::onPlaybackTimeout() +{ + // Timer callback that drives playback + Q_ASSERT(&g_StudioApp); + g_StudioApp.GetCore()->GetDoc()->ClientStep(); +} + +//============================================================================== + +void CMainFrame::showEvent(QShowEvent *event) +{ + QMainWindow::showEvent(event); + + QSettings settings; + restoreGeometry(settings.value("mainWindowGeometry").toByteArray()); + restoreState(settings.value("mainWindowState").toByteArray()); +} + +/** + * Called when the main frame is actually created. Sets up tool bars and default + * views. + */ +int CMainFrame::OnCreate() +{ + m_SceneView = new CSceneView(&g_StudioApp, this); + connect(m_SceneView, &CSceneView::toolChanged, this, &CMainFrame::OnUpdateToolChange); + +#ifdef INCLUDE_EDIT_CAMERA + // tell the edit camera bar about this scene view + m_ui->m_EditCamerasBar->SetSceneView(m_SceneView); +#endif + + // Newly launched, the file dialog for open and import should default to more recent + // opened/imported + CDialogs *theDialogs = g_StudioApp.GetDialogs(); + // this must NOT be in 'command line' mode + if (theDialogs) { + Q3DStudio::CString theMostRecentOpen; + if (m_RecentItems && m_RecentItems->GetItemCount() > 0) + theMostRecentOpen = m_RecentItems->GetItem(0).GetPath(); + if (theMostRecentOpen.IsEmpty()) // default to exe + theMostRecentOpen = CUICFile::GetApplicationDirectory().GetPath(); + + theDialogs->ResetSettings(theMostRecentOpen); + } +#ifdef KDAB_TEMPORARILY_REMOVED + + // Change the background color for the menu bar + if (IsMenu(theMenu)) { + MENUINFO theMenuInfo = { 0 }; + theMenuInfo.cbSize = sizeof(MENUINFO); + theMenuInfo.fMask = MIM_BACKGROUND; + + CBrush *theNewBrush = new CBrush(); + CColor theBaseColor(CStudioPreferences::GetMenuBarBaseColor()); + theNewBrush->CreateSolidBrush( + RGB(theBaseColor.GetRed(), theBaseColor.GetGreen(), theBaseColor.GetBlue())); + theMenuInfo.hbrBack = *theNewBrush; // Brush you want to draw + + SetMenuInfo(theMenu, &theMenuInfo); + } + #endif + + // Create the view manager + m_PaletteManager = new CPaletteManager(this); + + // Remove basic toolbar (open, save, undo/redo, etc.) + // Kept in ui form in case it is going to be added back later on. + delete m_ui->toolBar; + + setCentralWidget(m_SceneView); + return 0; +} + +#ifdef KDAB_TEMPORARILY_REMOVED + +// If we want things to look good then on the *first* paint we want to actually +// paint over the background. I don't know why, but if you were to paint +// the entire background on every message you would get some flashing. +void CMainFrame::OnPaint() +{ + static bool needsPaint = true; + if (needsPaint) { + needsPaint = false; + RECT theRect; + ::GetClientRect(GetSafeHwnd(), &theRect); + CBrush theBrush; + ::CColor theColor = CStudioPreferences::GetBaseColor(); + DWORD theColorRef = RGB(theColor.GetRed(), theColor.GetGreen(), theColor.GetBlue()); + theBrush.CreateSolidBrush(theColor); + CPaintDC dc(this); + dc.FillRect(&theRect, &theBrush); + } + CFrameWnd::OnPaint(); +} +//============================================================================== +void CMainFrame::OnInitMenu(CMenu *inMenu) +{ + ReleaseFocus(); + // Emulate a Control ModifierUp on the Sceneview to "unstick" the Alt-Key/Scale Tool + m_SceneView->HandleModifierUp(CHotKeys::KEY_MENU, 0, 0); + CFrameWnd::OnInitMenu(inMenu); +} + +::CString CMainFrame::m_WindowClass; + +::CString CMainFrame::GetWindowClass() +{ + if (m_WindowClass.GetLength() == 0) { + ::CColor theColor = CStudioPreferences::GetBaseColor(); + DWORD theRefColor = RGB(theColor.GetRed(), theColor.GetGreen(), theColor.GetBlue()); + HBRUSH theBrush = ::CreateSolidBrush(theRefColor); + m_WindowClass = AfxRegisterWndClass(0, 0, theBrush, 0); + } + return m_WindowClass; +} + +BOOL CMainFrame::PreCreateWindow(CREATESTRUCT &cs) +{ + if (!CFrameWnd::PreCreateWindow(cs)) + return FALSE; + + // TODO: Modify the Window class or styles here by modifying + cs.lpszClass = GetWindowClass(); + return TRUE; +} + +BOOL CMainFrame::DestroyWindow() +{ + // Save before we destroy anything + SaveLayout(); + + SAFE_DELETE(m_PaletteManager); + + g_StudioApp.GetCore()->GetDispatch()->RemovePresentationChangeListener(this); + g_StudioApp.GetCore()->GetDispatch()->RemoveFileOpenListener(this); + g_StudioApp.GetCore()->GetDispatch()->RemoveClientPlayChangeListener(this); + + SAFE_DELETE(m_RecentItems); + + // In order to help debug why image lists sometimes crash on shutdown + // This will help identify whcih cone is causing the problem + m_ClientToolsImageList.DeleteImageList(); + m_ClientToolsImageListHot.DeleteImageList(); + m_ClientToolsImageListDisabled.DeleteImageList(); + m_PlaybackImageList.DeleteImageList(); + m_PlaybackImageListHot.DeleteImageList(); + m_PlaybackImageListDisabled.DeleteImageList(); + m_EditCameraToolsImageList.DeleteImageList(); + m_EditCameraToolsImageListHot.DeleteImageList(); + m_EditCameraToolsImageListDisabled.DeleteImageList(); + + return CFrameWnd::DestroyWindow(); +} +#endif + +//============================================================================== +/** + * Called when a new presenation is created. We have to wait to associate the + * scene object with the scene view until this point, because the scene object + * does not exist until this function gets called. + */ +void CMainFrame::OnNewPresentation() +{ + // TODO - CN needs to fix this + // Associate the scene object with the scene view + m_ui->m_EditCamerasBar->SetupCameras(); +} + +//============================================================================== +/** + * Called when the current presentation is being closed. + * This will close all the editor windows that are open. + */ +void CMainFrame::OnClosingPresentation() +{ +} + +//============================================================================== +/** + * Handles the Timeline | Set Interpolation menu item + * This is a temporary method that will display the Set Interpolation dialog. + */ +void CMainFrame::OnTimelineSetInterpolation() +{ + g_StudioApp.GetCore()->GetDoc()->SetKeyframeInterpolation(); +} + +//============================================================================== +/** + * Store all the information regarding the layout of the main frame and its palettes. + * This is used to save the current position, so when the app is restarted the + * window will come back to it's previous location. + * On one hand, there is the main frame which continues to use the original + * CPaletteState scheme. Now there is also the control bars/palettes that dock. + * These all now use the MFC path for serialization to the registry. + * This operation used to occur every time there was a change to any window, now + * the final state is only saved when the app is closed. + */ +void CMainFrame::SaveLayout() +{ + if (m_PaletteManager) + m_PaletteManager->Save(); + +#ifdef KDAB_TEMPORARILY_REMOVED + // Only save the window position if we're not minimized + if (!IsIconic()) { + CPaletteState theState("MainWindow"); + + theState.SetMaximized(IsZoomed() == TRUE); + if (!IsZoomed()) { + /* + SDJ: 12/17/03 - From MSDN + The coordinates used in a WINDOWPLACEMENT structure should be used only by the + GetWindowPlacement and SetWindowPlacement functions. Passing coordinates + to functions which expect screen coordinates (such as SetWindowPos) will result + in the window appearing in the wrong location. For example, if the taskbar is at + the top of the screen, saving window coordinates using GetWindowPlacement and + restoring them using SetWindowPos causes the window to appear to "creep" up the screen. + + We were using GetWindowPlacement with MoveWindow (in SetLayout) which was causing + "creep" when the taskbar was at the top of the screen. Replaced GetWindowPlacement + with the following GetWindowRect call. + */ + + CRect theRect; + GetWindowRect(&theRect); + + theState.SetPosition(CPt(theRect.left, theRect.top)); + theState.SetSize(CPt(theRect.right - theRect.left, theRect.bottom - theRect.top)); + } + theState.SetVisible(IsWindowVisible() ? true : false); + + theState.SaveState(); + + // Force a recalc of the layout to ensure that everything is correct with the docking + RecalcLayout(TRUE); + } +#endif +} + +//============================================================================== +/** + * Restore all the information regarding the layout of the main frame and its palettes. + * This will make the window be located at the last stored location. + * On one hand, there is the main frame which continues to use the original + * CPaletteState scheme. Now there is also the control bars/palettes that dock. + * These all now use the MFC path for serialization to the registry. This happens + * on startup. + */ +void CMainFrame::RestoreLayout() +{ +#ifdef KDAB_TEMPORARILY_REMOVED + CPaletteState theState("MainWindow"); + theState.LoadState(); + + SetLayout(theState); + + if (!m_PaletteManager->Load()) + m_PaletteManager->RestoreDefaults(true); + + // Force a recalc for the layout for the docking palettes to work + RecalcLayout(TRUE); +#endif +} + +//============================================================================== +/** + * Set the state of this window to the specified state. + */ +void CMainFrame::SetLayout(const CPaletteState &inState) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + CPt thePosition = inState.GetPosition(); + CPt theSize = inState.GetSize(); + bool isVisible = inState.IsVisible(); + + CRect theWindowRect(thePosition.x, thePosition.y, thePosition.x + theSize.x, + thePosition.y + theSize.y); + + // Relocate the window to the new location + MoveWindow(theWindowRect); + + if (inState.IsMaximized()) + ::AfxGetApp()->m_nCmdShow = SW_SHOWMAXIMIZED; + ShowWindow(::AfxGetApp()->m_nCmdShow); + ShowWindow((isVisible ? SW_SHOW : SW_HIDE)); +#endif + // UpdateWindow(); +} + +//============================================================================== +/** + * OnEditRedo: calls handleRedoOperation + */ +//============================================================================== +void CMainFrame::OnEditRedo() +{ + g_StudioApp.GetCore()->GetCmdStack()->Redo(); +} + +//============================================================================== +/** + * OnEditUndo: calls HandleUndoOperation + */ +//============================================================================== +void CMainFrame::OnEditUndo() +{ + g_StudioApp.GetCore()->GetCmdStack()->Undo(); +} + +//============================================================================== +/** + * OnUpdateEditUndo: Handler for ID_EDIT_UNDO message + * + * @param pCmndUI The UI element that generated the message + */ +void CMainFrame::OnUpdateEditUndo() +{ + const QString undoDescription = QObject::tr("Undo %1\tCtrl+Z").arg(g_StudioApp.GetCore()->GetCmdStack()->GetUndoDescription()); + m_ui->action_Undo->setEnabled(g_StudioApp.CanUndo()); + m_ui->action_Undo->setText(undoDescription); +} + +//============================================================================== +/** + * OnUpdateEditRedo: handles the message ID_EDIT_REDO + * + * @param pCmndUI The UI element that generated the message + */ +void CMainFrame::OnUpdateEditRedo() +{ + const QString redoDescription = QObject::tr("Redo %1\tCtrl+Y").arg(g_StudioApp.GetCore()->GetCmdStack()->GetRedoDescription()); + m_ui->action_Redo->setEnabled(g_StudioApp.CanRedo()); + m_ui->action_Redo->setText(redoDescription); +} + +//============================================================================== +/** + * OnEditCopy: Handles the Copy message + * + * Tells the doc to copy the selected keyframes. + */ +void CMainFrame::OnEditCopy() +{ + g_StudioApp.OnCopy(); +} + +//============================================================================== +/** + * OnUpdateEditCopy: Handle the update UI command for the copy button and menu item + * + * If there are keyframes selected, the button is enabled, otherwise, it is + * disabled. + * + * @param pCmndUI The UI element that generated the message + */ +void CMainFrame::OnUpdateEditCopy() +{ + if (g_StudioApp.CanCopy()) { + Q3DStudio::CString theDescription; + theDescription.Format(::LoadResourceString(IDS_MENU_WIN_COPY_FORMAT), + static_cast(g_StudioApp.GetCopyType())); + + m_ui->action_Copy->setText(theDescription.toQString()); + m_ui->action_Copy->setEnabled(true); + } else { + m_ui->action_Copy->setEnabled(false); + } +} + +//============================================================================== +/** + * OnEditCut: Handles the Cut message + * + * Tells the doc to cut the selected keyframes. + */ +void CMainFrame::OnEditCut() +{ + g_StudioApp.OnCut(); +} + +//============================================================================== +/** + * OnUpdateEditCut: Handle the update UI command for the cut button and menu item + * + * If there are keyframes selected, the button is enabled, otherwise, it is + * disabled. + * + * @param pCmndUI The UI element that generated the message + */ +void CMainFrame::OnUpdateEditCut() +{ + if (g_StudioApp.CanCut()) { + Q3DStudio::CString theDescription; + theDescription.Format(::LoadResourceString(IDS_MENU_WIN_CUT_FORMAT), + static_cast(g_StudioApp.GetCopyType())); + + m_ui->action_Cut->setText(theDescription.toQString()); + m_ui->action_Cut->setEnabled(true); + } else { + m_ui->action_Cut->setEnabled(false); + } +} + +//============================================================================== +/** + * OnEditPaste: Handles the Paste command + * + * Tells the doc to paste the copied keyframes at the current playhead time, on + * the currently selected object. + */ +void CMainFrame::OnEditPaste() +{ + g_StudioApp.OnPaste(); +} + +//============================================================================== +/** + * OnUpdateEditPaste: Handle the update UI command for the paste button and menu item + * + * If there we can perform a keyframe paste, the button is enabled, otherwise, it is + * disabled. + * + * @param pCmndUI The UI element that generated the message + */ +void CMainFrame::OnUpdateEditPaste() +{ + if (g_StudioApp.CanPaste()) { + Q3DStudio::CString theUndoDescription; + theUndoDescription.Format(::LoadResourceString(IDS_MENU_WIN_PASTE_FORMAT), + static_cast(g_StudioApp.GetPasteType())); + + m_ui->action_Paste->setText(theUndoDescription.toQString()); + + m_ui->action_Paste->setEnabled(true); + } else { + m_ui->action_Paste->setEnabled(false); + } +} + +#ifdef KDAB_TEMPORARILY_REMOVED +//============================================================================= +/** + * Router for forwarding messages onto the MsgRouter. + * This is used for posting messages between threads. + */ +LRESULT CMainFrame::OnMsgRouterMsg(WPARAM inWParam, LPARAM inLParam) +{ + CMsgRouter::GetInstance()->HandleMessage(inWParam, inLParam); + + return TRUE; +} +#endif + +//============================================================================= +/** + * Called when a tool mode changes from a modifier key + */ +void CMainFrame::OnUpdateToolChange() +{ + long theSelectMode = g_StudioApp.GetSelectMode(); + m_ui->actionGroup_Select_Tool->setChecked(theSelectMode == STUDIO_SELECTMODE_GROUP); + m_ui->actionItem_Select_Tool->setChecked(theSelectMode == STUDIO_SELECTMODE_ENTITY); + + // See what tool mode we are in and change checks accordingly + long theToolMode = g_StudioApp.GetToolMode(); + m_ui->actionPosition_Tool->setChecked(theToolMode == STUDIO_TOOLMODE_MOVE); + m_ui->actionRotation_Tool->setChecked(theToolMode == STUDIO_TOOLMODE_ROTATE); + m_ui->actionScale_Tool->setChecked(theToolMode == STUDIO_TOOLMODE_SCALE); + m_ui->actionLocal_Global_Manipulators->setChecked(g_StudioApp.GetMinpulationMode() + == StudioManipulationModes::Global); + +#ifdef INCLUDE_EDIT_CAMERA + m_ui->actionPan_Tool->setChecked(theToolMode == STUDIO_TOOLMODE_CAMERA_PAN); + m_ui->actionOrbit_Tool->setChecked(theToolMode == STUDIO_TOOLMODE_CAMERA_ROTATE); + m_ui->actionZoom_Tool->setChecked(theToolMode == STUDIO_TOOLMODE_CAMERA_ZOOM); + +/*CEditCameraContainer* theEditCameras = g_StudioApp.GetCore()->GetDoc()->GetEditCameraContainer( ); +CSEditCamera* theActiveEditCamera = theEditCameras->GetActiveEditCamera( ); +bool theIsEditView = !m_SceneView->IsDeploymentView( ); +m_EditCamerasBar.GetToolBarCtrl( ).EnableButton( ID_TOOL_EDITCAMERA_ROTATE, ( theActiveEditCamera && +theActiveEditCamera->Is3D( ) ) ); +m_EditCamerasBar.GetToolBarCtrl( ).EnableButton( ID_TOOL_EDITCAMERA_PAN, theIsEditView ); +m_EditCamerasBar.GetToolBarCtrl( ).EnableButton( ID_TOOL_EDITCAMERA_ZOOM, theIsEditView ); +m_EditCamerasBar.GetToolBarCtrl( ).EnableButton( ID_EDITCAMERA_ZOOMEXTENT, theIsEditView ); + +m_EditCamerasBar.GetToolBarCtrl( ).EnableButton( ID_TOOL_EDITVIEW_FILLMODE, theIsEditView ); +m_EditCamerasBar.GetToolBarCtrl( ).CheckButton( ID_TOOL_EDITVIEW_FILLMODE, theIsEditView && +theEditCameras->GetEditViewFillMode( ) ); +*/ +#endif +} + +//============================================================================== +/** + * OnTimelineSettimebarcolor: Handles the ID_TIMELINE_SETTIMEBARCOLOR message. + * + * Called when the user clicks on Timeline->Change Time Bar Color. Changes + * the currently selected timebar's color. + */ +void CMainFrame::OnTimelineSetTimeBarColor() +{ + ITimelineTimebar *theTimelineTimebar = GetSelectedTimelineTimebar(); + if (theTimelineTimebar != NULL) { + CColor theColor = theTimelineTimebar->GetTimebarColor(); + + if (g_StudioApp.GetDialogs()->PromptObjectTimebarColor(theColor)) + theTimelineTimebar->SetTimebarColor(theColor); + } +} + +//============================================================================== +/** + * OnUpdateTimelineSetTimeBarColor: Handles the update UI message for the + * "Change Time Bar Color" menu item. + * + * If the currently selected object is an item in the timeline and it has a + * time bar, this menu item is enabled. Otherwise, the menu item is disabled. + * + * @param pCmndUI Pointer to the ui object that generated this update message. + */ +void CMainFrame::OnUpdateTimelineSetTimeBarColor() +{ + m_ui->actionChange_Time_Bar_Color->setEnabled(g_StudioApp.CanChangeTimebarColor()); +} + +//============================================================================== +/** + * OnTimelineSetChangedKeyframe: Handles the ID_TIMELINE_SETCHANGEDKEYFRAME message. + * + * Calls the StudioDoc handler to insert keyframes for animatable properties that + * have changed. + */ +void CMainFrame::OnTimelineSetChangedKeyframe() +{ + g_StudioApp.HandleSetChangedKeys(); +} + +//============================================================================== +/** + * OnTimelineDeleteSelectedKeyframes: Handles the ID_TIMELINE_DELETESELECTEDKEYFRAMES + * message. + * + * Deletes all currently selected keyframes. + */ +void CMainFrame::OnTimelineDeleteSelectedKeyframes() +{ + g_StudioApp.DeleteSelectedKeys(); +} + +//============================================================================== +/** + * OnUpdateTimelineDeleteSelectedKeyframes: Handles the update UI message for + * the "Delete Selected Keyframe(s)" message. + * + * If there are currently keyframes selected, the menu item is enabled. Otherwise, + * the menu item is disabled. + * + * @param pCmdUI The UI element that generated this message + */ +void CMainFrame::OnUpdateTimelineDeleteSelectedKeyframes() +{ + m_ui->actionDelete_Selected_Keyframe_s->setEnabled(g_StudioApp.CanCopy()); +} + +//============================================================================== +/** + * OnUpdateTimelineSetInterpolation: Handles the update UI message for + * the "Set Interpolation" message. + * + * If there are currently keyframes selected, this menu item is enabled, otherwise + * it is disabled. + * + * @param pCmdUI The UI element that generated this message + */ +void CMainFrame::OnUpdateTimelineSetInterpolation() +{ + m_ui->actionSet_Interpolation->setEnabled(g_StudioApp.GetCore()->GetDoc()->GetKeyframesManager()->HasSelectedKeyframes()); +} + +//============================================================================== +/** + * OnEditDuplicate: Handles the ID_EDIT_DUPLICATE message. + * + * Pass through to the doc. + */ +void CMainFrame::OnEditDuplicate() +{ + g_StudioApp.HandleDuplicateCommand(); +} + +//============================================================================== +/** + * OnUpdateEditDuplicate: Handles the UPDATE COMMAND UI message for this menu item. + * + * If the currently selected object is not null, and it is not in the library, + * then the user can duplicate the object and the menu item is enabled. Otherwise, + * it is disabled. + */ +void CMainFrame::OnUpdateEditDuplicate() +{ + m_ui->action_Duplicate_Object->setEnabled(g_StudioApp.CanDuplicateObject()); +} + +//============================================================================= +/** + * Command handler for the File Open menu and toolbar options. + * This will save the file, if the file has not been saved before this will + * do a save as operation. + */ +void CMainFrame::OnFileOpen() +{ + g_StudioApp.OnFileOpen(); +} + +//============================================================================= +/** + * Command handler for the File Save menu and toolbar options. + * This will save the file, if the file has not been saved before this will + * do a save as operation. + */ +void CMainFrame::OnFileSave() +{ + g_StudioApp.OnSave(); +} + +void CMainFrame::OnUpdateFileSave() +{ + m_ui->action_Save->setEnabled(g_StudioApp.GetCore()->GetDoc()->IsModified()); +} +//============================================================================= +/** + * Command handler for the File Save As menu option. + * This will prompt the user for a location to save the file out to then + * will perform the save. + */ +void CMainFrame::OnFileSaveAs() +{ + g_StudioApp.OnSaveAs(); +} + +//============================================================================= +/** + * Command handler for the File Save a Copy menu option. + * This will prompt the user for a location to save the file out to then + * save a copy, leaving the original file open in the editor. + */ +void CMainFrame::OnFileSaveCopy() +{ + g_StudioApp.OnSaveCopy(); +} + +//============================================================================= +/** + * Command handler for the New Document menu option. + * This will create a new default document. + */ +void CMainFrame::OnFileNew() +{ + g_StudioApp.OnFileNew(); +} + + +//============================================================================== +/** + * Overrides the close method to prompt if the document is modified. + */ +void CMainFrame::closeEvent(QCloseEvent *event) +{ + QSettings settings; + settings.setValue("mainWindowGeometry", saveGeometry()); + settings.setValue("mainWindowState", saveState()); + QMainWindow::closeEvent(event); + + if (g_StudioApp.GetCore()->GetDoc()->IsModified()) { + CDialogs::ESavePromptResult theResult = g_StudioApp.GetDialogs()->PromptForSave(); + if (theResult == CDialogs::SAVE_FIRST) { + // If the save was canceled or failed then do not exit. + if (!g_StudioApp.OnSave()) + return; + } + // On cancel ditch out of here and abort exit. Abort! Abort! + else if (theResult == CDialogs::CANCEL_OPERATION) { + event->ignore(); + return; + } + } + + // Tell the app to shutdown, do it here so it does not rely on static destructor. + g_StudioApp.PerformShutdown(); +} + +//============================================================================== +/** + * Displays the preferences dialog and can change program settings. + */ +void CMainFrame::OnEditApplicationPreferences() +{ + EditPreferences(PAGE_STUDIOAPPPREFERENCES); +} + +//============================================================================== +/** + * Displays the preferences dialog and can change program settings. + */ +void CMainFrame::OnEditPresentationPreferences() +{ + EditPreferences(PAGE_STUDIOPROJECTSETTINGS); +} + +//============================================================================== +/** + * Displays the preferences dialog and can change subpresentation settings. + */ +void CMainFrame::OnEditSubPresentations() +{ + QString dir = g_StudioApp.GetCore()->GetDoc()->GetDocumentDirectory().toQString(); + + CSubPresentationsDlg dlg(QDir::toNativeSeparators(dir), + g_StudioApp.m_subpresentations); + dlg.exec(); + if (dlg.result() == QDialog::Accepted) { + g_StudioApp.m_subpresentations = dlg.subpresentations(); + g_StudioApp.SaveUIAFile(); + } +} + +//============================================================================== +/** + * EditPreferences: Displays the presentation settings property sheet with + * the specified active page. + * + * Used for editing the application and project settings. + * + * @param inPageIndex The page index to select when displayed. + */ +void CMainFrame::EditPreferences(short inPageIndex) +{ + // Set the active page based on the inPageIndex + CStudioPreferencesPropSheet thePropSheet(::LoadResourceString(IDS_STUDIOPREFSTITLE).toQString(), + this, inPageIndex); + + // CStudioProjectSettings *theProjectSettings = g_StudioApp.GetCore()->GetStudioProjectSettings(); + + // Q3DStudio::CString theAuthorName theAuthorName = theProjectSettings->GetAuthor(); + // Q3DStudio::CString theCompanyName theCompanyName = theProjectSettings->GetCompany(); + + // Display the CStudioPreferencesPropSheet + int thePrefsReturn = thePropSheet.exec(); + + // Ugly hack to fix some bug + m_SceneView->OnEditCameraChanged(); + + if (thePrefsReturn == PREFS_RESET_DEFAULTS) { + // Restore default values + g_StudioApp.SetAutosetKeyframes(true); + CStudioPreferences::SetBoundingBoxesOn(true); + CStudioPreferences::SetTimebarDisplayTime(true); + g_StudioApp.GetCore()->GetDoc()->SetDefaultKeyframeInterpolation(true); + CStudioPreferences::SetNudgeAmount(10.0f); + CStudioPreferences::SetSnapRange(10); + CStudioPreferences::SetTimelineSnappingGridActive(true); + CStudioPreferences::SetTimelineSnappingGridResolution(SNAPGRID_SECONDS); +// Edit Cameras +#ifdef INCLUDE_EDIT_CAMERA + CColor theDefaultBgColor(CStudioPreferences::EDITVIEW_DEFAULTBGCOLOR); + CStudioPreferences::SetEditViewBackgroundColor(theDefaultBgColor); + // g_StudioApp.GetCore()->GetDoc()->SetEditViewBackgroundColor( theDefaultBgColor ); + CStudioPreferences::SetPreferredStartupView( + CStudioPreferences::PREFERREDSTARTUP_DEFAULTINDEX); +#endif + + if (m_PaletteManager) + m_PaletteManager->RestoreDefaults(); + + RecheckSizingMode(); + + // Remove keys related to the ObjRef and PropRef Pickers + CPreferences::GetUserPreferences(::LoadResourceString(IDS_PREFS_REFERENCECONTROLS)) + .RemoveKey("ObjectReferenceWidth"); + CPreferences::GetUserPreferences(::LoadResourceString(IDS_PREFS_REFERENCECONTROLS)) + .RemoveKey("ObjectReferenceHeight"); + CPreferences::GetUserPreferences(::LoadResourceString(IDS_PREFS_REFERENCECONTROLS)) + .RemoveKey("ObjectReferenceXPos"); + CPreferences::GetUserPreferences(::LoadResourceString(IDS_PREFS_REFERENCECONTROLS)) + .RemoveKey("ObjectReferenceYPos"); + CPreferences::GetUserPreferences(::LoadResourceString(IDS_PREFS_REFERENCECONTROLS)) + .RemoveKey("PropertyReferenceWidth"); + CPreferences::GetUserPreferences(::LoadResourceString(IDS_PREFS_REFERENCECONTROLS)) + .RemoveKey("PropertyReferenceHeight"); + CPreferences::GetUserPreferences(::LoadResourceString(IDS_PREFS_REFERENCECONTROLS)) + .RemoveKey("PropertyReferenceXPos"); + CPreferences::GetUserPreferences(::LoadResourceString(IDS_PREFS_REFERENCECONTROLS)) + .RemoveKey("PropertyReferenceYPos"); + + // Also clear out the viewer's settings file + Q3DStudio::CFilePath theFilePath(Q3DStudio::CFilePath::CombineBaseAndRelative( + Q3DStudio::CFilePath::GetUserApplicationDirectory(), + "UIComposer\\UICViewerSettings.txt")); + theFilePath.DeleteThisFile(); + } +} + +//============================================================================== +/** + * OnToolAutosetkeys: Called when the Autoset Keyframe button is pressed. + * Calls the doc to turn off or on the Autoset Keyframe preference. + */ +void CMainFrame::OnToolAutosetkeys() +{ + // Toggle autoset keyframes to the opposite of what it's currently set as + g_StudioApp.SetAutosetKeyframes(!CStudioPreferences::IsAutosetKeyframesOn()); +} + +//============================================================================== +/** + * OnUpdateToolAutosetkeys: Updates the UI associated with this button. + * Checks or unchecks this button on the toolbar, depending on the current + * tool mode, and whether or not the button is enabled. + * @param pCmdUI Pointer to the button that generated the message. + */ +void CMainFrame::OnUpdateToolAutosetkeys() +{ + // If autoset keyframes is on + m_ui->actionAutoset_Keyframes->setChecked(CStudioPreferences::IsAutosetKeyframesOn()); +} + +//========================================================================== +/** + * Called when the presentation is being played in Studio. Updates the play + * button on the main frame. + */ +void CMainFrame::OnPlayStart() +{ + // Update the play button since this doesn't always happen automatically + m_ui->actionPlay->setChecked(true); + + if (m_PlaybackFlag == false) { + m_PlaybackFlag = true; + + // g_StudioApp.GetCore()->GetDoc()->SetPlayMode( PLAYMODE_PLAY ); + + m_playbackTimer.start(); + } +} + +//========================================================================== +/** + * Called when the presentation stops being played in Studio. Updates the play + * button on the main frame. + */ +void CMainFrame::OnPlayStop() +{ + // Update the play button since this doesn't always happen automatically + m_ui->actionPlay->setChecked(false); + + if (m_PlaybackFlag == true) { + m_PlaybackFlag = false; + m_playbackTimer.stop(); + // g_StudioApp.GetCore()->GetDoc()->SetPlayMode( PLAYMODE_STOP ); + } +} + +//========================================================================== +/** + * Called when the presentation time changes. Not handled by this class, + * but included because the base class requires it to be implemented. + */ +void CMainFrame::OnTimeChanged(long inTime) +{ + Q_UNUSED(inTime); + // Do nothing +} + +//============================================================================== +/** + * Handles pressing the play button. + */ +void CMainFrame::OnPlaybackPlay() +{ + g_StudioApp.PlaybackPlay(); +} + +//============================================================================== +/** + * Handles pressing of the stop button. + */ +void CMainFrame::OnPlaybackStop() +{ + g_StudioApp.PlaybackStopNoRestore(); +} + +//============================================================================== +/** + * Handles pressing the preview button. + */ +void CMainFrame::OnPlaybackPreview() +{ + if (m_remoteProject->isConnected()) + CPreviewHelper::OnDeploy(*m_remoteProject); + else + CPreviewHelper::OnPreview(); +} + +//============================================================================== +/** + * Handles the update ui message for the preview button. + * Adding more UI updating here would just be redundant. + * @param inCmdUI Pointer to the UI element that needs updating + */ +void CMainFrame::OnUpdatePlaybackPreview() +{ +} + +//============================================================================== +/** + * Handles the update ui message for the play button. Does nothing because the + * button state is being updated manually in OnPlayStart() and OnPlayStop. + * Adding more UI updating here would just be redundant. + * @param inCmdUI Pointer to the UI element that needs updating + */ +void CMainFrame::OnUpdatePlaybackPlay() +{ +} + +//============================================================================== +/** + * Handles pressing the rewind button. + */ +void CMainFrame::OnPlaybackRewind() +{ + g_StudioApp.PlaybackRewind(); +} + +//============================================================================== +/** + * Handles the update ui message for the rewind button. Does nothing because + * no additional ui handling is necessary for this button. + * @param inCmdUI Pointer to the UI element that needs updating + */ +void CMainFrame::OnUpdatePlaybackRewind() +{ +} + +//============================================================================== +/** + * Handles the update ui message for the stop button. Doesn't do anything + * because no special ui handling is necessary for the stop button. + * @param inCmdUI Pointer to the UI element that needs updating + */ +void CMainFrame::OnUpdatePlaybackStop() +{ +} + +//============================================================================== +/** + * Registers all the keys it will need for shortcuts, also telsl children to register theirs + * @param inHotKeys the hotkeys to with which to register + */ +void CMainFrame::RegisterGlobalKeyboardShortcuts(CHotKeys *inHotKeys) +{ + inHotKeys->RegisterKeyEvent(new CDynHotKeyConsumer(this, &CMainFrame::OnToolMove), + 0, Qt::Key_W); + inHotKeys->RegisterKeyEvent(new CDynHotKeyConsumer(this, &CMainFrame::OnToolRotate), + 0, Qt::Key_R); + inHotKeys->RegisterKeyEvent(new CDynHotKeyConsumer(this, &CMainFrame::OnToolScale), + 0, Qt::Key_E); + inHotKeys->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CMainFrame::OnViewBoundingBoxes), + Qt::ControlModifier, Qt::Key_B); + inHotKeys->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CMainFrame::OnViewPivotPoint), + Qt::ControlModifier | Qt::AltModifier, Qt::Key_P); + inHotKeys->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CMainFrame::OnEditPresentationPreferences), + Qt::ControlModifier, Qt::Key_P); + inHotKeys->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CMainFrame::OnOpenMostRecentlyUsedDocument), + Qt::ControlModifier | Qt::AltModifier | Qt::ShiftModifier, Qt::Key_P); + + inHotKeys->RegisterKeyEvent(new CDynHotKeyConsumer(this, &CMainFrame::OnShowAction), + Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_A); + inHotKeys->RegisterKeyEvent(new CDynHotKeyConsumer(this, &CMainFrame::OnShowBasic), + Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_B); + inHotKeys->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CMainFrame::OnShowInspector), + Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_I); + inHotKeys->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CMainFrame::OnShowProject), + Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_P); + inHotKeys->RegisterKeyEvent(new CDynHotKeyConsumer(this, &CMainFrame::OnShowSlide), + Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_D); + inHotKeys->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CMainFrame::OnShowTimeline), + Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_T); + inHotKeys->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CMainFrame::OnViewGuidesRulers), + Qt::ControlModifier, Qt::Key_Semicolon); + inHotKeys->RegisterKeyEvent(new CDynHotKeyConsumer(this, &CMainFrame::OnLockGuides), + Qt::ControlModifier | Qt::AltModifier, Qt::Key_Semicolon); + +#ifdef INCLUDE_EDIT_CAMERA + inHotKeys->RegisterKeyDownEvent( + new CDynHotKeyConsumer(this, &CMainFrame::HandleEditViewFillModeKey), 0, + Qt::Key_F3); + inHotKeys->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CMainFrame::HandleEditCameraZoomExtent), 0, Qt::Key_F); +#endif + + inHotKeys->RegisterKeyDownEvent( + new CDynHotKeyConsumer(this, &CMainFrame::OnPlaybackPreview), 0, + Qt::Key_F5); + + m_SceneView->RegisterGlobalKeyboardShortcuts(inHotKeys); + + CTimelineControl *theTimelineControl = GetTimelineControl(); + if (theTimelineControl) + theTimelineControl->RegisterGlobalKeyboardShortcuts(inHotKeys); +} + +//============================================================================== +/** + * OnUpdateToolMove: Updates the UI associated with this button. + * + * Checks or unchecks this button on the toolbar, depending on the current + * tool mode, and whether or not the button is enabled. + * + * @param pCmdUI Pointer to the button that generated the message. + */ +//============================================================================== +void CMainFrame::OnUpdateToolMove() +{ + long theCurrentToolSettings = g_StudioApp.GetToolMode(); + + // If the current tool mode matches this button + // If the button is currently enabled + m_ui->actionPosition_Tool->setChecked(theCurrentToolSettings == STUDIO_TOOLMODE_MOVE && m_ui->actionPosition_Tool->isEnabled()); +} + +//============================================================================== +/** + * OnUpdateToolRotate: Updates the UI associated with this button. + * + * Checks or unchecks this button on the toolbar, depending on the current + * tool mode, and whether or not the button is enabled. + * + * @param pCmdUI Pointer to the button that generated the message. + */ +void CMainFrame::OnUpdateToolRotate() +{ + long theCurrentToolSettings = g_StudioApp.GetToolMode(); + + // If the current tool mode matches this button + // If the button is currently enabled + m_ui->actionRotation_Tool->setChecked(theCurrentToolSettings == STUDIO_TOOLMODE_ROTATE && m_ui->actionRotation_Tool->isEnabled()); +} + +//============================================================================== +/** + * OnUpdateToolScale: Updates the UI associated with this button. + * + * Checks or unchecks this button on the toolbar, depending on the current + * tool mode, and whether or not the button is enabled. + * + * @param pCmdUI Pointer to the button that generated the message. + */ +void CMainFrame::OnUpdateToolScale() +{ + long theCurrentToolSettings = g_StudioApp.GetToolMode(); + + // If the current tool mode matches this button + // If the button is currently enabled + m_ui->actionScale_Tool->setChecked(theCurrentToolSettings == STUDIO_TOOLMODE_SCALE && m_ui->actionScale_Tool->isEnabled()); +} + +//============================================================================== +/** + * OnUpdateToolScale: Updates the UI associated with this button. + * + * Checks or unchecks this button on the toolbar, depending on the current + * tool mode, and whether or not the button is enabled. + * + * @param pCmdUI Pointer to the button that generated the message. + */ +void CMainFrame::OnUpdateToolGlobalManipulators() +{ + StudioManipulationModes::Enum theMode = g_StudioApp.GetMinpulationMode(); + + // If the current tool mode matches this button + // If the button is currently enabled + m_ui->actionLocal_Global_Manipulators->setChecked(theMode == StudioManipulationModes::Global && m_ui->actionLocal_Global_Manipulators->isEnabled()); +} + +//============================================================================== +/** + * OnToolMove: Called when the Move button is pressed. + * Sets the current tool mode and changes the cursor. + */ +void CMainFrame::OnToolMove() +{ + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_MOVE); + m_SceneView->SetToolMode(STUDIO_TOOLMODE_MOVE); +} + +//============================================================================== +/** + * OnToolRotate: Called when the Rotate button is pressed. + * Sets the current tool mode and changes the cursor. + */ +void CMainFrame::OnToolRotate() +{ + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_ROTATE); + m_SceneView->SetToolMode(STUDIO_TOOLMODE_ROTATE); +} + +//============================================================================== +/** + * OnToolScale: Called when the Scale button is pressed. + * Sets the current tool mode and changes the cursor. + */ +void CMainFrame::OnToolScale() +{ + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_SCALE); + m_SceneView->SetToolMode(STUDIO_TOOLMODE_SCALE); +} + +void CMainFrame::OnToolGlobalManipulators() +{ + if (m_ui->actionLocal_Global_Manipulators->isChecked()) + g_StudioApp.SetMinpulationMode(StudioManipulationModes::Global); + else + g_StudioApp.SetMinpulationMode(StudioManipulationModes::Local); + + g_StudioApp.GetRenderer().RequestRender(); +} + +//============================================================================== +/** + * OnUpdateToolGroupSelection: Updates the UI associated with this button. + * + * Checks or unchecks this button on the toolbar, depending on the current + * tool mode, and whether or not the button is enabled. + * + * @param pCmdUI Pointer to the button that generated the message. + */ +void CMainFrame::OnUpdateToolGroupSelection() +{ + long theCurrentSelectSettings = g_StudioApp.GetSelectMode(); + + // If the current tool mode matches this button + // If the button is currently enabled + m_ui->actionGroup_Select_Tool->setChecked(theCurrentSelectSettings == STUDIO_SELECTMODE_GROUP && m_ui->actionGroup_Select_Tool->isEnabled()); +} + +//============================================================================== +/** + * OnUpdateToolItemSelection: Updates the UI associated with this button. + * + * Checks or unchecks this button on the toolbar, depending on the current + * tool mode, and whether or not the button is enabled. + * + * @param pCmdUI Pointer to the button that generated the message. + */ +void CMainFrame::OnUpdateToolItemSelection() +{ + long theCurrentSelectSettings = g_StudioApp.GetSelectMode(); + + // If the current tool mode matches this button + // If the button is currently enabled + m_ui->actionItem_Select_Tool->setChecked(theCurrentSelectSettings == STUDIO_SELECTMODE_ENTITY && m_ui->actionItem_Select_Tool->isEnabled()); +} + +//============================================================================== +/** + * Called when the edit camera Zoom Extent button is pressed. + * Inform the current active edit camera to toggle itself. + */ +void CMainFrame::OnEditCameraZoomExtent() +{ + if (g_StudioApp.GetRenderer().GetEditCamera() >= 0) + g_StudioApp.GetRenderer().EditCameraZoomToFit(); + else + g_StudioApp.SetAuthorZoom(!g_StudioApp.IsAuthorZoom()); +} + +//============================================================================== +/** + * Called when the "Zoom Extent" keyboard shortcut is pressed. + * Inform the current active edit camera to toggle itself. + */ +//============================================================================== +void CMainFrame::HandleEditCameraZoomExtent() +{ + OnEditCameraZoomExtent(); +} + +//============================================================================== +/** + * Called when the Pan Edit Camera button is pressed. + * Inform the current active edit camera on their tool mode. + */ +void CMainFrame::OnEditCameraPan() +{ + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_PAN); + m_SceneView->SetToolMode(STUDIO_TOOLMODE_CAMERA_PAN); +} + +//============================================================================== +/** + * Called when the Rotate Edit Camera button is pressed. + * Inform the current active edit camera on their tool mode. + */ +void CMainFrame::OnEditCameraRotate() +{ + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_ROTATE); + m_SceneView->SetToolMode(STUDIO_TOOLMODE_CAMERA_ROTATE); +} + +//============================================================================== +/** + * Called when the Zoom Edit Camera button is pressed. + * Inform the current active edit camera on their tool mode. + */ +void CMainFrame::OnEditCameraZoom() +{ + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_ZOOM); + m_SceneView->SetToolMode(STUDIO_TOOLMODE_CAMERA_ZOOM); +} + +//============================================================================== +/** + * Updates the UI associated with this button. + * + * Checks or unchecks this button on the toolbar, depending on the current + * settings of the current edit camera tool. + * + * @param pCmdUI Pointer to the button that generated the message. + */ +//============================================================================== +void CMainFrame::OnUpdateCameraZoomExtentAndAuthorZoom() +{ + if (m_SceneView == GetActiveView() && !m_SceneView->IsDeploymentView()) { + m_ui->actionFit_Selected->setChecked(false); + } else { + m_ui->actionFit_Selected->setChecked(g_StudioApp.IsAuthorZoom()); + } +} + +//============================================================================== +/** + * Updates the UI associated with this button. + * + * Checks or unchecks this button on the toolbar, depending on the current + * settings of the current edit camera tool. + * + * @param pCmdUI Pointer to the button that generated the message. + */ +//============================================================================== +void CMainFrame::OnUpdateEditCameraPan() +{ + if (m_SceneView == GetActiveView() && !m_SceneView->IsDeploymentView()) { + m_ui->actionPan_Tool->setEnabled(true); + + long theCurrentToolSettings = g_StudioApp.GetToolMode(); + m_ui->actionPan_Tool->setChecked(theCurrentToolSettings == STUDIO_TOOLMODE_CAMERA_PAN); + } else { + m_ui->actionPan_Tool->setEnabled(false); + m_ui->actionPan_Tool->setChecked(false); + } +} + +//============================================================================== +/** + * Updates the UI associated with this button. + * + * Checks or unchecks this button on the toolbar, depending on the current + * settings of the current edit camera tool. + * + * @param pCmdUI Pointer to the button that generated the message. + */ +//============================================================================== +void CMainFrame::OnUpdateEditCameraRotate() +{ + if (m_SceneView == GetActiveView() && !m_SceneView->IsDeploymentView() + && g_StudioApp.GetRenderer().DoesEditCameraSupportRotation( + g_StudioApp.GetRenderer().GetEditCamera())) { + m_ui->actionOrbit_Tool->setEnabled(true); + + long theCurrentToolSettings = g_StudioApp.GetToolMode(); + m_ui->actionOrbit_Tool->setChecked(theCurrentToolSettings == STUDIO_TOOLMODE_CAMERA_ROTATE); + } else { + m_ui->actionOrbit_Tool->setEnabled(false); + m_ui->actionOrbit_Tool->setChecked(false); + } +} + +//============================================================================== +/** + * Updates the UI associated with this button. + * + * Checks or unchecks this button on the toolbar, depending on the current + * settings of the current edit camera tool. + * + * @param pCmdUI Pointer to the button that generated the message. + */ +//============================================================================== +void CMainFrame::OnUpdateEditCameraZoom() +{ + if (m_SceneView == GetActiveView() && !m_SceneView->IsDeploymentView()) { + m_ui->actionZoom_Tool->setEnabled(true); + + long theCurrentToolSettings = g_StudioApp.GetToolMode(); + m_ui->actionZoom_Tool->setChecked(theCurrentToolSettings == STUDIO_TOOLMODE_CAMERA_ZOOM); + } else { + m_ui->actionZoom_Tool->setEnabled(false); + m_ui->actionZoom_Tool->setChecked(false); + } +} + +//============================================================================== +/** + * Called when the "Render geometry as solid/wireframe in edit view" button is pressed. + * Toggle the mode and update the studio preferences, also cache it in EditCameraContainer + */ +//============================================================================== +void CMainFrame::HandleEditViewFillModeKey() +{ + if (m_SceneView == GetActiveView() && !m_SceneView->IsDeploymentView()) { + OnEditViewFillMode(); + bool theEditViewFillMode = g_StudioApp.GetRenderer().IsEditLightEnabled(); + m_ui->actionShading_Mode->setChecked(theEditViewFillMode); + } +} + +//============================================================================== +/** + * Called when the "Render geometry as solid/wireframe in edit view" button is pressed. + * Toggle the mode and update the studio preferences, also cache it in EditCameraContainer + */ +//============================================================================== +void CMainFrame::OnEditViewFillMode() +{ + bool theEditViewFillMode = !g_StudioApp.GetRenderer().IsEditLightEnabled(); + g_StudioApp.GetRenderer().SetEnableEditLight(theEditViewFillMode); +} + +//============================================================================== +/** + * Updates the UI associated with this button. + * + * Checks or unchecks this button on the toolbar, depending on the current + * settings of the "Render geometry as solid/wireframe in edit view". + * + * @param pCmdUI Pointer to the button that generated the message. + */ +//============================================================================== +void CMainFrame::OnUpdateEditViewFillMode() +{ + if (m_SceneView == GetActiveView() && !m_SceneView->IsDeploymentView()) { + m_ui->actionShading_Mode->setEnabled(true); + m_ui->actionShading_Mode->setChecked(g_StudioApp.GetRenderer().IsEditLightEnabled()); + } else { + m_ui->actionShading_Mode->setEnabled(false); + m_ui->actionShading_Mode->setChecked(false); + } +} + +void CMainFrame::OnViewGuidesRulers() +{ + g_StudioApp.GetRenderer().SetGuidesEnabled(!g_StudioApp.GetRenderer().AreGuidesEnabled()); + g_StudioApp.GetCore()->GetDispatch()->FireAuthorZoomChanged(); + m_SceneView->OnRulerGuideToggled(); +} + +void CMainFrame::OnUpdateViewGuidesRulers() +{ + m_ui->actionRulers_Guides->setEnabled(m_SceneView->IsDeploymentView()); + m_ui->actionRulers_Guides->setChecked(g_StudioApp.GetRenderer().AreGuidesEnabled()); +} + +void CMainFrame::OnClearGuides() +{ + g_StudioApp.ClearGuides(); +} + +void CMainFrame::OnUpdateClearGuides() +{ + bool enable = g_StudioApp.GetRenderer().AreGuidesEnabled() + && g_StudioApp.GetRenderer().AreGuidesEditable() && m_SceneView->IsDeploymentView(); + + m_ui->actionClear_Guides->setEnabled(enable); +} + +void CMainFrame::OnLockGuides() +{ + g_StudioApp.GetRenderer().SetGuidesEditable(!g_StudioApp.GetRenderer().AreGuidesEditable()); +} + +void CMainFrame::OnUpdateLockGuides() +{ + bool enable = g_StudioApp.GetRenderer().AreGuidesEnabled() && m_SceneView->IsDeploymentView(); + m_ui->actionLock_Guides->setEnabled(enable); + // Set to the inverse of guides editable. + m_ui->actionLock_Guides->setChecked(!g_StudioApp.GetRenderer().AreGuidesEditable()); +} + +void CMainFrame::timerEvent(QTimerEvent *event) +{ + if (event->timerId() == WM_STUDIO_TIMER) + g_StudioApp.GetTickTock().ProcessMessages(); + QMainWindow::timerEvent(event); +} + +void CMainFrame::OnViewAction() +{ + m_PaletteManager->ToggleControl(CPaletteManager::CONTROLTYPE_ACTION); + SaveLayout(); +} + +void CMainFrame::OnUpdateViewAction() +{ + m_ui->actionAction->setChecked( + m_PaletteManager->IsControlVisible(CPaletteManager::CONTROLTYPE_ACTION)); +} + +void CMainFrame::OnViewBasicObjects() +{ + m_PaletteManager->ToggleControl(CPaletteManager::CONTROLTYPE_BASICOBJECTS); + SaveLayout(); +} + +void CMainFrame::OnUpdateViewBasicObjects() +{ + m_ui->actionBasic_Objects->setChecked(m_PaletteManager->IsControlVisible(CPaletteManager::CONTROLTYPE_BASICOBJECTS)); +} + +void CMainFrame::OnViewInspector() +{ + m_PaletteManager->ToggleControl(CPaletteManager::CONTROLTYPE_INSPECTOR); + SaveLayout(); +} + +void CMainFrame::OnUpdateViewInspector() +{ + m_ui->actionInspector->setChecked( + m_PaletteManager->IsControlVisible(CPaletteManager::CONTROLTYPE_INSPECTOR)); +} + +void CMainFrame::OnViewProject() +{ + m_PaletteManager->ToggleControl(CPaletteManager::CONTROLTYPE_PROJECT); + SaveLayout(); +} + +void CMainFrame::OnUpdateViewProject() +{ + m_ui->actionProject->setChecked( + m_PaletteManager->IsControlVisible(CPaletteManager::CONTROLTYPE_PROJECT)); +} + +void CMainFrame::OnViewSlide() +{ + m_PaletteManager->ToggleControl(CPaletteManager::CONTROLTYPE_SLIDE); + SaveLayout(); +} + +void CMainFrame::OnUpdateViewSlide() +{ + m_ui->actionSlide->setChecked( + m_PaletteManager->IsControlVisible(CPaletteManager::CONTROLTYPE_SLIDE) ? TRUE : FALSE); +} + +//============================================================================== +/** + * Called when the View Inspector Palette menu item is chosen. + */ +void CMainFrame::OnViewTimeline() +{ + m_PaletteManager->ToggleControl(CPaletteManager::CONTROLTYPE_TIMELINE); + SaveLayout(); +} + +//============================================================================== +/** + * Checks or unchecks the menu item depending on if the view is available or not. + * @param pCmdUI Pointer to the UI element that generated the message. + */ +void CMainFrame::OnUpdateViewTimeline() +{ + m_ui->actionTimeline->setChecked( + m_PaletteManager->IsControlVisible(CPaletteManager::CONTROLTYPE_TIMELINE)); +} + +//============================================================================== +/** + * Called when the View Inspector Palette menu item is chosen. + */ +void CMainFrame::OnViewBoundingBoxes() +{ + CStudioPreferences::SetBoundingBoxesOn(!CStudioPreferences::IsBoundingBoxesOn()); + g_StudioApp.GetRenderer().RequestRender(); +} + +//============================================================================== +/** + * Checks or unchecks the menu item depending on if the view is available or not. + * @param pCmdUI Pointer to the UI element that generated the message. + */ +void CMainFrame::OnUpdateViewBoundingBoxes() +{ + m_ui->actionBounding_Boxes->setChecked(CStudioPreferences::IsBoundingBoxesOn()); +} + +//============================================================================== +/** + * Called when the View Pivot Point menu item is chosen. + */ +void CMainFrame::OnViewPivotPoint() +{ + CStudioPreferences::SetDisplayPivotPoint(!CStudioPreferences::ShouldDisplayPivotPoint()); + g_StudioApp.GetRenderer().RequestRender(); +} + +//============================================================================== +/** + * Checks or unchecks the menu item depending on if the view is available or not. + * @param pCmdUI Pointer to the UI element that generated the message. + */ +void CMainFrame::OnUpdateViewPivotPoint() +{ + m_ui->actionPivot_Point->setChecked(CStudioPreferences::ShouldDisplayPivotPoint()); +} + +//============================================================================== +/** + * Called when the View Wireframe menu item is chosen. + */ +void CMainFrame::OnViewWireframe() +{ + CStudioPreferences::SetWireframeModeOn(!CStudioPreferences::IsWireframeModeOn()); + g_StudioApp.GetRenderer().RequestRender(); +} + +//============================================================================== +/** + * Checks or unchecks the menu item depending on if the view is available or not. + * @param pCmdUI Pointer to the UI element that generated the message. + */ +void CMainFrame::OnUpdateViewWireframe() +{ + m_ui->actionWireframe->setChecked(CStudioPreferences::IsWireframeModeOn()); +} + +//============================================================================== +/** + * Checks or unchecks the menu item depending whether tooltips should be shown + * or not. + * @param inCmdUI Pointer to the UI element that generated the message. + */ +void CMainFrame::OnUpdateViewTooltips() +{ + m_ui->actionTooltips->setChecked(CStudioPreferences::ShouldShowTooltips()); +} + +//============================================================================== +/** + * Called when the "View->Tooltips" menu item is chosen. Toggles tooltips on + * and off for custom controls. + */ +void CMainFrame::OnViewTooltips() +{ + CStudioPreferences::SetShowTooltips(!CStudioPreferences::ShouldShowTooltips()); +} + +//============================================================================== +/** + * Called when the update message occurs for the Help->Help Topics menu item. + * If the help file exists, the menu item is enabled, otherwise it's disabled. + * @param inCmdUI UI element that generated the message + */ +void CMainFrame::OnUpdateHelpIndex() +{ + CUICFile theFile(g_StudioApp.m_pszHelpFilePath); + m_ui->action_Reference_Manual->setEnabled(theFile.Exists()); +} + +//============================================================================== +/** + * Handles the ID_HELP_INDEX command. Opens the online help for Studio. + */ +void CMainFrame::OnHelpIndex() +{ + CUICFile theFile(g_StudioApp.m_pszHelpFilePath); + if (theFile.Exists()) + QDesktopServices::openUrl(QUrl::fromLocalFile(theFile.GetAbsolutePath().toQString())); +} + +//============================================================================== +/** + * Handles the ID_HELP_VISIT_QT command. Opens the Qt Web site. + */ +void CMainFrame::OnHelpVisitQt() +{ + Q3DStudio::CString theWebSite(::LoadResourceString(IDS_HELP_VISIT_QT)); + QDesktopServices::openUrl(QUrl(theWebSite.toQString())); +} + +//============================================================================== +/** + * Opens the tutorial. + */ +void CMainFrame::OnHelpOpenTutorial() +{ + StudioTutorialWidget tutorial(false); + tutorial.exec(); +} + +//============================================================================== +/** + * OnHelpBehaviorReference: Handles the ID_HELP_BEHAVIORREFERENCE message. + * Called when the Behavior Reference menu item is chosen inside the Help menu. + * Opens the HTML file to display the Behavior help. + */ +void CMainFrame::OnHelpBehaviorReference() +{ + CUICFile theFile(CUICFile::GetApplicationDirectory(), + ::LoadResourceString(IDS_HELP_BEHAVIORREFERENCE)); + if (theFile.Exists()) { + g_StudioApp.GetCore()->GetDispatch()->FireOnNavigate( + Q3DStudio::CString::fromQString(theFile.GetURL().path()), true); + SaveLayout(); + } +} + +//============================================================================== +/** + * Handle the file revert menu option. + */ +void CMainFrame::OnFileRevert() +{ + g_StudioApp.OnRevert(); +} + +void CMainFrame::OnFileConnectToDevice() +{ + if (m_remoteProject->isConnected()) + m_remoteProject->disconnect(); + else + m_remoteProject->connect(); +} + +//============================================================================== +/** + * Handles the recent list. + */ +void CMainFrame::OnFileOpenRecent(int nID) +{ + g_StudioApp.OnFileOpenRecent(m_RecentItems->GetItem(nID)); +} + +//============================================================================== +/** + * Tells the scene view to recheck its sizing mode and tells client to update + */ +void CMainFrame::RecheckSizingMode() +{ + m_SceneView->RecheckSizingMode(); +} + +//============================================================================== +/** + * Callback when a Core is opened or fails to open. + */ +void CMainFrame::OnOpenDocument(const CUICFile &inFilename, bool inSucceeded) +{ + if (inSucceeded) + m_RecentItems->AddRecentItem(inFilename); + else + m_RecentItems->RemoveRecentItem(inFilename); +} + +//============================================================================== +/** + * Callback when a Core is saved or fails to save. + */ +void CMainFrame::OnSaveDocument(const CUICFile &inFilename, bool inSucceeded, bool inSaveCopy) +{ + if (!inSaveCopy) + OnOpenDocument(inFilename, inSucceeded); +} + +//============================================================================== +/** + * Callback for when a the doc gets a new path + */ +void CMainFrame::OnDocumentPathChanged(const CUICFile &inNewPath) +{ + QString theTitle = inNewPath.GetName().toQString(); + if (theTitle.isEmpty()) + theTitle = QObject::tr("Untitled"); + + theTitle = theTitle + " - " + QObject::tr("Qt 3D Studio"); + + // TODO: Move this whole pile to the studio app + setWindowTitle(theTitle); + + if (inNewPath.Exists()) + m_RecentItems->AddRecentItem(inNewPath); +} + +//============================================================================== +/** + * Secret hot-key compatibility with Aftereffects muscle memory + */ +void CMainFrame::OnOpenMostRecentlyUsedDocument() +{ + CUICFile theDocument = m_RecentItems->GetItem(0); + if (theDocument.Exists()) + g_StudioApp.OnLoadDocument(theDocument); +} + +void CMainFrame::OnShowSlide() +{ + m_PaletteManager->ShowControl(CPaletteManager::CONTROLTYPE_SLIDE); +} + +void CMainFrame::OnShowTimeline() +{ + m_PaletteManager->ShowControl(CPaletteManager::CONTROLTYPE_TIMELINE); +} + +void CMainFrame::OnShowBasic() +{ + m_PaletteManager->ShowControl(CPaletteManager::CONTROLTYPE_BASICOBJECTS); +} + +void CMainFrame::OnShowProject() +{ + m_PaletteManager->ShowControl(CPaletteManager::CONTROLTYPE_PROJECT); +} + +void CMainFrame::OnShowAction() +{ + m_PaletteManager->ShowControl(CPaletteManager::CONTROLTYPE_ACTION); +} + +void CMainFrame::OnShowInspector() +{ + m_PaletteManager->ShowControl(CPaletteManager::CONTROLTYPE_INSPECTOR); +} + +CTimelineControl *CMainFrame::GetTimelineControl() +{ + return m_PaletteManager->GetTimelineControl(); +} + +ITimelineTimebar *CMainFrame::GetSelectedTimelineTimebar() +{ + CUICDMTimelineItemBinding *theTimelineItemBinding = + GetTimelineControl()->GetTranslationManager()->GetSelectedBinding(); + if (theTimelineItemBinding == NULL) + return NULL; + + return theTimelineItemBinding->GetTimelineItem()->GetTimebar(); +} + +CRecentItems *CMainFrame::GetRecentItems() +{ + return m_RecentItems; +} + +QWidget *CMainFrame::GetActiveView() +{ + return centralWidget(); +} + +bool CMainFrame::eventFilter(QObject *obj, QEvent *event) +{ + switch (event->type()) { + case QEvent::KeyPress: { + QKeyEvent *ke = static_cast(event); + if (ke->key() == Qt::Key_Tab) { + if (m_PaletteManager->tabNavigateFocusedWidget(true)) + return true; + } else if (ke->key() == Qt::Key_Backtab) { + if (m_PaletteManager->tabNavigateFocusedWidget(false)) + return true; + } + break; + } + default: + break; + } + return QMainWindow::eventFilter(obj, event); +} diff --git a/src/Authoring/Studio/MainFrm.h b/src/Authoring/Studio/MainFrm.h new file mode 100644 index 00000000..56373498 --- /dev/null +++ b/src/Authoring/Studio/MainFrm.h @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** 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_MAIN_FRAME +#define INCLUDED_MAIN_FRAME 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "PreviewHelper.h" +#include "DispatchListeners.h" + +#include +#include + +//============================================================================== +// Forwards +//============================================================================== +class CHotKeys; +class CPaletteManager; +class CPaletteState; +class CRecentItems; +class CSceneView; +class CStudioApp; +class CTimelineControl; +class ITimelineTimebar; +class RemoteProject; + +#ifdef QT_NAMESPACE +using namespace QT_NAMESPACE; +#endif + +QT_BEGIN_NAMESPACE +namespace Ui +{ + class MainFrame; +} +QT_END_NAMESPACE + +class CMainFrame : public QMainWindow, + public CPresentationChangeListener, + public CFileOpenListener, + public CClientPlayChangeListener +{ + Q_OBJECT +public: + CMainFrame(); + virtual ~CMainFrame(); + + void OnNewPresentation() override; + void OnClosingPresentation() override; + + // CFileOpenListener + void OnOpenDocument(const CUICFile &inFilename, bool inSucceeded) override; + void OnSaveDocument(const CUICFile &inFilename, bool inSucceeded, bool inSaveCopy) override; + void OnDocumentPathChanged(const CUICFile &inNewPath) override; + + void RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler); + void RecheckSizingMode(); + + void SaveLayout(); + void RestoreLayout(); + void SetLayout(const CPaletteState &inState); + + // CClientPlayChangeListener + void OnPlayStart() override; + void OnPlayStop() override; + void OnTimeChanged(long inTime) override; + + CRecentItems *GetRecentItems(); + + int OnCreate(); + + void onPlaybackTimeout(); + + void OnFileOpen(); + void OnFileSave(); + void OnUpdateFileSave(); + void OnFileSaveAs(); + void OnFileSaveCopy(); + void OnFileNew(); + void OnFileRevert(); + void OnFileConnectToDevice(); + void OnFileOpenRecent(int nID); + + void OnEditRedo(); + void OnEditUndo(); + void OnUpdateEditUndo(); + void OnUpdateEditRedo(); + void OnEditCopy(); + void OnUpdateEditCopy(); + void OnEditCut(); + void OnUpdateEditCut(); + void OnEditPaste(); + void OnUpdateEditPaste(); + void OnEditDuplicate(); + void OnUpdateEditDuplicate(); + +#ifdef KDAB_TEMPORARILY_REMOVED + afx_msg LRESULT OnMsgRouterMsg(WPARAM inWParam, LPARAM inLParam); +#endif + void timerEvent(QTimerEvent *event) override; + void showEvent(QShowEvent *event) override; + + void OnUpdateTimelineSetTimeBarColor(); + void OnTimelineSetTimeBarColor(); + void OnTimelineSetChangedKeyframe(); + void OnTimelineDeleteSelectedKeyframes(); + void OnUpdateTimelineDeleteSelectedKeyframes(); + void OnTimelineSetTimeBarText(); + void OnUpdateTimelineSetTimeBarText(); + void OnUpdateTimelineSetInterpolation(); + void OnTimelineSetInterpolation(); + void closeEvent(QCloseEvent *event) override; + void OnToolAutosetkeys(); + void OnUpdateToolAutosetkeys(); + void OnEditApplicationPreferences(); + void OnEditPresentationPreferences(); + void OnEditSubPresentations(); + void OnPlaybackPlay(); + void OnUpdatePlaybackPlay(); + void OnPlaybackRewind(); + void OnUpdatePlaybackRewind(); + void OnPlaybackStop(); + void OnUpdatePlaybackStop(); + void OnPlaybackPreview(); + void OnUpdatePlaybackPreview(); + void OnUpdateToolMove(); + void OnUpdateToolRotate(); + void OnUpdateToolScale(); + void OnUpdateToolGlobalManipulators(); + void OnToolMove(); + void OnToolRotate(); + void OnToolScale(); + void OnToolGlobalManipulators(); + void OnUpdateToolChange(); + void OnUpdateToolGroupSelection(); + void OnUpdateToolItemSelection(); + + void OnViewBoundingBoxes(); + void OnUpdateViewBoundingBoxes(); + void OnViewPivotPoint(); + void OnUpdateViewPivotPoint(); + void OnViewWireframe(); + void OnUpdateViewWireframe(); + void OnViewHelpPalette(); + void OnUpdateViewHelpPalette(); + void OnUpdateViewTooltips(); + void OnViewTooltips(); + void OnUpdateHelpIndex(); + void OnHelpIndex(); + void OnHelpVisitQt(); + void OnHelpOpenTutorial(); + void OnHelpBehaviorReference(); + void OnOpenMostRecentlyUsedDocument(); + + void OnViewAction(); + void OnUpdateViewAction(); + void OnViewBasicObjects(); + void OnUpdateViewBasicObjects(); + void OnViewInspector(); + void OnUpdateViewInspector(); + void OnViewProject(); + void OnUpdateViewProject(); + void OnViewSlide(); + void OnUpdateViewSlide(); + void OnViewTimeline(); + void OnUpdateViewTimeline(); + + void OnEditCameraZoomExtent(); + void OnEditCameraPan(); + void OnEditCameraRotate(); + void OnEditCameraZoom(); + void OnUpdateCameraZoomExtentAndAuthorZoom(); + void OnUpdateEditCameraPan(); + void OnUpdateEditCameraRotate(); + void OnUpdateEditCameraZoom(); + void OnEditViewFillMode(); + void OnUpdateEditViewFillMode(); + + void OnViewGuidesRulers(); + void OnUpdateViewGuidesRulers(); + void OnClearGuides(); + void OnUpdateClearGuides(); + void OnLockGuides(); + void OnUpdateLockGuides(); + + void OnShowSlide(); + void OnShowTimeline(); + void OnShowBasic(); + void OnShowProject(); + void OnShowAction(); + void OnShowInspector(); + + CTimelineControl *GetTimelineControl(); + ITimelineTimebar *GetSelectedTimelineTimebar(); + + void EditPreferences(short inPageIndex); + + void HandleEditViewFillModeKey(); + void HandleEditCameraZoomExtent(); + + QWidget *GetActiveView(); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; + + RemoteProject *m_remoteProject = nullptr; + CSceneView *m_SceneView = nullptr; + CRecentItems *m_RecentItems = nullptr; + CPaletteManager *m_PaletteManager = nullptr; + bool m_PlaybackFlag = false; + + QScopedPointer m_ui; + QTimer m_playbackTimer; +}; + +#endif // INCLUDED_MAIN_FRAME diff --git a/src/Authoring/Studio/MainFrm.qrc b/src/Authoring/Studio/MainFrm.qrc new file mode 100644 index 00000000..cb91ad47 --- /dev/null +++ b/src/Authoring/Studio/MainFrm.qrc @@ -0,0 +1,83 @@ + + + res/prefstab-00.png + res/prefstab-01.png + res/client_tools_hi_color-00.png + res/client_tools_hi_color-01.png + res/client_tools_hi_color-02.png + res/client_tools_hi_color-03.png + res/client_tools_hi_color-04.png + res/client_tools_hi_color-05.png + res/client_tools_hi_color-06.png + res/editcamera_tools_hi-00.png + res/editcamera_tools_hi-01.png + res/editcamera_tools_hi-02.png + res/editcamera_tools_hi-03.png + res/editcamera_tools_hi-04.png + res/editcamera_tools_hi-05.png + res/playback_tools_low-00.png + res/playback_tools_low-01.png + res/playback_tools_low-02.png + res/playback_tools_low-03.png + res/Toolbar-00.png + res/Toolbar-01.png + res/Toolbar-02.png + res/Toolbar-03.png + res/Toolbar-04.png + res/Toolbar-05.png + res/Toolbar-06.png + res/Toolbar-07.png + res/About Icon.bmp + res/Studio.png + style.qss + res/separator.png + res/editcamera_tools_hi-00_disabled.png + res/editcamera_tools_hi-01_disabled.png + res/editcamera_tools_hi-02_disabled.png + res/editcamera_tools_hi-03_disabled.png + res/editcamera_tools_hi-04_disabled.png + res/editcamera_tools_hi-05_disabled.png + res/editcamera_tools_hi-00@2x.png + res/editcamera_tools_hi-00_disabled@2x.png + res/editcamera_tools_hi-01@2x.png + res/editcamera_tools_hi-01_disabled@2x.png + res/editcamera_tools_hi-02@2x.png + res/editcamera_tools_hi-02_disabled@2x.png + res/editcamera_tools_hi-03@2x.png + res/editcamera_tools_hi-03_disabled@2x.png + res/editcamera_tools_hi-04@2x.png + res/editcamera_tools_hi-04_disabled@2x.png + res/editcamera_tools_hi-05@2x.png + res/editcamera_tools_hi-05_disabled@2x.png + res/playback_tools_low-00@2x.png + res/playback_tools_low-01@2x.png + res/playback_tools_low-02@2x.png + res/prefstab-01@2x.png + res/separator@2x.png + res/client_tools_hi_color-00@2x.png + res/client_tools_hi_color-01@2x.png + res/client_tools_hi_color-02@2x.png + res/client_tools_hi_color-03@2x.png + res/client_tools_hi_color-04@2x.png + res/client_tools_hi_color-05@2x.png + res/client_tools_hi_color-06@2x.png + res/prefstab-00@2x.png + res/arrow_down.png + res/arrow_down@2x.png + res/playback_tools_low-03@2x.png + + + res/open_dialog.png + + + res/edit_camera_rot.png + res/edit_camera_pan.png + res/edit_camera_zoom.png + res/group_move.png + res/group_rotate.png + res/group_scale.png + res/item_move.png + res/item_rotate.png + res/item_scale.png + + diff --git a/src/Authoring/Studio/MainFrm.ui b/src/Authoring/Studio/MainFrm.ui new file mode 100644 index 00000000..3f626236 --- /dev/null +++ b/src/Authoring/Studio/MainFrm.ui @@ -0,0 +1,799 @@ + + + MainFrame + + + + 0 + 0 + 973 + 617 + + + + Qt 3D Studio + + + + :/res/Studio.png:/res/Studio.png + + + + + + 0 + 0 + 973 + 21 + + + + + &File + + + + Recent Projects + + + + + + + + + + + + + + + + + + &Edit + + + + + + + + + + + + + + + + &View + + + + + + + + + + + + + + + + + + + &Timeline + + + + + + + + + + + &Help + + + + + + + + + + + + + + + + Tool Bar + + + + 16 + 15 + + + + TopToolBarArea + + + false + + + + + + + + + + + + + + + Client Tools + + + + 16 + 16 + + + + TopToolBarArea + + + true + + + + + + + + + + + + + + Edit Cameras + + + + 16 + 16 + + + + TopToolBarArea + + + false + + + + + + + + + + + + + Playback + + + + 16 + 16 + + + + TopToolBarArea + + + false + + + + + + + + + + &Reference Manual... + + + + + &Visit Qt Web site... + + + + + &About Qt 3D Studio... + + + + + &Open Tutorial... + + + + + Set Changed Keyframes + + + F6 + + + + + Delete Selected Keyframe(s) + + + + + Set Interpolation... + + + + + Change Time Bar Color... + + + + + true + + + + :/res/client_tools_hi_color-06.png:/res/client_tools_hi_color-06.png + + + Autoset Keyframes + + + Toggle autoset keyframes + + + + + true + + + Action + + + Ctrl+Shift+A + + + + + true + + + Basic Objects + + + Ctrl+Shift+B + + + + + true + + + Inspector + + + Ctrl+Shift+I + + + + + true + + + Project + + + Ctrl+Shift+P + + + + + true + + + Slide + + + Ctrl+Shift+D + + + + + true + + + Timeline + + + Ctrl+Shift+T + + + + + true + + + Bounding Boxes + + + Ctrl+B + + + + + true + + + Pivot Point + + + Ctrl+Alt+P + + + + + true + + + + :/res/editcamera_tools_hi-05.png + :/res/editcamera_tools_hi-05_disabled.png:/res/editcamera_tools_hi-05.png + + + Wireframe + + + Show or Hide Wireframe + + + + + true + + + Tooltips + + + + + true + + + Rulers && Guides + + + Ctrl+; + + + + + true + + + Lock Guides + + + Ctrl+Alt+; + + + + + Clear Guides + + + + + + :/res/Toolbar-06.png:/res/Toolbar-06.png + + + &Undo + + + Ctrl+Z + + + + + + :/res/Toolbar-07.png:/res/Toolbar-07.png + + + &Redo + + + Ctrl+Y + + + + + + :/res/Toolbar-03.png:/res/Toolbar-03.png + + + Cu&t + + + Ctrl+X + + + + + + :/res/Toolbar-04.png:/res/Toolbar-04.png + + + &Copy + + + Ctrl+C + + + + + + :/res/Toolbar-05.png:/res/Toolbar-05.png + + + P&aste + + + Ctrl+V + + + + + &Duplicate Object + + + Ctrl+D + + + + + Studio &Preferences... + + + QAction::PreferencesRole + + + + + Presentation &Settings... + + + Ctrl+P + + + + + + :/res/Toolbar-00.png:/res/Toolbar-00.png + + + &New + + + Ctrl+N + + + + + + :/res/Toolbar-01.png:/res/Toolbar-01.png + + + &Open + + + Ctrl+O + + + + + + :/res/Toolbar-02.png:/res/Toolbar-02.png + + + &Save + + + Ctrl+S + + + + + Save &As... + + + Ctrl+Shift+S + + + + + Save a Copy... + + + Ctrl+Alt+S + + + + + &Revert... + + + + + true + + + &Connect to Device + + + + + E&xit + + + + + Something + + + + + true + + + + :/res/client_tools_hi_color-00.png:/res/client_tools_hi_color-00.png + + + Group Select Tool + + + Group Select + + + + + true + + + + :/res/client_tools_hi_color-01.png:/res/client_tools_hi_color-01.png + + + Item Select Tool + + + Select Item + + + + + true + + + + :/res/client_tools_hi_color-04.png:/res/client_tools_hi_color-04.png + + + Rotation Tool + + + Rotate current selection + + + + + true + + + + :/res/client_tools_hi_color-02.png:/res/client_tools_hi_color-02.png + + + Position Tool + + + Move current selection + + + + + true + + + + :/res/client_tools_hi_color-03.png:/res/client_tools_hi_color-03.png + + + Scale Tool + + + Scale current selection + + + + + true + + + + :/res/client_tools_hi_color-05.png:/res/client_tools_hi_color-05.png + + + Local/Global Manipulators + + + Toggle Manipulators to work in global/local space + + + + + true + + + + :/res/editcamera_tools_hi-00.png + :/res/editcamera_tools_hi-00_disabled.png:/res/editcamera_tools_hi-00.png + + + Fit Selected (F) + + + Fit Selected + + + + + true + + + + :/res/editcamera_tools_hi-01.png + :/res/editcamera_tools_hi-01_disabled.png:/res/editcamera_tools_hi-01.png + + + Pan Tool (Middle Mouse Drag) + + + Pan current edit camera + + + + + true + + + + :/res/editcamera_tools_hi-02.png + :/res/editcamera_tools_hi-02_disabled.png:/res/editcamera_tools_hi-02.png + + + Zoom Tool (Mouse Wheel) + + + Zoom current edit camera + + + + + true + + + + :/res/editcamera_tools_hi-03.png + :/res/editcamera_tools_hi-03_disabled.png:/res/editcamera_tools_hi-03.png + + + Orbit Tool (Alt+Middle Mouse Drag) + + + Orbit current edit camera + + + + + true + + + + :/res/editcamera_tools_hi-04.png + :/res/editcamera_tools_hi-04_disabled.png:/res/editcamera_tools_hi-04.png + + + Shading Mode (F3) + + + Toggle Shading Mode + + + F3 + + + + + + :/res/playback_tools_low-00.png:/res/playback_tools_low-00.png + + + Rewind + + + + + + :/res/playback_tools_low-01.png:/res/playback_tools_low-01.png + + + Stop + + + + + true + + + + :/res/playback_tools_low-02.png:/res/playback_tools_low-02.png + + + Play + + + + + + :/res/playback_tools_low-03.png:/res/playback_tools_low-03.png + + + Preview + + + + + Sub-presentations... + + + + + + CEditCameraBar + QToolBar +
Studio/_Win/UI/EditCameraBar.h
+
+
+ + + + +
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 + +//============================================================================== +/** + * 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 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(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 + +#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 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 +#include +#include +#include + +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(); + if (handlerArg.m_handle.GetHandleValue() == handle && i < m_handlerArguments.size() - 1) { + m_currentPropertyValueHandle = m_handlerArguments[i + 1].value().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(argumentInfo.m_Value); + theArgValue = SValue(std::make_shared( + 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 instances; + + switch (inSelectable.getType()) { + case Q3DStudio::SelectedValueTypes::Instance: + theInstance = inSelectable.getData(); + break; + case Q3DStudio::SelectedValueTypes::MultipleInstances: + instances = inSelectable.getData>(); + // 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().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 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("Qt3DStudio", 1, 0, "HandlerArgumentType", + "HandlerArgumentType is an enum container"_L1); + qmlRegisterUncreatableType("Qt3DStudio", 1, 0, "DataModelDataType", + "DataModelDataType is an enum container"_L1); + qmlRegisterUncreatableType("Qt3DStudio", 1, 0, "AdditionalMetaDataType", + "AdditionalMetaDataType is an enum container"_L1); + qmlRegisterUncreatableType("Qt3DStudio", 1, 0, "PropertyInfo", + "PropertyInfo is anot creatable in QML"_L1); + qmlRegisterUncreatableType("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 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 +#include +#include +#include + +#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> + m_connections; /// connections to the UICDM + QPointer m_objectsModel; + QPointer m_triggerObjectBrowser; + QPointer m_targetObjectBrowser; + QPointer m_eventsModel; + QPointer m_handlersModel; + QPointer m_fireEventsModel; + QPointer m_eventsBrowser; + QPointer m_handlerBrowser; + QPointer 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 +#include +#include +#include + +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 + +#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 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 + +#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 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 > m_events; + QVector 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(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(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 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 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(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 + +#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 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 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 +#include +#include + +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 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 + +#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 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 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 +#include +#include +#include +#include + +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 + +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 + +#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 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 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 expandedItems; + for (const auto &item : m_items) { + if (item.expanded) + expandedItems.insert(item.index); + } + + const std::function 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 +#include +#include +#include + +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 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 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 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 FileChooserModel::getFixedItems() const +{ + static const QVector 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 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 +#include +#include + +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(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 + +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 TGetterFunc; +typedef std::function TSetterFunc; +typedef std::function TCommitFunc; +typedef std::function 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( + 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( + 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( + 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::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(L"Horizontal"); + case UICDM::GuideDirections::Vertical: + return std::make_shared(L"Vertical"); + default: + return std::make_shared(L""); + } +} + +void SGuideInspectableImpl::SetPosition(const UICDM::SValue &inValue) +{ + float thePos = inValue.getData(); + 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(); + + 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> 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 &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 ImageChooserModel::getFixedItems() const +{ + static const QVector 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 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 +#include +#include + +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(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 + +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 + +#include + +#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 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 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 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 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 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(); + 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(); + if (property->m_property == UICDM::CDataModelHandle(handle)) + return property->m_value; + } + } + return {}; +} + +void InspectorControlModel::setMaterials(std::vector &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 + (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(inspectable)) { + int existingIndex = 0; + if (const auto group = dynamic_cast(theInspectorGroup)) { + const auto materialGroup + = dynamic_cast(group); + if (materialGroup && materialGroup->isMaterialGroup()) { + auto i = existingGroup.controlElements.at(existingIndex++).value(); + 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(); + 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 +{ + QVector 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(inspectable)) { + if (const auto group = dynamic_cast(theInspectorGroup)) { + const auto materialGroup + = dynamic_cast(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(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(value); + //intentional fall-through + case UICDM::DataModelDataType::StringOrInt: + if (element->m_propertyType == UICDM::AdditionalMetaDataType::StringList) { + QStringList stringlist = UICDM::get(info->m_MetaDataData); + auto slideSystem = studioSystem->GetSlideSystem(); + + if (element->m_title == QStringLiteral("Play Mode")) { + std::pair 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 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(value); + if (stringOrInt.GetType() == UICDM::SStringOrIntTypes::String) + listOpt = QString::fromWCharArray(UICDM::get + (stringOrInt.m_Value)->GetData()); + else + selectedSlideHandle = UICDM::get(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(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(value); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Font) { + std::vector 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(value); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Mesh) { + QString meshValue = UICDM::get(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(value)); + element->m_value = fileInfo.fileName(); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::PathBuffer) { + element->m_value = UICDM::get(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(value); + } + break; + case UICDM::DataModelDataType::Bool: + element->m_value = UICDM::get(value); + break; + case UICDM::DataModelDataType::Long4: + if (element->m_propertyType == UICDM::AdditionalMetaDataType::Image) { + UICDM::Option guid = UICDM::get(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(value); + const UICDM::SMetaDataRange ranges = UICDM::get(info->m_MetaDataData); + const QList rangesValues{ranges.m_Min, ranges.m_Max}; + element->m_values = QVariant::fromValue >(rangesValues); + } + else if (element->m_propertyType == UICDM::AdditionalMetaDataType::ShadowMapResolution) { + element->m_value = UICDM::get(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(value); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Rotation) { + const QVector3D theFloat3 = UICDM::get(value); + const QList float3Values{theFloat3.x(), theFloat3.y(), theFloat3.z()}; + element->m_values = QVariant::fromValue >(float3Values); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::None) { + const QVector3D theFloat3 = UICDM::get(value); + const QList float3Values{theFloat3.x(), theFloat3.y(), theFloat3.z()}; + element->m_values = QVariant::fromValue >(float3Values); + } + break; + case UICDM::DataModelDataType::Float: + if (element->m_propertyType == UICDM::AdditionalMetaDataType::None) { + element->m_value = UICDM::get(value); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::Range) { + element->m_value = UICDM::get(value); + const UICDM::SMetaDataRange ranges = UICDM::get(info->m_MetaDataData); + const QList rangesValues{ranges.m_Min, ranges.m_Max}; + element->m_values = QVariant::fromValue >(rangesValues); + } else if (element->m_propertyType == UICDM::AdditionalMetaDataType::FontSize) { + element->m_value = UICDM::get(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(); + 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(); + 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(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(info->m_MetaDataData); + + auto slideSystem = studioSystem->GetSlideSystem(); + std::pair 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 + (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 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 +#include + +#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 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 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 roleNames() const override; + + void setInspectable(CInspectableBase *inInspectable); + void setMaterials(std::vector &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()->deleteLater(); + } + }; + + mutable QVector m_groupElements; + CInspectableBase *m_inspectableBase = nullptr; + + struct MaterialEntry + { + QString m_name; + QString m_relativePath; + }; + + std::vector 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 m_notifier; + std::shared_ptr 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 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 +#include +#include +#include +#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 &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 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("Qt3DStudio", 1, 0, "DataModelDataType", + "DataModelDataType is an enum container"); + qmlRegisterUncreatableType( + "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 +#include +#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 &materials); + void setPropertyValueFromFilename(long instance, int handle, const QString &name); + void showBrowser(QQuickWidget *browser, const QPoint &point); + + std::shared_ptr m_selectionChangedConnection; + std::shared_ptr m_DirectoryConnection; + std::shared_ptr m_PropertyChangeConnection; + QColor m_backgroundColor; + InspectorControlModel *m_inspectorControlModel = nullptr; + CInspectableBase *m_inspectableBase = nullptr; + QPointer m_imageChooserView; + QPointer m_meshChooserView; + QPointer m_fileChooserView; + QPointer m_textureChooserView; + QPointer m_objectReferenceView; + QPointer m_objectReferenceModel; + std::vector 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 + +//============================================================================== +/** + * @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 MeshChooserModel::getFixedItems() const +{ + static QVector 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 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 +#include +#include + +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(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 + +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 +#include +#include +#include + +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("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 + +#include "RelativePathTools.h" +#include "UICDMHandles.h" + +#include + +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 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 +#include + +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 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(index.internalId()); +} + +UICDM::TInstanceHandleList ObjectListModel::childrenList(const UICDM::CUICDMSlideHandle &slideHandle, const UICDM::CUICDMInstanceHandle &handle) const +{ + auto slideSystem = m_core->GetDoc()->GetStudioSystem()->GetSlideSystem(); + auto currentMaster = slideSystem->GetMasterSlide(slideHandle); + + UICDM::TInstanceHandleList children; + m_objRefHelper->GetChildInstanceList(handle, children, slideHandle, m_baseHandle); + children.erase( + std::remove_if(children.begin(), children.end(), + [&slideHandle, slideSystem, ¤tMaster](const UICDM::CUICDMInstanceHandle &h) { + const auto childSlide = slideSystem->GetAssociatedSlide(h); + if (!childSlide.Valid()) + return true; + const auto childMaster = slideSystem->GetMasterSlide(childSlide); + if (childMaster == currentMaster) { + return childSlide != childMaster && childSlide != slideHandle; + } else { + return childSlide != childMaster; + } + }), children.end()); + return children; +} + +QString ObjectListModel::nameForHandle(const UICDM::CUICDMInstanceHandle &handle) const +{ + const auto data = m_objRefHelper->GetInfo(handle); + return data.m_Name.toQString(); +} + +QModelIndex ObjectListModel::indexForHandle(const UICDM::CUICDMInstanceHandle &handle, + const QModelIndex &startIndex) const +{ + if (handle == m_baseHandle) + return index(0, 0, {}); + + for (int i = 0; i < rowCount(startIndex); i++) { + auto idx = index(i, 0, startIndex); + if (static_cast(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::collectSourceIndexes( + const QModelIndex &sourceIndex, int depth) const +{ + QVector 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 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 +#include + +#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 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 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 collectSourceIndexes(const QModelIndex &sourceIndex, int depth) const; + + QVector 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 + +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 +#include +#include + +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 +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 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 +#include + +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 > 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 +#include +#include + +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(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 + +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 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 theFilters( + theMetaData.GetMetaDataPropertyFilters(retval[idx])); + if (theFilters.size()) { + Option 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 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 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 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( 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::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 m_UICDMInspectorRows; + CUICDMInspectable &m_Inspectable; + long m_Index; + +public: // Construction + CUICDMInspectorGroup(CStudioApp &inApp, const QString &inName, + CUICDMInspectable &inInspectable, long inIndex); + ~CUICDMInspectorGroup(); + + const std::vector &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 m_CommitListener; + vector 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::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::iterator + GetOrCreateMaterialEntry(const Q3DStudio::CString &inRelativePath) + { + vector::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::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(); + 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::EFILLSTYLE_FLOOD); + CProceduralButton::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 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 m_TabControl; ///< + Q3DStudio::CAutoMemPtr> + 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(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 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 + +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 + +#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 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(&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 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 &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 &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 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 expandedItems; + for (const auto &item : m_items) { + if (item.expanded) + expandedItems.insert(item.index); + } + + const std::function 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 +#include +#include +#include + +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 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 &urls, int row); + Q_INVOKABLE bool hasValidUrlsForDropping(const QList &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 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 +#include +#include +#include +#include +#include + +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 +#include + +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 + +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(); + 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 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 + +#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 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 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 +#include +#include +#include + +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 + +#include "DispatchListeners.h" +#include "SlideModel.h" + +#include "UICDMHandles.h" +#include "UICDMSignals.h" +#include +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> + m_Connections; /// connections to the UICDM + typedef std::unordered_map 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 + +//============================================================================== +// 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(m_StateRows.size()); +} + +CBaseStateRow *CBaseStateRow::GetNonPropertyRow(long inIndex) const +{ + return m_StateRows.at(inIndex); +} + +long CBaseStateRow::GetNumPropertyRows() const +{ + return static_cast(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 TPropertyRowList; + typedef std::vector 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(); + } + + 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 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( + 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(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 +{ +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 +{ +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(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(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 &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::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(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 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 m_InstanceSet; + std::vector 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(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( + 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 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(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(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(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(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(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 + TNameFormalNamePair; + typedef std::vector 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(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( + 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(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(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 TNameFormalNamePair; + typedef std::vector 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 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(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 + +//============================================================================== +// 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 + +//============================================================================== +// 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 theSetter( + std::bind(&CSlideTimelineItemBinding::OnPropertyChanged, this, std::placeholders::_2)); + m_Connection = theEngine->ConnectInstancePropertyValue( + std::bind(UICDM::MaybackCallbackInstancePropertyValue>, + 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 + 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 theSetter( + std::bind(&CTimelineBreadCrumbProvider::OnNameDirty, this)); + + // Listen to name changes on the Asset + m_Connections.push_back(theEngine->ConnectInstancePropertyValue( + std::bind(UICDM::MaybackCallbackInstancePropertyValue>, + 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::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 m_BreadCrumbList; + CDoc *m_Doc; + std::vector> + 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(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(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(GetBinding(inInstance)); + if (theTimelineBinding) + theTimelineBinding->AddPropertyRow(inProperty); +} + +void CTimelineTranslationManager::OnAnimationDeleted(CUICDMInstanceHandle inInstance, + CUICDMPropertyHandle inProperty) +{ + CUICDMTimelineItemBinding *theTimelineBinding = + dynamic_cast(GetBinding(inInstance)); + if (theTimelineBinding) + theTimelineBinding->RemovePropertyRow(inProperty); +} + +void CTimelineTranslationManager::OnPropertyLinked(CUICDMInstanceHandle inInstance, + CUICDMPropertyHandle inProperty) +{ + CUICDMTimelineItemBinding *theTimelineBinding = + dynamic_cast(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(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(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(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(GetBinding(inInstance)); + if (theItemBinding) { + CUICDMTimelineItemBinding *theParentBinding = + dynamic_cast(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(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(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 + TInstanceHandleBindingMap; + + // Store expanded state + typedef std::map TInstanceHandleExpandedMap; // UICDM support + +protected: // Properties + // UICDM support + TInstanceHandleBindingMap m_InstanceHandleBindingMap; + + CKeyframesManager *m_KeyframesManager; + IBreadCrumbProvider *m_BreadCrumbProvider; + std::vector> + 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 + +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(theValue); +} + +void CUICDMTimelineItemBinding::UICDMSetBoolean(UICDM::CUICDMPropertyHandle inProperty, + bool inValue, const QString &inNiceText) const +{ + CDoc *theDoc = dynamic_cast(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(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(inTimelineItemBinding->GetChild(i)); + ToggleChildrenLock(scopedDocEditor, child, inSceneAsset, inLocked); + } +} + +void CUICDMTimelineItemBinding::SetLocked(bool inLocked) +{ + CDoc *theDoc = dynamic_cast(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(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(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(&(*theIter)); + } + return nullptr; +} + +IKeyframe *CUICDMTimelineItemBinding::GetKeyframeByIndex(long inIndex) const +{ + if (inIndex >= 0 && inIndex < (long)m_Keyframes.size()) + return const_cast(&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(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(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(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(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(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 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(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 TPropertyBindingMap; + typedef std::vector 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 +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 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(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 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(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(theValue); + if (inChannelIndex >= 0 && inChannelIndex < 3) + return UICDMToColor(theFloat3[inChannelIndex]); + } else { + SFloat3 theFloat3 = UICDM::get(theValue); + if (inChannelIndex >= 0 && inChannelIndex < 3) + return theFloat3[inChannelIndex]; + } + break; + } + case DataModelDataType::Float2: { + SFloat2 theFloat2 = UICDM::get(theValue); + if (inChannelIndex >= 0 && inChannelIndex < 2) + return theFloat2[inChannelIndex]; + break; + } + case DataModelDataType::Float: + return UICDM::get(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(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(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(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 TKeyframeList; + + CPropertyRow *m_Row; + UICDM::CUICDMInstanceHandle m_InstanceHandle; + UICDM::CUICDMPropertyHandle m_PropertyHandle; + CTimelineTranslationManager *m_TransMgr; + std::vector 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> 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(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(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( + 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 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(theValue); + + m_Color.SetRGB(static_cast(theTimebarColor.m_Floats[0] * 255.0f), + static_cast(theTimebarColor.m_Floats[1] * 255.0f), + static_cast(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(theValue); + + m_Color.SetRGB(static_cast(theTimebarColor.m_Floats[0] * 255.0f), + static_cast(theTimebarColor.m_Floats[1] * 255.0f), + static_cast(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(theValue); + m_Comment.Assign(static_cast(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 +T GetInstancePropertyValue(UICDM::IPropertySystem *inPropertySystem, + UICDM::CUICDMInstanceHandle inInstanceHandle, + UICDM::CUICDMPropertyHandle inProperty) +{ + UICDM::SValue theValue; + inPropertySystem->GetInstancePropertyValue(inInstanceHandle, inProperty, theValue); + return UICDM::get(theValue); +} + +long CUICDMTimelineTimebar::GetStartTime() const +{ + return GetInstancePropertyValue(m_PropertySystem, m_DataHandle, m_StartTime); +} + +long CUICDMTimelineTimebar::GetEndTime() const +{ + return GetInstancePropertyValue(m_PropertySystem, m_DataHandle, m_EndTime); +} + +long CUICDMTimelineTimebar::GetDuration() const +{ + auto theStartTime = GetInstancePropertyValue(m_PropertySystem, m_DataHandle, m_StartTime); + auto theEndTime = GetInstancePropertyValue(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 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 + +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 + +//============================================================================== +// 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(); + m_FltrPropertiesBtn = new CProceduralButton(); + m_FltrMaterialsBtn = new CProceduralButton(); + m_FltrShyBtn = new CProceduralButton(); + m_FltrVisibleBtn = new CProceduralButton(); + + // 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::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::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 *m_FltrBehaviorsBtn; + CProceduralButton *m_FltrPropertiesBtn; + CProceduralButton *m_FltrMaterialsBtn; + CProceduralButton *m_FltrShyBtn; + CProceduralButton *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 +#include + +#include + +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 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 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 + +#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 + +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 +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 + +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 + +//============================================================================== +// 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 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 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 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 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 + +//============================================================================== +// 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 + +//============================================================================= +/** + * 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 + +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 +#include + +class CSnapper +{ + typedef std::set TTimeList; + typedef std::vector 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(m_TimebarControl); + return (theTimebarControl) ? &theTimebarControl->GetSnappingListProvider() : nullptr; +} + +void CStateRow::SetSnappingListProvider(ISnappingListProvider *inProvider) +{ + CStateTimebarRow *theTimebarControl = dynamic_cast(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 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 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 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; ///' keys would respond + // accordingly + CStudioPreferences::SetTimeAdvanceAmount(static_cast(m_SmallHashInterval)); + CStudioPreferences::SetBigTimeAdvanceAmount(static_cast(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(); + + // 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(); + 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(); + 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(); + 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 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 + +//============================================================================= +/** + * 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 +#include +//============================================================================== +// 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(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> + 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 + +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(*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( + this, &CTimelineTimelineLayout::OnScalingZoomIn), + 0, Qt::Key_Plus); + inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer( + this, &CTimelineTimelineLayout::OnScalingZoomOut), + 0, Qt::Key_Minus); + inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer( + this, &CTimelineTimelineLayout::OnScalingZoomIn), + Qt::KeypadModifier, Qt::Key_Plus); + inShortcutHandler->RegisterKeyDownEvent(new CDynHotKeyConsumer( + 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 +#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 TTimelineRowList; + typedef std::map 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( 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 + +//============================================================================= +// 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 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::SBorderOptions theBorderOptions(false, true, true, true); + + m_FltrShyBtn = new CProceduralButton(); + 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(); + 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(); + 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 *m_FltrShyBtn; + CProceduralButton *m_FltrVisibleBtn; + CProceduralButton *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 + } +} diff --git a/src/Authoring/Studio/PreviewHelper.cpp b/src/Authoring/Studio/PreviewHelper.cpp new file mode 100644 index 00000000..271daf4d --- /dev/null +++ b/src/Authoring/Studio/PreviewHelper.cpp @@ -0,0 +1,291 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "PreviewHelper.h" +#include "StudioApp.h" +#include "Dialogs.h" +#include "Dispatch.h" +#include "Doc.h" +#include "StudioPreferences.h" +#include "StudioProjectSettings.h" +#include "StudioProjectVariables.h" +#include "Core.h" +#include "UICFileTools.h" + +#include +#include +#include + +#include "remoteproject.h" + +//============================================================================= +/** + * PKC : Yes, we're duplicating functionality found in UICStateApplication + * but we want to eliminate as many dependencies on UICState as possible in Studio. + */ + +Q3DStudio::CString CPreviewHelper::GetLaunchFile(const Q3DStudio::CString &inUipPath) +{ + Q3DStudio::CFilePath theUipPath(inUipPath); + + Q3DStudio::CString theDir = theUipPath.GetDirectory(); + Q3DStudio::CString theStem = theUipPath.GetFileStem(); + + // Check if a corresponding .UIA file actually exists + theDir.append('/'); + Q3DStudio::CString idealPath = theDir + theStem + Q3DStudio::CString(".uia"); + + Q3DStudio::CFilePath theUiaPath(idealPath); + + return (theUiaPath.IsFile()) ? idealPath : inUipPath; +} + +//============================================================================= +/** + * Callback for previewing a presentation. + */ +void CPreviewHelper::OnPreview() +{ + Q3DStudio::CBuildConfigurations &theConfigurations = + g_StudioApp.GetCore()->GetBuildConfigurations(); + Q3DStudio::CBuildConfiguration *theBuildConfiguration = + theConfigurations.GetConfiguration(CStudioPreferences::GetPreviewConfig()); + if (theBuildConfiguration) + PreviewViaConfig(theBuildConfiguration, EXECMODE_PREVIEW); +} + +//============================================================================= +/** + * Callback for deploying a presentation. + */ +void CPreviewHelper::OnDeploy(RemoteProject &project) +{ + Q3DStudio::CBuildConfigurations &theConfigurations = + g_StudioApp.GetCore()->GetBuildConfigurations(); + Q3DStudio::CBuildConfiguration *theBuildConfiguration = + theConfigurations.GetConfiguration(CStudioPreferences::GetPreviewConfig()); + if (theBuildConfiguration) { + // ItemDataPtr != nullptr ==> Build configurations specified NANT pipeline exporter + PreviewViaConfig(theBuildConfiguration, EXECMODE_DEPLOY, &project); + } +} + +//============================================================================= +/** + * Previewing a presentation using the build configurations loaded. + * This involves 2 steps: + * 1 Export the presentation using the specified exporter. + * 2 Viewing the exported content following the command specified in the configuration. + */ +void CPreviewHelper::PreviewViaConfig(Q3DStudio::CBuildConfiguration *inSelectedConfig, + EExecMode inMode, RemoteProject *project) +{ + bool theUsingTempFile; + CUICFile theDocument = GetDocumentFile(theUsingTempFile); + CCore *theCore = g_StudioApp.GetCore(); + try { + if (theCore->GetDoc()->IsModified()) { + theCore->OnSaveDocument(theDocument); + } + + DoPreviewViaConfig(inSelectedConfig, theDocument.GetAbsolutePath(), + inMode, project); + } catch (...) { + theCore->GetDispatch()->FireOnProgressEnd(); + g_StudioApp.GetDialogs()->DisplaySaveReadOnlyFailed(theDocument); + } +} + +//============================================================================= +/** + * Launch a viewing app to preview a file. + * @param inDocumentFile File to be previewed + */ +void CPreviewHelper::DoPreviewViaConfig(Q3DStudio::CBuildConfiguration * /*inSelectedConfig*/, + const Q3DStudio::CString &inDocumentFile, + EExecMode inMode, + RemoteProject *project) +{ + using namespace Q3DStudio; + Q3DStudio::CString theCommandStr; + + if (inMode == EXECMODE_DEPLOY) { + Q_ASSERT(project); + project->streamProject(inDocumentFile.GetCharStar()); + } else if (inMode == EXECMODE_PREVIEW + && CStudioPreferences::GetPreviewProperty("PLATFORM") == "PC") { + // Quick Preview on PC without going via NANT + CFilePath theCurrentPath(CUICFile::GetApplicationDirectory().GetAbsolutePath()); + CFilePath theViewerDir = CFilePath::fromQString(QApplication::applicationDirPath()); + if (!theViewerDir.IsDirectory()) { + // theMainDir = theCurrentPath.GetDirectory().GetDirectory(); + // theViewerDir = CFilePath::CombineBaseAndRelative( theMainDir, CFilePath( + // L"Runtime/Build/Bin/Win32" ) ); + theViewerDir = theCurrentPath.GetDirectory(); // Developing directory + } + + Q3DStudio::CString theDocumentFile = CPreviewHelper::GetLaunchFile(inDocumentFile); +#ifdef Q_OS_WIN + Q3DStudio::CString theViewerFile = "Qt3DViewer.exe"; + theCommandStr = theViewerDir + "\\" + theViewerFile; +#else +#ifdef Q_OS_MACOS + Q3DStudio::CString theViewerFile = "../../../Qt3DViewer.app/Contents/MacOS/Qt3DViewer"; +#else + Q3DStudio::CString theViewerFile = "Qt3DViewer"; +#endif + theCommandStr = theViewerDir + "/" + theViewerFile; +#endif + + QProcess *p = new QProcess; + auto finished = static_cast(&QProcess::finished); + QObject::connect(p, finished, p, &QObject::deleteLater); + p->start(theCommandStr.toQString(), { theDocumentFile.toQString() }); + + if (!p->waitForStarted()) { + QMessageBox::critical(nullptr, QObject::tr("Error Launching Viewer"), QObject::tr("%1 failed with error: %2") + .arg(theViewerFile.toQString()).arg(p->errorString())); + delete p; + return; + } + } +} + +//============================================================================= +/** + * Interpret the string by resolving the variables. + * @param inSourceString String to be interpreted + */ +Q3DStudio::CString CPreviewHelper::InterpretString(Q3DStudio::CBuildConfiguration *inSelectedConfig, + const Q3DStudio::CString &inDocumentFile, + const Q3DStudio::CString &inSourceString) +{ + Q3DStudio::CString theReturnString; + long theStart = 0; // start index of string + long theBeginIndex = 0; // index of '%' + long theEndIndex = 0; // index of '%' + while (Q3DStudio::CString::ENDOFSTRING != theEndIndex) { + theBeginIndex = inSourceString.Find('%', theStart); + if (Q3DStudio::CString::ENDOFSTRING != theBeginIndex) { + theReturnString += inSourceString.Extract(theStart, theBeginIndex - theStart); + // find the corresponding '%' + theEndIndex = inSourceString.Find('%', theBeginIndex + 1); + if (Q3DStudio::CString::ENDOFSTRING != theEndIndex) { + // first, resolve the variable by the toolbar selection + Q3DStudio::CString theVariable = + inSourceString.Extract(theBeginIndex + 1, theEndIndex - theBeginIndex - 1); + Q3DStudio::CString theResolvedVariable; + bool theHasResolved = ResolveVariable(inSelectedConfig, inDocumentFile, theVariable, + theResolvedVariable); + + if (theHasResolved) { + theReturnString += theResolvedVariable; + } else { + theReturnString += "_NULL_"; + } + theStart = theEndIndex + 1; + } else + theReturnString += inSourceString.Extract(theBeginIndex); + } else { + theEndIndex = theBeginIndex; + theReturnString += inSourceString.Extract(theStart); + } + } + + return theReturnString; +} + +//============================================================================== +/** + * Resolves the passed in variable and write out the resolved value if it exists + * in the current selected build configuration. + * @param inVariable the environment to be resolved + * @param outValue the string to receive the resolved value + * @return true if the variable exists, else false + */ +//============================================================================== +bool CPreviewHelper::ResolveVariable(Q3DStudio::CBuildConfiguration *inSelectedConfig, + const Q3DStudio::CString &inDocumentFile, + const Q3DStudio::CString &inVariable, + Q3DStudio::CString &outValue) +{ + Q3DStudio::CString theReturnStr; + bool theHasResolved = false; + + // Handle special variable + if (inVariable == "BUILDFILE") { + if (inSelectedConfig) { + theReturnStr = inSelectedConfig->GetPath(); + theHasResolved = true; + } + } else if (inVariable == "UIPFILE") { + theReturnStr = inDocumentFile; + theHasResolved = true; + } + + if (!theHasResolved) { + Q3DStudio::CString theValue = CStudioPreferences::GetPreviewProperty(inVariable); + if (theValue != "") { + theReturnStr = theValue; + theHasResolved = true; + } + } + + if (theHasResolved) + outValue = InterpretString(inSelectedConfig, inDocumentFile, theReturnStr); + + return theHasResolved; +} + +//============================================================================= +/** + * Gets a file to be previewed or conditioned based on the current document. + * If the document has not been saved yet (and thus does not have a name), a temp file is used. + * If the document has been saved but it's dirty, a temp file based on the current document is + *used (same path but different extension). + * @param outUsingTempFile if temp file if used + * @return the document file to be previewed or conditioned + */ +CUICFile CPreviewHelper::GetDocumentFile(bool &outUsingTempFile) +{ + CUICFile theDocument = g_StudioApp.GetCore()->GetDoc()->GetDocumentPath(); + CUICFile theResult(""); + theResult = theDocument; + outUsingTempFile = false; + return theResult; +} diff --git a/src/Authoring/Studio/PreviewHelper.h b/src/Authoring/Studio/PreviewHelper.h new file mode 100644 index 00000000..e68e51d9 --- /dev/null +++ b/src/Authoring/Studio/PreviewHelper.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_PREVIEW_HELPER +#define INCLUDED_PREVIEW_HELPER 1 + +//============================================================================== +// Includes +//============================================================================== +#include "UICFile.h" +#include "UICString.h" +#include "remoteproject.h" + +//============================================================================== +// Forwards +//============================================================================== +class CHotKeys; + +namespace Q3DStudio { +class CBuildConfiguration; +} + +//============================================================================== +/** + * @class CPreviewHelper + */ +class CPreviewHelper +{ +public: + enum EExecMode { + EXECMODE_PREVIEW, ///< Preview + EXECMODE_DEPLOY, ///< Deploy + }; + +public: + static void OnPreview(); + static void OnDeploy(RemoteProject &project); + static void PreviewViaConfig(Q3DStudio::CBuildConfiguration *inSelectedConfig, + EExecMode inMode, RemoteProject *project = 0); + static void DoPreviewViaConfig(Q3DStudio::CBuildConfiguration *inSelectedConfig, + const Q3DStudio::CString &inDocumentFile, + EExecMode inMode, + RemoteProject *project = 0); + +protected: + static Q3DStudio::CString InterpretString(Q3DStudio::CBuildConfiguration *inSelectedConfig, + const Q3DStudio::CString &inDocumentFile, + const Q3DStudio::CString &inSourceString); + static bool ResolveVariable(Q3DStudio::CBuildConfiguration *inSelectedConfig, + const Q3DStudio::CString &inDocumentFile, + const Q3DStudio::CString &inVariable, Q3DStudio::CString &outValue); + static CUICFile GetDocumentFile(bool &outUsingTempFile); + static Q3DStudio::CString GetLaunchFile(const Q3DStudio::CString &inDocFile); +}; + +#endif diff --git a/src/Authoring/Studio/Render/IStudioRenderer.h b/src/Authoring/Studio/Render/IStudioRenderer.h new file mode 100644 index 00000000..2dabbd08 --- /dev/null +++ b/src/Authoring/Studio/Render/IStudioRenderer.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 UIC_STUDIO_RENDERER +#define UIC_STUDIO_RENDERER +#pragma once + +#include "IDocSceneGraph.h" +#include +#include + +#include + +QT_BEGIN_NAMESPACE +class QWidget; +QT_END_NAMESPACE + +namespace Q3DStudio { +using qt3ds::QT3DSI32; +class IStudioRenderer : public IDocSceneGraph +{ +protected: + virtual ~IStudioRenderer() {} + +public: + friend class std::shared_ptr; + + virtual bool IsInitialized() = 0; + + virtual void Initialize(QWidget *inWindow) = 0; + + virtual void SetViewRect(const QRect &inRect) = 0; + + virtual void GetEditCameraList(QStringList &outCameras) = 0; + virtual void SetEnableEditLight(bool inEnableLight) = 0; + virtual bool IsEditLightEnabled() const = 0; + virtual bool DoesEditCameraSupportRotation(QT3DSI32 inIndex) = 0; + virtual bool AreGuidesEnabled() const = 0; + virtual void SetGuidesEnabled(bool val) = 0; + virtual bool AreGuidesEditable() const = 0; + virtual void SetGuidesEditable(bool val) = 0; + // Setting the camera to -1 disables the edit cameras + // So setting the camera to 0- (numcameras - 1) will set change the active + // edit camera. + virtual void SetEditCamera(QT3DSI32 inIndex) = 0; + virtual QT3DSI32 GetEditCamera() const = 0; + virtual void EditCameraZoomToFit() = 0; + + // This must be safe to call from multiple places + virtual void Close() = 0; + + // synchronously render the content + virtual void RenderNow() = 0; + + virtual void MakeContextCurrent() = 0; + virtual void ReleaseContext() = 0; + + // Uses the global studio app to get the doc and dispatch. + static std::shared_ptr CreateStudioRenderer(); +}; +}; + +#endif diff --git a/src/Authoring/Studio/Render/PathWidget.cpp b/src/Authoring/Studio/Render/PathWidget.cpp new file mode 100644 index 00000000..49fea1ef --- /dev/null +++ b/src/Authoring/Studio/Render/PathWidget.cpp @@ -0,0 +1,512 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "PathWidget.h" +#include "UICRenderWidgets.h" +#include "render/Qt3DSRenderContext.h" +#include "render/Qt3DSRenderVertexBuffer.h" +#include "render/Qt3DSRenderShaderProgram.h" +#include "render/Qt3DSRenderInputAssembler.h" +#include "UICRenderPath.h" +#include "UICRenderPathSubPath.h" +#include "UICRenderPathManager.h" +#include "UICRenderContext.h" +#include "UICRenderShaderCodeGeneratorV2.h" + +using namespace uic::widgets; + +namespace { + +QT3DSVec3 toVec3(QT3DSVec2 inPoint) +{ + return QT3DSVec3(inPoint.x, inPoint.y, 0.0f); +} +QT3DSVec3 toVec3(QT3DSVec2 inPoint, float z) +{ + return QT3DSVec3(inPoint.x, inPoint.y, z); +} + +struct SPointEntry +{ + QT3DSVec2 m_Position; + QT3DSVec3 m_Color; + QT3DSF32 m_ObjectId; + SPointEntry(QT3DSVec2 pos, QT3DSVec3 color, size_t objId) + : m_Position(pos) + , m_Color(color) + , m_ObjectId((QT3DSF32)objId) + { + } + SPointEntry() {} +}; + +struct SPathWidget : public IPathWidget +{ + typedef nvvector> + TReverseAnchorBuffer; + + NVAllocatorCallback &m_Allocator; + IUICRenderContext &m_UICContext; + + NVScopedRefCounted m_PointVertexBuffer; + NVScopedRefCounted m_PointAssembler; + NVScopedRefCounted m_PointShader; + NVScopedRefCounted m_PointPickShader; + + NVScopedRefCounted m_LineVertexBuffer; + NVScopedRefCounted m_LineAssembler; + NVScopedRefCounted m_LineShader; + + nvvector> m_LineBuffer; + nvvector m_PointBuffer; + TReverseAnchorBuffer m_AnchorIndexBuffer; + SWidgetRenderSetupResult m_RenderSetup; + QT3DSVec2 m_PointViewportDimensions; + QT3DSMat44 m_PointMVP; + + QT3DSI32 m_RefCount; + SPathWidget(NVAllocatorCallback &inAlloc, IUICRenderContext &inRc) + : m_Allocator(inAlloc) + , m_UICContext(inRc) + , m_LineBuffer(inAlloc, "m_LineBuffer") + , m_PointBuffer(inAlloc, "m_PointBuffer") + , m_AnchorIndexBuffer(inAlloc, "m_AnchorIndexBuffer") + , m_LineShader(nullptr) + , m_RefCount(0) + { + } + + void addRef() override { ++m_RefCount; } + void release() override + { + --m_RefCount; + if (m_RefCount <= 0) { + NVAllocatorCallback &alloc(m_Allocator); + NVDelete(alloc, this); + } + } + + void SetNode(SNode &inNode) override { m_Node = &inNode; } + + QT3DSVec3 ToGlobalSpace(QT3DSVec3 inPoint) { return m_Node->m_GlobalTransform.transform(inPoint); } + + QT3DSVec3 ToCameraSpace(QT3DSVec3 inPoint) + { + QT3DSVec3 theGlobalPos = m_Node->m_GlobalTransform.transform(inPoint); + return m_RenderSetup.m_WidgetInfo.m_CameraGlobalInverse.transform(theGlobalPos); + } + + QT3DSVec3 ToCameraSpace(QT3DSVec2 inPoint) + { + return ToCameraSpace(QT3DSVec3(inPoint.x, inPoint.y, 0.0f)); + } + + void GeneratePointVertexGeometrySections(IShaderProgramGenerator &inProgramGenerator) + { + IShaderStageGenerator &vertex(*inProgramGenerator.GetStage(ShaderGeneratorStages::Vertex)); + IShaderStageGenerator &geometry( + *inProgramGenerator.GetStage(ShaderGeneratorStages::Geometry)); + vertex.AddIncoming("attr_pos", "vec2"); + vertex.AddIncoming("attr_color", "vec3"); + vertex.AddIncoming("attr_objid", "float"); + vertex.AddOutgoing("point_color", "vec3"); + vertex.AddOutgoing("object_id", "float"); + vertex.AddUniform("model_view_projection", "mat4"); + vertex << "void main()" << Endl << "{" << Endl + << "\tgl_Position = model_view_projection * vec4( attr_pos.xy, 0.0, 1.0 );" << Endl + << "\tpoint_color = attr_color;" << Endl << "\tobject_id = uint(attr_objid);" << Endl + << "}" << Endl; + + geometry.AddUniform("viewport_dimensions", "vec2"); + geometry.AddUniform("pointsize", "float"); + geometry.AddIncoming("point_color", "vec3"); + geometry.AddIncoming("object_id", "float"); + geometry.AddOutgoing("point_colorGE", "vec3"); + geometry.AddOutgoing("object_idGE", "float"); + geometry.AddOutgoing("uv_coords", "vec2"); + geometry.Append("layout (points) in;"); + geometry.Append("layout (triangle_strip, max_vertices = 4) out;"); + geometry.Append( + "void main() {" + "// project points to screen space\n" + "\tvec2 p0 = vec2(gl_in[0].gl_Position.xy) / gl_in[0].gl_Position.w;\n" + "\tvec2 increments = (pointsize / viewport_dimensions) / 2.0;\n" + "\tgl_Position = vec4( p0.x - increments.x, p0.y + increments.y, 0.0, 1.0 );\n" + "\tpoint_colorGE = point_color[0];\n" + "\tuv_coords = vec2(0.0, 0.0);\n" + "\tobject_idGE = object_id[0];\n" + "\tEmitVertex();\n" + "\tgl_Position = vec4( p0.x + increments.x, p0.y + increments.y, 0.0, 1.0 );\n" + "\tpoint_colorGE = point_color[0];\n" + "\tuv_coords = vec2(1.0, 0.0);\n" + "\tobject_idGE = object_id[0];\n" + "\tEmitVertex();\n" + "\tgl_Position = vec4( p0.x - increments.x, p0.y - increments.y, 0.0, 1.0 );\n" + "\tpoint_colorGE = point_color[0];\n" + "\tuv_coords = vec2(0.0, 1.0);\n" + "\tobject_idGE = object_id[0];\n" + "\tEmitVertex();\n" + "\tgl_Position = vec4( p0.x + increments.x, p0.y - increments.y, 0.0, 1.0 );\n" + "\tpoint_colorGE = point_color[0];\n" + "\tuv_coords = vec2(1.0, 1.0);\n" + "\tobject_idGE = object_id[0];\n" + "\tEmitVertex();\n" + "\tEndPrimitive();\n" + "}\n"); + } + + NVRenderShaderProgram *GetPointShader(IShaderProgramGenerator &inProgramGenerator) + { + if (m_PointShader) + return m_PointShader.mPtr; + inProgramGenerator.BeginProgram(IShaderProgramGenerator::DefaultFlags() + | ShaderGeneratorStages::Geometry); + GeneratePointVertexGeometrySections(inProgramGenerator); + + IShaderStageGenerator &fragment( + *inProgramGenerator.GetStage(ShaderGeneratorStages::Fragment)); + fragment.AddIncoming("point_colorGE", "vec3"); + fragment.AddIncoming("uv_coords", "vec2"); + fragment.Append("void main()\n" + "{\n" + "\tvec2 coords = uv_coords - vec2(.5, .5);\n" + "\tfloat coordLen = length( coords );\n" + "\tfloat margin = .4;\n" + "\tfloat leftover = min( 1.0, (coordLen - margin)/.1 );\n" + "\tfloat alpha = coordLen < margin ? 1.0 : mix( 1.0, 0.0, leftover );\n" + "\tfragOutput = vec4(point_colorGE, alpha);\n" + "}\n"); + + m_PointShader = inProgramGenerator.CompileGeneratedShader("path widget point shader"); + return m_PointShader.mPtr; + } + + NVRenderShaderProgram *GetPointPickShader(IShaderProgramGenerator &inProgramGenerator) + { + if (m_PointPickShader) + return m_PointPickShader.mPtr; + inProgramGenerator.BeginProgram(IShaderProgramGenerator::DefaultFlags() + | ShaderGeneratorStages::Geometry); + GeneratePointVertexGeometrySections(inProgramGenerator); + + IShaderStageGenerator &fragment( + *inProgramGenerator.GetStage(ShaderGeneratorStages::Fragment)); + fragment.AddIncoming("object_idGE", "float"); + fragment.AddIncoming("uv_coords", "vec2"); + fragment.Append("void main()\n" + "{\n" + "\tvec2 coords = uv_coords - vec2(.5, .5);\n" + "\tfloat coordLen = length( coords );\n" + "\tfloat margin = .4;\n" + "\tuint object_id = coordLen < margin ? uint(object_idGE + 1) : uint(0);\n" + "\tfragOutput.r = float(object_id % 256)/255.0;\n" + "\tfragOutput.g = float(object_id / 256)/255.0;\n" + //"\tfragOutput.g = float(object_id) / 10.0;\n" + "\tfragOutput.b = 0.0;\n" + "\tfragOutput.a = 1.0;\n" + "}\n"); + m_PointPickShader = + inProgramGenerator.CompileGeneratedShader("path widget point pick shader"); + return m_PointPickShader.mPtr; + } + + NVRenderShaderProgram *GetLineShader(IShaderProgramGenerator &inProgramGenerator) + { + if (m_LineShader) + return m_LineShader.mPtr; + + inProgramGenerator.BeginProgram(IShaderProgramGenerator::DefaultFlags() + | ShaderGeneratorStages::Geometry); + + IShaderStageGenerator &vertex(*inProgramGenerator.GetStage(ShaderGeneratorStages::Vertex)); + IShaderStageGenerator &geometry( + *inProgramGenerator.GetStage(ShaderGeneratorStages::Geometry)); + IShaderStageGenerator &fragment( + *inProgramGenerator.GetStage(ShaderGeneratorStages::Fragment)); + + vertex.AddIncoming("attr_pos", "vec2"); + vertex.AddUniform("model_view_projection", "mat4"); + vertex << "void main()" << Endl << "{" << Endl + << "\tgl_Position = model_view_projection * vec4( attr_pos.xy, 0.0, 1.0 );" << Endl + << "}" << Endl; + + geometry.AddUniform("viewport_dimensions", "vec2"); + geometry.AddUniform("linewidth", "float"); + geometry.AddOutgoing("uv_coords", "vec2"); + geometry.Append( + "layout (lines) in;\n" + "layout (triangle_strip, max_vertices = 4) out;\n" + "void main()\n" + "{\n" + "\tvec2 p0 = vec2(gl_in[0].gl_Position.xy) / gl_in[0].gl_Position.w;\n" + "\tvec2 p1 = vec2(gl_in[1].gl_Position.xy) / gl_in[1].gl_Position.w;\n" + "\tvec2 slope = normalize( p1 - p0 );\n" + "\tvec2 tangent = vec2(slope.y, -slope.x);\n" + "\tvec2 increments = (linewidth / viewport_dimensions) / 2.0;\n" + "\tvec2 tangentVec = vec2( tangent.x * increments.x, tangent.y * increments.y );\n" + "\tgl_Position = vec4( p0 - tangentVec, 0.0, 1.0);\n" + "\tuv_coords = vec2(0.0, 0.0);\n" + "\tEmitVertex();\n" + "\tgl_Position = vec4( p0 + tangentVec, 0.0, 1.0);\n" + "\tuv_coords = vec2(1.0, 0.0);\n" + "\tEmitVertex();\n" + "\tgl_Position = vec4( p1 - tangentVec, 0.0, 1.0);\n" + "\tuv_coords = vec2(0.0, 1.0);\n" + "\tEmitVertex();\n" + "\tgl_Position = vec4( p1 + tangentVec, 0.0, 1.0);\n" + "\tuv_coords = vec2(1.0, 1.0);\n" + "\tEmitVertex();\n" + "\tEndPrimitive();\n" + "}\n"); + + fragment.AddUniform("line_color", "vec3"); + fragment.AddIncoming("uv_coords", "vec2"); + fragment.Append("void main()\n" + "{\n" + "\tvec2 coords = uv_coords - vec2(.5, .5);\n" + "\tfloat coordLen = abs(coords.x);\n" + "\tfloat margin = .1;\n" + "\tfloat leftover = min( 1.0, (coordLen - margin)/.3 );\n" + "\tleftover = leftover * leftover;\n" + "\tfloat alpha = coordLen < margin ? 1.0 : mix( 1.0, 0.0, leftover );\n" + "\tfragOutput = vec4(line_color, alpha);\n" + "}\n"); + + m_LineShader = inProgramGenerator.CompileGeneratedShader("path widget line shader"); + return m_LineShader.mPtr; + } + + void RenderPointBuffer(NVRenderShaderProgram &inProgram, const QT3DSMat44 &inMVP, + NVRenderContext &inRenderContext) + { + inRenderContext.SetCullingEnabled(false); + inRenderContext.SetDepthTestEnabled(false); + inRenderContext.SetDepthWriteEnabled(false); + inRenderContext.SetStencilTestEnabled(false); + inRenderContext.SetBlendingEnabled(true); + inRenderContext.SetBlendFunction(qt3ds::render::NVRenderBlendFunctionArgument( + qt3ds::render::NVRenderSrcBlendFunc::SrcAlpha, + qt3ds::render::NVRenderDstBlendFunc::OneMinusSrcAlpha, + qt3ds::render::NVRenderSrcBlendFunc::One, + qt3ds::render::NVRenderDstBlendFunc::OneMinusSrcAlpha)); + inRenderContext.SetBlendEquation(qt3ds::render::NVRenderBlendEquationArgument( + NVRenderBlendEquation::Add, NVRenderBlendEquation::Add)); + inRenderContext.SetActiveShader(&inProgram); + inProgram.SetPropertyValue("model_view_projection", inMVP); + inProgram.SetPropertyValue("pointsize", (QT3DSF32)15.0f); + inProgram.SetPropertyValue("viewport_dimensions", m_PointViewportDimensions); + inRenderContext.SetInputAssembler(m_PointAssembler); + inRenderContext.Draw(NVRenderDrawMode::Points, m_PointBuffer.size(), 0); + } + + void PushPoint(const SPointEntry &inEntry, QT3DSU32 inAnchorIndex, + uic::studio::SPathPick::EAnchorProperty inProperty) + { + QT3DSU32 anchorIndex = (QT3DSU32)m_PointBuffer.size(); + m_PointBuffer.push_back(inEntry); + m_AnchorIndexBuffer.push_back(eastl::make_pair(inAnchorIndex, inProperty)); + } + + void Render(IRenderWidgetContext &inWidgetContext, NVRenderContext &inRenderContext) override + { + if (!m_Node) + return; + SPath &thePath = static_cast(*m_Node); + IPathManager &theManager = m_UICContext.GetPathManager(); + + QT3DSVec3 anchorColor(0, 1, 0); + QT3DSVec3 controlColor(0, 0, 1); + m_LineBuffer.clear(); + m_PointBuffer.clear(); + // point index -> anchor index + m_AnchorIndexBuffer.clear(); + QT3DSU32 anchorIndex = 0; + + for (SPathSubPath *theSubPath = thePath.m_FirstSubPath; theSubPath; + theSubPath = theSubPath->m_NextSubPath) { + NVDataRef thePathBuffer( + theManager.GetPathSubPathBuffer(*theSubPath)); + if (thePathBuffer.size() == 0) + return; + + QT3DSU32 numAnchors = thePathBuffer.size(); + for (QT3DSU32 idx = 0, end = numAnchors; idx < end; ++idx) { + const uic::render::SPathAnchorPoint &theAnchorPoint(thePathBuffer[idx]); + if (idx > 0) { + QT3DSVec2 incoming(uic::render::IPathManagerCore::GetControlPointFromAngleDistance( + theAnchorPoint.m_Position, theAnchorPoint.m_IncomingAngle, + theAnchorPoint.m_IncomingDistance)); + PushPoint(SPointEntry(incoming, controlColor, m_PointBuffer.size()), + anchorIndex, uic::studio::SPathPick::IncomingControl); + m_LineBuffer.push_back(eastl::make_pair(theAnchorPoint.m_Position, incoming)); + } + PushPoint(SPointEntry(theAnchorPoint.m_Position, anchorColor, m_PointBuffer.size()), + anchorIndex, uic::studio::SPathPick::Anchor); + if (idx < (numAnchors - 1)) { + QT3DSVec2 outgoing(uic::render::IPathManagerCore::GetControlPointFromAngleDistance( + theAnchorPoint.m_Position, theAnchorPoint.m_OutgoingAngle, + theAnchorPoint.m_OutgoingDistance)); + PushPoint(SPointEntry(outgoing, controlColor, m_PointBuffer.size()), + anchorIndex, uic::studio::SPathPick::OutgoingControl); + m_LineBuffer.push_back(eastl::make_pair(theAnchorPoint.m_Position, outgoing)); + } + ++anchorIndex; + } + } + + m_RenderSetup = SWidgetRenderSetupResult(inWidgetContext, *m_Node, + uic::render::RenderWidgetModes::Local); + + m_PointMVP = m_RenderSetup.m_WidgetInfo.m_LayerProjection + * m_RenderSetup.m_WidgetInfo.m_CameraGlobalInverse * m_Node->m_GlobalTransform; + + NVRenderRect theViewport = inRenderContext.GetViewport(); + m_PointViewportDimensions = QT3DSVec2((QT3DSF32)theViewport.m_Width, (QT3DSF32)theViewport.m_Height); + + if (!m_LineBuffer.empty()) { + QT3DSU32 vertItemSize = sizeof(QT3DSVec2); + QT3DSU32 vertBufSize = m_LineBuffer.size() * vertItemSize * 2; + if ((!m_LineVertexBuffer) || m_LineVertexBuffer->Size() < vertBufSize) { + m_LineVertexBuffer = inRenderContext.CreateVertexBuffer( + qt3ds::render::NVRenderBufferUsageType::Dynamic, vertBufSize, vertItemSize, + qt3ds::foundation::toU8DataRef(m_LineBuffer.data(), (QT3DSU32)m_LineBuffer.size())); + m_LineAssembler = nullptr; + } else + m_LineVertexBuffer->UpdateBuffer( + qt3ds::foundation::toU8DataRef(m_LineBuffer.data(), (QT3DSU32)m_LineBuffer.size())); + + if (m_LineAssembler == nullptr) { + qt3ds::render::NVRenderVertexBufferEntry theEntries[] = { + qt3ds::render::NVRenderVertexBufferEntry( + "attr_pos", qt3ds::render::NVRenderComponentTypes::QT3DSF32, 2, 0), + }; + NVRenderAttribLayout *theAttribLayout = + &inWidgetContext.CreateAttributeLayout(toConstDataRef(theEntries, 1)); + m_LineAssembler = inRenderContext.CreateInputAssembler( + theAttribLayout, toConstDataRef(&m_LineVertexBuffer.mPtr, 1), nullptr, + toConstDataRef(vertItemSize), toConstDataRef((QT3DSU32)0)); + } + inRenderContext.SetInputAssembler(m_LineAssembler); + NVRenderShaderProgram *lineShader = + GetLineShader(inWidgetContext.GetProgramGenerator()); + if (lineShader) { + inRenderContext.SetCullingEnabled(false); + inRenderContext.SetDepthTestEnabled(false); + inRenderContext.SetDepthWriteEnabled(false); + inRenderContext.SetStencilTestEnabled(false); + inRenderContext.SetBlendingEnabled(true); + inRenderContext.SetBlendFunction(qt3ds::render::NVRenderBlendFunctionArgument( + qt3ds::render::NVRenderSrcBlendFunc::SrcAlpha, + qt3ds::render::NVRenderDstBlendFunc::OneMinusSrcAlpha, + qt3ds::render::NVRenderSrcBlendFunc::One, + qt3ds::render::NVRenderDstBlendFunc::OneMinusSrcAlpha)); + inRenderContext.SetBlendEquation(qt3ds::render::NVRenderBlendEquationArgument( + NVRenderBlendEquation::Add, NVRenderBlendEquation::Add)); + inRenderContext.SetActiveShader(lineShader); + lineShader->SetPropertyValue("model_view_projection", m_PointMVP); + lineShader->SetPropertyValue("line_color", QT3DSVec3(1.0, 1.0, 0.0)); + // Note the line needs to be wide enough to account for anti-aliasing. + lineShader->SetPropertyValue("linewidth", 3.0f); + lineShader->SetPropertyValue("viewport_dimensions", m_PointViewportDimensions); + inRenderContext.Draw(NVRenderDrawMode::Lines, m_LineBuffer.size() * 2, 0); + } + } + { + QT3DSU32 vertItemSize = (sizeof(SPointEntry)); + QT3DSU32 vertBufSize = m_PointBuffer.size() * vertItemSize; + if ((!m_PointVertexBuffer) || m_PointVertexBuffer->Size() < vertBufSize) { + m_PointVertexBuffer = inRenderContext.CreateVertexBuffer( + qt3ds::render::NVRenderBufferUsageType::Dynamic, vertBufSize, vertItemSize, + qt3ds::foundation::toU8DataRef(m_PointBuffer.data(), (QT3DSU32)m_PointBuffer.size())); + m_PointAssembler = nullptr; + } else + m_PointVertexBuffer->UpdateBuffer( + qt3ds::foundation::toU8DataRef(m_PointBuffer.data(), (QT3DSU32)m_PointBuffer.size())); + if (m_PointAssembler == nullptr) { + qt3ds::render::NVRenderVertexBufferEntry theEntries[] = { + qt3ds::render::NVRenderVertexBufferEntry( + "attr_pos", qt3ds::render::NVRenderComponentTypes::QT3DSF32, 2, 0), + qt3ds::render::NVRenderVertexBufferEntry( + "attr_color", qt3ds::render::NVRenderComponentTypes::QT3DSF32, 3, 8), + qt3ds::render::NVRenderVertexBufferEntry( + "attr_objid", qt3ds::render::NVRenderComponentTypes::QT3DSF32, 1, 20), + }; + NVRenderAttribLayout *theAttribLayout = + &inWidgetContext.CreateAttributeLayout(toConstDataRef(theEntries, 3)); + m_PointAssembler = inRenderContext.CreateInputAssembler( + theAttribLayout, toConstDataRef(&m_PointVertexBuffer.mPtr, 1), nullptr, + toConstDataRef(vertItemSize), toConstDataRef((QT3DSU32)0)); + } + NVRenderShaderProgram *thePointShader = + GetPointShader(inWidgetContext.GetProgramGenerator()); + GetPointPickShader(inWidgetContext.GetProgramGenerator()); + + if (thePointShader) { + m_PointMVP = m_RenderSetup.m_WidgetInfo.m_LayerProjection + * m_RenderSetup.m_WidgetInfo.m_CameraGlobalInverse * m_Node->m_GlobalTransform; + + RenderPointBuffer(*m_PointShader, m_PointMVP, inRenderContext); + } + } + } + + void RenderPick(const QT3DSMat44 &inProjPreMult, NVRenderContext &inRenderContext, + uic::render::SWindowDimensions inWinDimensions) override + { + if (m_PointAssembler == nullptr || m_PointPickShader == nullptr) + return; + // The projection premultiplication step moves the viewport around till + // it is centered over the mouse and scales everything *post* rendering (to keep appropriate + // aspect). + QT3DSMat44 theMVP = inProjPreMult * m_PointMVP; + m_PointViewportDimensions = + QT3DSVec2((QT3DSF32)inWinDimensions.m_Width, (QT3DSF32)inWinDimensions.m_Height); + + RenderPointBuffer(*m_PointPickShader, theMVP, inRenderContext); + } + + uic::studio::SStudioPickValue PickIndexToPickValue(QT3DSU32 inPickIndex) override + { + inPickIndex -= 1; + + if (inPickIndex < m_AnchorIndexBuffer.size()) + return uic::studio::SPathPick(m_AnchorIndexBuffer[inPickIndex].first, + m_AnchorIndexBuffer[inPickIndex].second); + else { + QT3DS_ASSERT(false); + return uic::studio::SPathPick(); + } + } +}; +} + +IPathWidget &IPathWidget::CreatePathWidget(NVAllocatorCallback &inCallback, IUICRenderContext &inRc) +{ + return *QT3DS_NEW(inCallback, SPathWidget)(inCallback, inRc); +} diff --git a/src/Authoring/Studio/Render/PathWidget.h b/src/Authoring/Studio/Render/PathWidget.h new file mode 100644 index 00000000..cde1a84a --- /dev/null +++ b/src/Authoring/Studio/Render/PathWidget.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 UIC_STUDIO_PATH_WIDGET_H +#define UIC_STUDIO_PATH_WIDGET_H +#pragma once +#include "StudioWidget.h" +#include "UICDMHandles.h" +#include "StudioPickValues.h" + +namespace uic { +namespace widgets { + + class IPathWidget : public IStudioWidgetBase + { + public: + uic::studio::SStudioPickValue PickIndexToPickValue(QT3DSU32 inPickIndex) override = 0; + static IPathWidget &CreatePathWidget(NVAllocatorCallback &inAlloc, + IUICRenderContext &inRenderContext); + }; +} +} + +#endif diff --git a/src/Authoring/Studio/Render/StudioPickValues.h b/src/Authoring/Studio/Render/StudioPickValues.h new file mode 100644 index 00000000..cc811073 --- /dev/null +++ b/src/Authoring/Studio/Render/StudioPickValues.h @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 UIC_STUDIO_PICK_VALUES_H +#define UIC_STUDIO_PICK_VALUES_H +#pragma once +#include "foundation/Qt3DSDiscriminatedUnion.h" +#include "foundation/Qt3DSUnionCast.h" +#include "UICDMHandles.h" +#include "StaticMaxSize.h" + +namespace uic { +namespace studio { + using UICDM::CUICDMInstanceHandle; + using UICDM::CUICDMGuideHandle; + + struct StudioPickValueTypes + { + enum Enum { + UnknownValueType = 0, + Instance, + Widget, + Guide, + Path, + }; + }; + + struct SWidgetPick + { + qt3ds::QT3DSI32 m_WidgetId; + SWidgetPick(qt3ds::QT3DSI32 id = 0) + : m_WidgetId(id) + { + } + }; + + struct SPathPick + { + enum EAnchorProperty { + Anchor = 0, + IncomingControl, + OutgoingControl, + }; + + qt3ds::QT3DSU32 m_AnchorIndex; + EAnchorProperty m_Property; + + SPathPick() + : m_AnchorIndex(0) + , m_Property(Anchor) + { + } + + SPathPick(qt3ds::QT3DSU32 ai, EAnchorProperty p) + : m_AnchorIndex(ai) + , m_Property(p) + { + } + }; + + template + struct SStudioPickValueTypeMap + { + }; + + template <> + struct SStudioPickValueTypeMap + { + static StudioPickValueTypes::Enum GetType() { return StudioPickValueTypes::Instance; } + }; + + template <> + struct SStudioPickValueTypeMap + { + static StudioPickValueTypes::Enum GetType() { return StudioPickValueTypes::Widget; } + }; + + template <> + struct SStudioPickValueTypeMap + { + static StudioPickValueTypes::Enum GetType() { return StudioPickValueTypes::Guide; } + }; + + template <> + struct SStudioPickValueTypeMap + { + static StudioPickValueTypes::Enum GetType() { return StudioPickValueTypes::Path; } + }; + + struct SStudioPickValueTraits + { + typedef StudioPickValueTypes::Enum TIdType; + enum { + TBufferSize = Q3DStudio::StaticMaxSize::value + }; + + static TIdType getNoDataId() { return StudioPickValueTypes::UnknownValueType; } + + template + static TIdType getType() + { + return SStudioPickValueTypeMap().GetType(); + } + + template + static TRetType visit(char *inData, TIdType inType, TVisitorType inVisitor) + { + switch (inType) { + case StudioPickValueTypes::Instance: + return inVisitor(*qt3ds::NVUnionCast(inData)); + case StudioPickValueTypes::Widget: + return inVisitor(*qt3ds::NVUnionCast(inData)); + case StudioPickValueTypes::Guide: + return inVisitor(*qt3ds::NVUnionCast(inData)); + case StudioPickValueTypes::Path: + return inVisitor(*qt3ds::NVUnionCast(inData)); + default: + QT3DS_ASSERT(false); + case StudioPickValueTypes::UnknownValueType: + return inVisitor(); + } + } + + template + static TRetType visit(const char *inData, TIdType inType, TVisitorType inVisitor) + { + switch (inType) { + case StudioPickValueTypes::Instance: + return inVisitor(*qt3ds::NVUnionCast(inData)); + case StudioPickValueTypes::Widget: + return inVisitor(*qt3ds::NVUnionCast(inData)); + case StudioPickValueTypes::Guide: + return inVisitor(*qt3ds::NVUnionCast(inData)); + case StudioPickValueTypes::Path: + return inVisitor(*qt3ds::NVUnionCast(inData)); + default: + QT3DS_ASSERT(false); + case StudioPickValueTypes::UnknownValueType: + return inVisitor(); + } + } + }; + + typedef qt3ds::foundation:: + DiscriminatedUnion, + SStudioPickValueTraits::TBufferSize> + TStudioPickValueType; + + struct SStudioPickValue : public TStudioPickValueType + { + SStudioPickValue() {} + SStudioPickValue(CUICDMInstanceHandle inst) + : TStudioPickValueType(inst) + { + } + SStudioPickValue(SWidgetPick inst) + : TStudioPickValueType(inst) + { + } + SStudioPickValue(CUICDMGuideHandle inst) + : TStudioPickValueType(inst) + { + } + SStudioPickValue(SPathPick inst) + : TStudioPickValueType(inst) + { + } + SStudioPickValue(const SStudioPickValue &other) + : TStudioPickValueType(static_cast(other)) + { + } + SStudioPickValue &operator=(const SStudioPickValue &other) + { + TStudioPickValueType::operator=(static_cast(other)); + return *this; + } + int GetWidgetId() const + { + if (getType() == StudioPickValueTypes::Widget) + return getData().m_WidgetId; + return 0; + } + }; +} +} + +#endif diff --git a/src/Authoring/Studio/Render/StudioRenderer.cpp b/src/Authoring/Studio/Render/StudioRenderer.cpp new file mode 100644 index 00000000..960cc1b6 --- /dev/null +++ b/src/Authoring/Studio/Render/StudioRenderer.cpp @@ -0,0 +1,883 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "StudioRendererImpl.h" +#include "StudioRendererTranslation.h" +#include "StudioPreferences.h" +#include "HotKeys.h" +#include "StudioUtils.h" + +#include + +#ifdef _WIN32 +#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union +#endif +using namespace uic::studio; + +namespace { + +const QT3DSU32 g_WheelFactor = 10; // the wheel zoom factor + +struct SEditCameraDefinition +{ + EditCameraTypes::Enum m_Type; + // Directional cameras have a direction they point + QT3DSVec3 m_Direction; // not normalized + QString m_Name; +}; + +SEditCameraDefinition g_EditCameraDefinitions[] = { + { EditCameraTypes::Perspective, QT3DSVec3(1, -1, -1), QObject::tr("Perspective View") }, + { EditCameraTypes::Orthographic, QT3DSVec3(1, -1, -1), QObject::tr("Orthographic View") }, + { EditCameraTypes::Directional, QT3DSVec3(0, -1, 0), QObject::tr("Top View") }, + { EditCameraTypes::Directional, QT3DSVec3(0, 1, 0), QObject::tr("Bottom View") }, + { EditCameraTypes::Directional, QT3DSVec3(1, 0, 0), QObject::tr("Left View") }, + { EditCameraTypes::Directional, QT3DSVec3(-1, 0, 0), QObject::tr("Right View") }, + { EditCameraTypes::Directional, QT3DSVec3(0, 0, -1), QObject::tr("Front View") }, + { EditCameraTypes::Directional, QT3DSVec3(0, 0, 1), QObject::tr("Back View") }, +}; +QT3DSU32 g_NumEditCameras = sizeof(g_EditCameraDefinitions) / sizeof(*g_EditCameraDefinitions); + +struct SRendererImpl : public IStudioRenderer, + public IDataModelListener, + public IReloadListener, + public CPresentationChangeListener, + public CSceneDragListener, + public CToolbarChangeListener +{ + typedef eastl::vector> TEditCameraInfoList; + std::shared_ptr m_RenderContext; + NVScopedRefCounted m_UICContext; + QRect m_Rect; + CDispatch &m_Dispatch; + CDoc &m_Doc; + std::shared_ptr m_Translation; + CPt m_MouseDownPoint; + CPt m_PreviousMousePoint; + bool m_HasPresentation; + bool m_Closed; + CUpdateableDocumentEditor m_UpdatableEditor; + MovementTypes::Enum m_LastDragToolMode; + bool m_MaybeDragStart; + TEditCameraInfoList m_EditCameraInformation; + QT3DSI32 m_EditCameraIndex; + SEditCameraPersistentInformation m_MouseDownCameraInformation; + SStudioPickValue m_PickResult; + bool m_RenderRequested; + int m_LastToolMode; + bool m_GuidesEnabled; + UICDM::TSignalConnectionPtr m_SelectionSignal; + + SRendererImpl() + : m_Dispatch(*g_StudioApp.GetCore()->GetDispatch()) + , m_Doc(*g_StudioApp.GetCore()->GetDoc()) + , m_HasPresentation(false) + , m_Closed(false) + , m_UpdatableEditor(m_Doc) + , m_LastDragToolMode(MovementTypes::Unknown) + , m_MaybeDragStart(false) + , m_EditCameraIndex(-1) + , m_RenderRequested(false) + , m_LastToolMode(0) + , m_GuidesEnabled(true) + { + m_Dispatch.AddReloadListener(this); + m_Dispatch.AddDataModelListener(this); + m_Dispatch.AddPresentationChangeListener(this); + m_SelectionSignal = + m_Dispatch.ConnectSelectionChange(std::bind(&SRendererImpl::OnSelectionChange, this)); + m_Dispatch.AddSceneDragListener(this); + m_Dispatch.AddToolbarChangeListener(this); + } + ~SRendererImpl() + { + Close(); + m_Dispatch.RemoveDataModelListener(this); + m_Dispatch.RemovePresentationChangeListener(this); + m_Dispatch.RemoveSceneDragListener(this); + m_Dispatch.RemoveToolbarChangeListener(this); + } + + // IDocSceneGraph + QT3DSVec3 GetIntendedPosition(UICDM::CUICDMInstanceHandle inHandle, CPt inPoint) override + { + if (m_Translation) + return m_Translation->GetIntendedPosition(inHandle, inPoint); + + return QT3DSVec3(0, 0, 0); + } + + ITextRenderer *GetTextRenderer() override + { + if (m_UICContext.mPtr) + return m_UICContext->GetTextRenderer(); + return NULL; + } + // The buffer manager may not be available + IBufferManager *GetBufferManager() override + { + if (m_UICContext.mPtr) + return &m_UICContext->GetBufferManager(); + return NULL; + } + + IPathManager *GetPathManager() override + { + if (m_UICContext.mPtr) + return &m_UICContext->GetPathManager(); + return NULL; + } + + qt3ds::foundation::IStringTable *GetRenderStringTable() override + { + if (m_UICContext.mPtr) + return &m_UICContext->GetStringTable(); + return NULL; + } + + bool IsInitialized() override { return m_UICContext.mPtr != NULL; } + + void Initialize(QWidget *inWindow) override + { + if (m_Closed) + return; + QT3DS_ASSERT(!m_RenderContext); + QT3DS_ASSERT(m_UICContext.mPtr == NULL); + try { + m_RenderContext = std::make_shared(inWindow); + + Q3DStudio::CString theResourcePath = Q3DStudio::CString::fromQString(resourcePath()); + NVScopedRefCounted theCore = + uic::render::IUICRenderContextCore::Create( + m_RenderContext->GetRenderContext().GetFoundation(), + m_RenderContext->GetRenderContext().GetStringTable()); + + // Create text renderer + uic::render::ITextRendererCore &theTextRenderer( + uic::render::ITextRendererCore::CreateQtTextRenderer( + m_RenderContext->GetRenderContext().GetFoundation(), + m_RenderContext->GetRenderContext().GetStringTable())); + theCore->SetTextRendererCore(theTextRenderer); + + m_UICContext = theCore->CreateRenderContext( + m_RenderContext->GetRenderContext(), + m_RenderContext->GetRenderContext().GetStringTable().RegisterStr( + theResourcePath.c_str())); + + // Allow the artist to interact with the top level objects alone. + m_UICContext->GetRenderer().PickRenderPlugins(false); + + SetupTextRenderer(); + + m_UICContext->SetAuthoringMode(true); + + InitializePointerTags(m_UICContext->GetStringTable()); + SetViewRect(m_Rect); +#ifdef KDAB_TEMPORARILY_REMOVE + // KDAB_TODO the below call asserts on windows + m_RenderContext->GetRenderContext().SetClearColor(QT3DSVec4(0, 0, 0, 1)); +#endif + if (m_HasPresentation) + CreateTranslator(); + + // Notify that renderer has been initialized + m_Dispatch.FireOnRendererInitialized(); + } catch (...) { + m_UICContext = nullptr; + m_RenderContext = std::shared_ptr(); + throw; + } + } + + void SetViewRect(const QRect &inRect) override + { + if (m_RenderContext) + m_RenderContext->resized(); + + m_Rect = inRect; + if (IsInitialized()) { + m_RenderContext->BeginRender(); + NVRenderContext &theContext = m_RenderContext->GetRenderContext(); + theContext.SetViewport(qt3ds::render::NVRenderRect(0, 0, inRect.width(), + inRect.height())); + SetTranslationViewport(); + m_RenderContext->EndRender(); + } + } + // Request that this object renders. May be ignored if a transaction + // is ongoing so we don't get multiple rendering per transaction. + void RequestRender() override + { + if (m_RenderContext) + m_RenderContext->requestRender(); + } + + void RenderRequestedRender() + { + if (m_RenderRequested) { + m_RenderContext->requestRender(); + } + } + + void RenderNow() override + { + Render(); + } + + void MakeContextCurrent() override + { + m_RenderContext->BeginRender(); + } + + void ReleaseContext() + { + m_RenderContext->EndRender(); + } + + void Render() + { + m_RenderRequested = false; + if (!m_Closed && IsInitialized()) { + m_RenderContext->BeginRender(); + if (m_Translation) + m_Translation->PreRender(); + NVRenderContext &theContext = m_RenderContext->GetRenderContext(); + theContext.SetDepthWriteEnabled(true); + theContext.Clear(qt3ds::render::NVRenderClearFlags( + qt3ds::render::NVRenderClearValues::Color | qt3ds::render::NVRenderClearValues::Depth)); + if (m_Translation) { + m_Translation->Render(m_PickResult.GetWidgetId(), m_GuidesEnabled); + } + m_RenderContext->EndRender(); + } + } + void GetEditCameraList(QStringList &outCameras) override + { + outCameras.clear(); + for (QT3DSU32 idx = 0; idx < g_NumEditCameras; ++idx) + outCameras.push_back(g_EditCameraDefinitions[idx].m_Name); + } + void SetEnableEditLight(bool inEnableLight) override + { + CStudioPreferences::SetEditViewFillMode(inEnableLight); + if (m_Translation) + m_Translation->m_EditLightEnabled = inEnableLight; + RequestRender(); + } + + bool DoesEditCameraSupportRotation(QT3DSI32 inIndex) override + { + if (inIndex >= 0 && inIndex < (QT3DSI32)g_NumEditCameras) + return g_EditCameraDefinitions[inIndex].m_Type != EditCameraTypes::Directional; + return false; + } + + bool AreGuidesEnabled() const override { return m_GuidesEnabled; } + + void SetGuidesEnabled(bool val) override { m_GuidesEnabled = val; } + + bool AreGuidesEditable() const override { return m_Doc.IsValid() ? m_Doc.GetDocumentReader().AreGuidesEditable() : false; } + + void SetGuidesEditable(bool val) override { if (m_Doc.IsValid()) m_Doc.GetDocumentReader().SetGuidesEditable(val); } + + // Setting the camera to -1 disables the edit cameras + // So setting the camera to 0- (numcameras - 1) will set change the active + // edit camera. + void SetEditCamera(QT3DSI32 inIndex) override + { + QT3DSI32 oldIndex = m_EditCameraIndex; + m_EditCameraIndex = NVMin(inIndex, (QT3DSI32)g_NumEditCameras); + // save the old edit camera information + if (oldIndex != m_EditCameraIndex && m_Translation && m_Translation->m_EditCameraEnabled) { + while (m_EditCameraInformation.size() <= (QT3DSU32)oldIndex) + m_EditCameraInformation.push_back(Empty()); + + m_EditCameraInformation[oldIndex] = m_Translation->m_EditCameraInfo; + } + + ApplyEditCameraIndex(); + RequestRender(); + } + + QT3DSI32 GetEditCamera() const override + { + if (m_EditCameraIndex >= 0 && m_EditCameraIndex < (QT3DSI32)g_NumEditCameras) + return m_EditCameraIndex; + return -1; + } + + bool IsEditLightEnabled() const override + { + return GetEditCamera() >= 0 && CStudioPreferences::GetEditViewFillMode(); + } + + void EditCameraZoomToFit() override + { + UICDM::CUICDMInstanceHandle theInstance = m_Doc.GetSelectedInstance(); + if (!m_Translation || m_Translation->m_EditCameraEnabled == false) + return; + // If we aren't pointed at a node then bounce up the asset graph till we are. + while (theInstance.Valid() && m_Translation->GetOrCreateTranslator(theInstance) + && GraphObjectTypes::IsNodeType( + m_Translation->GetOrCreateTranslator(theInstance)->GetGraphObject().m_Type) + == false) { + theInstance = m_Translation->m_AssetGraph.GetParent(theInstance); + } + // If we still aren't pointed at a node then use the active layer. + if (theInstance.Valid() == false + || m_Translation->GetOrCreateTranslator(theInstance) == nullptr + || GraphObjectTypes::IsNodeType( + m_Translation->GetOrCreateTranslator(theInstance)->GetGraphObject().m_Type) + == false) + theInstance = m_Doc.GetActiveLayer(); + + // If we *still* aren't pointed at a node then bail. + if (m_Translation->GetOrCreateTranslator(theInstance) == nullptr + || GraphObjectTypes::IsNodeType( + m_Translation->GetOrCreateTranslator(theInstance)->GetGraphObject().m_Type) + == false) + return; + + SNode &theNode = static_cast( + m_Translation->GetOrCreateTranslator(theInstance)->GetGraphObject()); + qt3ds::NVBounds3 theBounds; + theBounds.setEmpty(); + if (theNode.m_Type == GraphObjectTypes::Layer) { + SNode *theEditLayer = m_Translation->GetEditCameraLayer(); + if (theEditLayer) { + for (SNode *theChild = theEditLayer->m_FirstChild; theChild; + theChild = theChild->m_NextSibling) { + qt3ds::NVBounds3 childBounds = theChild->GetBounds( + m_UICContext->GetBufferManager(), m_UICContext->GetPathManager()); + if (childBounds.isEmpty() == false) { + childBounds.transform(theChild->m_GlobalTransform); + theBounds.include(childBounds); + } + } + } + } else + theBounds = + theNode.GetBounds(m_UICContext->GetBufferManager(), m_UICContext->GetPathManager()); + QT3DSVec3 theCenter = theNode.m_GlobalTransform.transform(theBounds.getCenter()); + // Center the edit camera so that it points directly at the bounds center point + m_Translation->m_EditCameraInfo.m_Position = theCenter; + // Now we need to adjust the camera's zoom such that the view frustum contains the bounding + // box. + // But to do that I need to figure out what the view frustum is at -600 units from the near + // clip plane + + QT3DSVec3 theExtents = theBounds.getExtents(); + // get the largest extent and then some addition so things fit nicely in the viewport. + QT3DSF32 theMaxPossibleRadius = theExtents.magnitude(); + // easiest case, the viewport dimensions map directly to the + m_Translation->m_EditCameraInfo.m_ViewRadius = theMaxPossibleRadius; + RequestRender(); + } + + // This must be safe to call from multiple places + void Close() override + { + m_Closed = true; + m_Translation = std::shared_ptr(); + m_UICContext = nullptr; + m_RenderContext = std::shared_ptr(); + } + + // Data model listener + + // Fired before a large group of notifications come out so views can + // only refresh their view once. + void OnBeginDataModelNotifications() override {} + // Fired after a large gruop of notifications (onInstancePropertyChanged, etc) come out + // so views can be careful about refreshing their data and there view + void OnEndDataModelNotifications() override { Render(); } + + // Fired during 3d drag or mouse move events (or keyframe drag) or likewise + // events so that views that need to update based on the new data can. + void OnImmediateRefreshInstanceSingle(UICDM::CUICDMInstanceHandle inInstance) override + { + if (m_Translation) { + m_Translation->MarkDirty(inInstance); + // Pass to translation system + Render(); + } + } + // Same thing, but fired when more than one instance is being refreshed. + void OnImmediateRefreshInstanceMultiple(UICDM::CUICDMInstanceHandle *inInstance, + long inInstanceCount) override + { + // Pass to translation system + if (m_Translation) { + m_Translation->MarkDirty(inInstance, inInstanceCount); + // Pass to translation system + Render(); + } + Render(); + } + + void OnReloadEffectInstance(UICDM::CUICDMInstanceHandle inInstance) override + { + if (m_Translation) + m_Translation->ReleaseEffect(inInstance); + } + + void ApplyEditCameraIndex() + { + if (!m_Translation) + return; + if (m_EditCameraIndex < 0 || m_EditCameraIndex >= (QT3DSI32)g_NumEditCameras) + m_Translation->m_EditCameraEnabled = false; + else { + const SEditCameraDefinition &theDefinition(g_EditCameraDefinitions[m_EditCameraIndex]); + + while ((size_t)m_EditCameraIndex >= m_EditCameraInformation.size()) + m_EditCameraInformation.push_back(Empty()); + + Option &theCameraInfo = + m_EditCameraInformation[m_EditCameraIndex]; + + if (!theCameraInfo.hasValue()) { + theCameraInfo = SEditCameraPersistentInformation(); + // TODO - consider resizing clip planes to scene so we use the depth buffer more + // accurately + // or consider requesting a larger depth buffer from the windowing system. + // Setup the camera + theCameraInfo->m_Direction = theDefinition.m_Direction; + theCameraInfo->m_CameraType = theDefinition.m_Type; + } + + m_Translation->m_EditCameraEnabled = true; + m_Translation->m_EditCameraInfo = theCameraInfo; + } + } + + void SetTranslationViewport() + { + if (m_Translation) { + m_Translation->SetViewport(QT3DSF32(m_Rect.right() - m_Rect.left()), + QT3DSF32(m_Rect.bottom() - m_Rect.top())); + } + } + + void CreateTranslator() + { + if (!m_Translation) { + if (m_UICContext.mPtr) { + m_Translation = std::make_shared(std::ref(*this), + std::ref(*m_UICContext.mPtr)); + m_Translation->m_EditLightEnabled = CStudioPreferences::GetEditViewFillMode(); + ApplyEditCameraIndex(); + SetTranslationViewport(); + } + } + } + + void SetupTextRenderer() + { + if (m_UICContext.mPtr && m_UICContext->GetTextRenderer()) { + m_UICContext->GetTextRenderer()->ClearProjectFontDirectories(); + Q3DStudio::CString theDocDir = m_Doc.GetDocumentDirectory(); + if (theDocDir.Length()) { + // Add the installed font folders from the res dir. + Q3DStudio::CString thePath(Q3DStudio::CString::fromQString( + resourcePath() + QStringLiteral("/Font"))); + m_UICContext->GetTextRenderer()->AddSystemFontDirectory( + m_UICContext->GetStringTable().RegisterStr(thePath.c_str())); + m_UICContext->GetTextRenderer()->AddProjectFontDirectory( + m_UICContext->GetStringTable().RegisterStr(theDocDir.c_str())); + } + } + } + + //========================================================================== + /** + * New presentation is being created. + */ + void OnNewPresentation() override + { + OnClosingPresentation(); + m_HasPresentation = true; + // Reset edit camera information. + m_EditCameraInformation.clear(); + // Rebuild translation + CreateTranslator(); + SetupTextRenderer(); + RequestRender(); + } + + //========================================================================== + /** + * The current presentation is being closed. + */ + void OnClosingPresentation() override + { + // Destroy translation + m_Translation = std::shared_ptr(); + m_HasPresentation = false; + } + + void OnSelectionChange() { RequestRender(); } + + UICDM::CUICDMInstanceHandle GetAnchorPointFromPick(SPathPick &inPick) + { + return m_Translation->GetAnchorPoint(inPick); + } + + //========================================================================== + // CSceneDragListener + //========================================================================== + void OnSceneMouseDown(SceneDragSenderType::Enum inSenderType, QPoint inPoint, int) override + { + if (m_Translation == NULL) + return; + + inPoint.setX(inPoint.x() * devicePixelRatio()); + inPoint.setY(inPoint.y() * devicePixelRatio()); + + m_PickResult = SStudioPickValue(); + TranslationSelectMode::Enum theSelectMode = TranslationSelectMode::Group; + switch (g_StudioApp.GetSelectMode()) { + case STUDIO_SELECTMODE_ENTITY: + theSelectMode = TranslationSelectMode::Single; + break; + case STUDIO_SELECTMODE_GROUP: + theSelectMode = TranslationSelectMode::Group; + break; + default: + QT3DS_ASSERT(false); + break; + } + if (inSenderType == SceneDragSenderType::SceneWindow + && m_Translation->GetPickArea(inPoint) == PickTargetAreas::Presentation) { + m_RenderContext->BeginRender(); + m_PickResult = m_Translation->Pick(inPoint, theSelectMode); + m_RenderContext->EndRender(); + // If we definitely did not pick a widget. + if (m_PickResult.getType() == StudioPickValueTypes::Instance) { + UICDM::CUICDMInstanceHandle theHandle(m_PickResult.getData()); + + if (theHandle != m_Doc.GetSelectedInstance()) + m_Doc.SelectUICDMObject(theHandle); + } else if (m_PickResult.getType() == StudioPickValueTypes::Guide) + m_Doc.NotifySelectionChanged(m_PickResult.getData()); + else if (m_PickResult.getType() == StudioPickValueTypes::Path) { + SPathPick thePick = m_PickResult.getData(); + UICDM::CUICDMInstanceHandle theAnchorHandle = + m_Translation->GetAnchorPoint(thePick); + if (theAnchorHandle.Valid() && theAnchorHandle != m_Doc.GetSelectedInstance()) { + m_Doc.SelectUICDMObject(theAnchorHandle); + } + } + RequestRender(); + } else { + qt3ds::foundation::Option pickResult = + m_Translation->PickRulers(inPoint); + if (pickResult.hasValue() == false) + m_Translation->PrepareForDrag(); + else { + Q3DStudio::IDocumentEditor &docEditor( + m_UpdatableEditor.EnsureEditor(L"Create Guide", __FILE__, __LINE__)); + CUICDMGuideHandle newGuide = docEditor.CreateGuide(*pickResult); + m_PickResult = SStudioPickValue(newGuide); + m_Doc.NotifySelectionChanged(newGuide); + } + } + m_LastDragToolMode = MovementTypes::Unknown; + m_MaybeDragStart = true; + m_MouseDownPoint = inPoint; + m_PreviousMousePoint = inPoint; + m_MouseDownCameraInformation = m_Translation->m_EditCameraInfo; + m_LastToolMode = g_StudioApp.GetToolMode(); + } + + void OnSceneMouseDrag(SceneDragSenderType::Enum, QPoint inPoint, int inToolMode, + int inFlags) override + { + if (m_Translation == NULL) + return; + + inPoint.setX(inPoint.x() * devicePixelRatio()); + inPoint.setY(inPoint.y() * devicePixelRatio()); + + if (m_MaybeDragStart) { + // Dragging in the first 5 pixels will be ignored to avoid unconsciously accidental + // moves + CPt theDragDistance = inPoint - m_MouseDownPoint; + if (m_PickResult.getType() == StudioPickValueTypes::Widget + || inToolMode != STUDIO_TOOLMODE_SCALE) { + if (theDragDistance.x * theDragDistance.x + theDragDistance.y * theDragDistance.y + <= 25) + return; + } else { + if (abs(theDragDistance.y) <= 5) + return; + } + } + + m_MaybeDragStart = false; + + // If the tool mode changes then we throw out the last widget pick if there was one. + if (m_LastToolMode != inToolMode) + m_PickResult = SStudioPickValue(); + m_LastToolMode = inToolMode; + + // General dragging + if (m_PickResult.getType() == StudioPickValueTypes::Instance + || m_PickResult.getType() + == StudioPickValueTypes::UnknownValueType) // matte drag and widget drag + { + // Not sure what right-click drag does in the scene. + bool isEditCamera = m_Translation->m_EditCameraEnabled; + int theCameraToolMode = isEditCamera ? (inToolMode & (STUDIO_CAMERATOOL_MASK)) : 0; + bool rightClick = (inFlags & CHotKeys::MOUSE_RBUTTON) != 0; + + if (theCameraToolMode == 0) { + if (m_Doc.GetDocumentReader().IsInstance(m_Doc.GetSelectedInstance())) { + bool rightClick = (inFlags & CHotKeys::MOUSE_RBUTTON) != 0; + MovementTypes::Enum theMovement(MovementTypes::Unknown); + + switch (inToolMode) { + default: + QT3DS_ASSERT(false); + break; + case STUDIO_TOOLMODE_MOVE: + if (rightClick) + theMovement = MovementTypes::TranslateAlongCameraDirection; + else + theMovement = MovementTypes::Translate; + break; + case STUDIO_TOOLMODE_SCALE: + if (rightClick) + theMovement = MovementTypes::ScaleZ; + else + theMovement = MovementTypes::Scale; + break; + case STUDIO_TOOLMODE_ROTATE: + if (rightClick) + theMovement = MovementTypes::RotationAboutCameraDirection; + else + theMovement = MovementTypes::Rotation; + break; + } + + if (theMovement != MovementTypes::Unknown) { + bool theLockToAxis = (inFlags & CHotKeys::MODIFIER_SHIFT) != 0; + + if (m_LastDragToolMode != MovementTypes::Unknown + && theMovement != m_LastDragToolMode) { + m_UpdatableEditor.RollbackEditor(); + m_MouseDownPoint = inPoint; + } + + m_LastDragToolMode = theMovement; + + switch (theMovement) { + case MovementTypes::TranslateAlongCameraDirection: + m_Translation->TranslateSelectedInstanceAlongCameraDirection( + m_MouseDownPoint, inPoint, m_UpdatableEditor); + break; + case MovementTypes::Translate: + m_Translation->TranslateSelectedInstance( + m_MouseDownPoint, inPoint, m_UpdatableEditor, theLockToAxis); + break; + case MovementTypes::ScaleZ: + m_Translation->ScaleSelectedInstanceZ(m_MouseDownPoint, inPoint, + m_UpdatableEditor); + break; + case MovementTypes::Scale: + m_Translation->ScaleSelectedInstance(m_MouseDownPoint, inPoint, + m_UpdatableEditor); + break; + case MovementTypes::Rotation: + m_Translation->RotateSelectedInstance(m_MouseDownPoint, + m_PreviousMousePoint, inPoint, + m_UpdatableEditor, theLockToAxis); + break; + case MovementTypes::RotationAboutCameraDirection: + m_Translation->RotateSelectedInstanceAboutCameraDirectionVector( + m_PreviousMousePoint, inPoint, m_UpdatableEditor); + break; + } + } + } + } else { + QT3DSF32 theXDistance = static_cast(inPoint.x() - m_MouseDownPoint.x); + QT3DSF32 theYDistance = static_cast(inPoint.y() - m_MouseDownPoint.y); + QT3DSF32 theSubsetXDistance = static_cast(inPoint.x() - m_PreviousMousePoint.x); + QT3DSF32 theSubsetYDistance = static_cast(inPoint.y() - m_PreviousMousePoint.y); + + // Edit cameras are not implemented. + switch (theCameraToolMode) { + case STUDIO_TOOLMODE_CAMERA_PAN: { + QT3DSVec3 theXAxis = + m_Translation->m_EditCamera.m_GlobalTransform.column0.getXYZ(); + QT3DSVec3 theYAxis = + m_Translation->m_EditCamera.m_GlobalTransform.column1.getXYZ(); + QT3DSVec3 theXChange = -1.0f * theXAxis * theXDistance; + QT3DSVec3 theYChange = theYAxis * theYDistance; + QT3DSVec3 theDiff = theXChange + theYChange; + m_Translation->m_EditCameraInfo.m_Position = + m_MouseDownCameraInformation.m_Position + theDiff; + RequestRender(); + } break; + case STUDIO_TOOLMODE_CAMERA_ZOOM: { + QT3DSF32 theMultiplier = 1.0f + theSubsetYDistance / 40.0f; + m_Translation->m_EditCameraInfo.m_ViewRadius = + NVMax(.0001f, m_Translation->m_EditCameraInfo.m_ViewRadius * theMultiplier); + RequestRender(); + } break; + case STUDIO_TOOLMODE_CAMERA_ROTATE: { + if (m_Translation->m_EditCameraInfo.SupportsRotation()) { + if (rightClick == false) { + QT3DSVec3 theXAxis = QT3DSVec3(1, 0, 0); + QT3DSVec3 theYAxis = QT3DSVec3(0, 1, 0); + // Rotate about the center; we will just rotation the direction vector. + QT3DSQuat theXRotation(-1.0f * theSubsetXDistance * g_RotationScaleFactor + / 20.0f, + theYAxis); + QT3DSQuat theYRotation(-1.0f * theSubsetYDistance * g_RotationScaleFactor + / 20.0f, + theXAxis); + m_Translation->m_EditCameraInfo.m_Rotation = + m_MouseDownCameraInformation.m_Rotation + * (theXRotation * theYRotation); + } else { + QT3DSVec3 theZAxis = QT3DSVec3(0, 0, 1); + QT3DSQuat theZRotation( + -1.0f * theYDistance * g_RotationScaleFactor / 20.0f, theZAxis); + m_Translation->m_EditCameraInfo.m_Rotation = + m_MouseDownCameraInformation.m_Rotation * theZRotation; + } + // Rotations need to be incremental and relative else things don't rotate + // intuitively. + m_MouseDownCameraInformation.m_Rotation = + m_Translation->m_EditCameraInfo.m_Rotation; + RequestRender(); + } + } break; + default: + QT3DS_ASSERT(false); + break; + } + } + } // if ( m_PickResult.m_WidgetId.hasValue() == false ) + + // We need to do widget-specific dragging. + else if (m_PickResult.getType() == StudioPickValueTypes::Widget) { + m_Translation->PerformWidgetDrag(m_PickResult.GetWidgetId(), m_MouseDownPoint, + m_PreviousMousePoint, inPoint, m_UpdatableEditor); + } else if (m_PickResult.getType() == StudioPickValueTypes::Guide) { + m_Translation->PerformGuideDrag(m_PickResult.getData(), inPoint, + m_UpdatableEditor); + } else if (m_PickResult.getType() == StudioPickValueTypes::Path) { + SPathPick thePick = m_PickResult.getData(); + m_Translation->PerformPathDrag(thePick, m_MouseDownPoint, m_PreviousMousePoint, inPoint, + m_UpdatableEditor); + } + m_PreviousMousePoint = inPoint; + } + + void OnSceneMouseUp(SceneDragSenderType::Enum) override + { + m_MaybeDragStart = false; + CUICDMGuideHandle theSelectedGuide; + if (m_PickResult.getType() == StudioPickValueTypes::Guide) { + theSelectedGuide = m_PickResult.getData(); + m_Translation->CheckGuideInPresentationRect(theSelectedGuide, m_UpdatableEditor); + } + m_UpdatableEditor.CommitEditor(); + m_PickResult = SStudioPickValue(); + if (m_Translation) + m_Translation->EndDrag(); + if (theSelectedGuide.GetHandleValue()) { + // Get rid of selection if things aren't editable. + if (m_Doc.GetDocumentReader().AreGuidesEditable()) + m_Doc.NotifySelectionChanged(theSelectedGuide); + else + m_Doc.NotifySelectionChanged(); + } + RequestRender(); + } + + void OnSceneMouseDblClick(SceneDragSenderType::Enum inSenderType, QPoint inPoint) override + { + if (inSenderType == SceneDragSenderType::SceneWindow && m_Translation) { + inPoint.setX(inPoint.x() * devicePixelRatio()); + inPoint.setY(inPoint.y() * devicePixelRatio()); + m_RenderContext->BeginRender(); + SStudioPickValue theResult( + m_Translation->Pick(inPoint, TranslationSelectMode::NestedComponentSingle)); + m_RenderContext->EndRender(); + + if (theResult.getType() == StudioPickValueTypes::Instance) + m_Doc.SelectAndNavigateToUICDMObject(theResult.getData()); + else if (theResult.getType() == StudioPickValueTypes::Path) { + SPathPick thePickValue = theResult.getData(); + UICDM::CUICDMInstanceHandle theAnchorHandle = + m_Translation->GetAnchorPoint(thePickValue); + if (theAnchorHandle.Valid() && theAnchorHandle != m_Doc.GetSelectedInstance()) { + m_Doc.SelectUICDMObject(theAnchorHandle); + } + } + } + } + + void OnSceneMouseWheel(SceneDragSenderType::Enum inSenderType, short inDelta, + int inToolMode) override + { + ASSERT(inSenderType == SceneDragSenderType::Matte); + if (inToolMode == STUDIO_TOOLMODE_CAMERA_ZOOM && m_Translation) { + QT3DSF32 theMultiplier = 1.0f - inDelta / static_cast(120 * g_WheelFactor); + m_Translation->m_EditCameraInfo.m_ViewRadius = + NVMax(.0001f, m_Translation->m_EditCameraInfo.m_ViewRadius * theMultiplier); + RequestRender(); + } + } + + void OnNudge(ENudgeDirection inNudgeDirection, int inToolMode, int inFlags) override + { + if (m_Translation) + m_Translation->OnNudge(inNudgeDirection, inToolMode, inFlags, m_UpdatableEditor); + } + + void OnNudgeDone() override + { + if (m_Translation) + m_Translation->OnNudgeFinished(); + m_UpdatableEditor.CommitEditor(); + } + + void OnToolbarChange() override { RequestRender(); } +}; +} + +std::shared_ptr IStudioRenderer::CreateStudioRenderer() +{ + return std::make_shared(); +} diff --git a/src/Authoring/Studio/Render/StudioRendererImpl.h b/src/Authoring/Studio/Render/StudioRendererImpl.h new file mode 100644 index 00000000..86ce4f0b --- /dev/null +++ b/src/Authoring/Studio/Render/StudioRendererImpl.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 UIC_STUDIO_RENDERER_IMPL_H +#define UIC_STUDIO_RENDERER_IMPL_H +#pragma once +#include "IStudioRenderer.h" +#include "WGLRenderContext.h" +#include "UICDMDataTypes.h" +#include "UICDMSignals.h" +#include "UICRenderContext.h" +#include "StudioApp.h" +#include "Doc.h" +#include "UICDMStudioSystem.h" +#include "ClientDataModelBridge.h" +#include "IDocumentReader.h" +#include "UICFileTools.h" +#include "render/Qt3DSRenderContext.h" +#include "foundation/Qt3DSVec4.h" +#include "DispatchListeners.h" +#include "Dispatch.h" +#include "Core.h" +#include "foundation/Qt3DSInvasiveSet.h" +#include "UICRenderer.h" +#include "UICRenderScene.h" +#include "UICRenderNode.h" +#include "UICRenderLayer.h" +#include "UICRenderModel.h" +#include "UICRenderDefaultMaterial.h" +#include "UICRenderLight.h" +#include "UICRenderCamera.h" +#include "UICRenderImage.h" +#include "UICRenderPresentation.h" +#include "StudioProjectSettings.h" +#include "UICRenderUIPSharedTranslation.h" +#include "UICRenderBufferManager.h" +#include "StudioFullSystem.h" +#include "UICDMSignals.h" +#include "CoreConst.h" +#include "IDocumentEditor.h" +#include "foundation/Qt3DSPlane.h" +#include "foundation/Qt3DSQuat.h" +#include "UICTextRenderer.h" +#include "foundation/Qt3DSOption.h" +#include "foundation/Qt3DSMathUtils.h" +#include "UICRenderEffect.h" +#include "UICRenderPath.h" +#include "UICRenderPathSubPath.h" + +namespace uic { +namespace studio { + using Q3DStudio::IDocumentReader; + using Q3DStudio::CUpdateableDocumentEditor; + using Q3DStudio::TIdentifier; + using Q3DStudio::IStudioRenderer; + using qt3ds::foundation::NVScopedRefCounted; + using qt3ds::QT3DSVec3; + using qt3ds::QT3DSQuat; + using qt3ds::QT3DSF32; + using qt3ds::QT3DSMat44; + using qt3ds::QT3DSMat33; + using qt3ds::QT3DSI32; + using qt3ds::QT3DSVec2; + using qt3ds::QT3DSVec4; + using qt3ds::NVMax; + using qt3ds::NVMin; + using qt3ds::QT3DSU32; + using qt3ds::foundation::Empty; + using qt3ds::foundation::InvasiveSet; + using qt3ds::foundation::nvhash_map; + using qt3ds::foundation::nvvector; + using qt3ds::foundation::rotationArc; + using qt3ds::foundation::Option; + using qt3ds::foundation::Empty; + using uic::render::IUICRenderContext; + using uic::render::SScene; + using uic::render::SLayer; + using uic::render::SNode; + using uic::render::SGraphObject; + using uic::render::SLight; + using uic::render::SCamera; + using uic::render::SDefaultMaterial; + using uic::render::SImage; + using uic::render::SModel; + using uic::render::SText; + using uic::render::GraphObjectTypes; + using uic::render::SRay; + using uic::render::ITextRenderer; + using uic::render::SEffect; + using uic::render::IEffectSystem; + using uic::render::SDynamicObject; + using uic::render::SCustomMaterial; + using uic::render::IDynamicObjectSystem; + using uic::render::ICustomMaterialSystem; + using uic::render::IBufferManager; + using uic::render::IPathManager; + using uic::render::SPath; + using uic::render::SPathSubPath; + using uic::render::SReferencedMaterial; + using qt3ds::render::CRegisteredString; + using qt3ds::render::IStringTable; + using UICDM::SFloat3; + using UICDM::SLong4; + using UICDM::SComposerObjectDefinitions; + using UICDM::CUICDMInstanceHandle; + using UICDM::CUICDMPropertyHandle; +} +} +#endif diff --git a/src/Authoring/Studio/Render/StudioRendererTranslation.cpp b/src/Authoring/Studio/Render/StudioRendererTranslation.cpp new file mode 100644 index 00000000..7efca4a4 --- /dev/null +++ b/src/Authoring/Studio/Render/StudioRendererTranslation.cpp @@ -0,0 +1,3827 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "StudioRendererImpl.h" +#include "StudioRendererTranslation.h" +#include "UICRenderEffectSystem.h" +#include "foundation/StrConvertUTF.h" +#include "UICFileTools.h" +#include "UICRenderUIPLoader.h" +#include "UICRenderWidgets.h" +#include "foundation/Qt3DSBounds3.h" +#include "UICRenderResourceManager.h" +#include "render/Qt3DSRenderFrameBuffer.h" +#include "UICRenderCamera.h" +#include "foundation/Qt3DSPlane.h" +#include "UICRenderRotationHelper.h" +#include "UICRenderPluginGraphObject.h" +#include "UICRenderPlugin.h" +#include "StudioCoreSystem.h" +#include "UICDMDataCore.h" +#include "UICRenderPluginPropertyValue.h" +#include "UICRenderEffectSystem.h" +#include "render/Qt3DSRenderShaderProgram.h" +#include "UICRenderMaterialHelpers.h" +#include "UICRenderDynamicObjectSystem.h" +#include "UICRenderCustomMaterialSystem.h" +#include "UICRenderReferencedMaterial.h" +#include "UICRenderPixelGraphicsTypes.h" +#include "UICRenderPixelGraphicsRenderer.h" +#include "UICRenderPathManager.h" +#include "PathWidget.h" +#include "UICRenderLightmaps.h" +#include "StudioPreferences.h" +#include "HotKeys.h" +#include + +#pragma warning(disable : 4100) // unreferenced formal parameter + +using namespace uic::studio; +QT3DSU32 uic::studio::g_GraphObjectTranslatorTag; +using uic::render::SPGGraphObject; +using uic::render::SPGRect; +using uic::render::SPGVertLine; +using uic::render::SPGHorzLine; +using qt3ds::render::NVRenderRectF; +using qt3ds::render::NVRenderRect; + +namespace { +using namespace UICDM; +struct STranslatorUICDMParser +{ + STranslation &m_Context; + CUICDMInstanceHandle m_InstanceHandle; + STranslatorUICDMParser(STranslation &inContext, CUICDMInstanceHandle inInstance) + : m_Context(inContext) + , m_InstanceHandle(inInstance) + { + } + CUICDMInstanceHandle GetInstanceHandle() { return m_InstanceHandle; } + + template + inline Option GetPropertyValue(UICDM::CUICDMPropertyHandle inProperty) + { + Option theValue = + m_Context.m_Reader.GetRawInstancePropertyValue(GetInstanceHandle(), inProperty); + if (theValue.hasValue()) + return UICDM::get(*theValue); + return Empty(); + } + + bool ParseProperty(CUICDMPropertyHandle inProperty, QT3DSF32 &outValue) + { + Option theValue = GetPropertyValue(inProperty); + if (theValue.hasValue()) { + outValue = theValue.getValue(); + return true; + } + return false; + } + + bool ParseProperty(CUICDMPropertyHandle inProperty, QT3DSU32 &outValue) + { + auto theValue = GetPropertyValue(inProperty); + if (theValue.hasValue()) { + outValue = NVMax(theValue.getValue(), 0); + return true; + } + return false; + } + + bool ParseProperty(CUICDMPropertyHandle inProperty, QT3DSI32 &outValue) + { + auto theValue = GetPropertyValue(inProperty); + if (theValue.hasValue()) { + outValue = *theValue; + return true; + } + return false; + } + + bool ParseRadianProperty(CUICDMPropertyHandle inProperty, QT3DSF32 &outValue) + { + if (ParseProperty(inProperty, outValue)) { + TORAD(outValue); + return true; + } + return false; + } + bool ParseRadianProperty(CUICDMPropertyHandle inProperty, QT3DSVec3 &outValue) + { + if (ParseProperty(inProperty, outValue)) { + TORAD(outValue.x); + TORAD(outValue.y); + TORAD(outValue.z); + return true; + } + return false; + } + bool ParseOpacityProperty(CUICDMPropertyHandle inProperty, QT3DSF32 &outValue) + { + if (ParseProperty(inProperty, outValue)) { + outValue = (1.0f / 100.0f) * outValue; + return true; + } + return false; + } + bool ParseRotationOrder(CUICDMPropertyHandle inProperty, QT3DSU32 &outValue) + { + qt3ds::render::CRegisteredString temp; + if (ParseProperty(inProperty, temp)) { + outValue = uic::render::MapRotationOrder(temp); + return true; + } + return false; + } + bool ParseOrientation(CUICDMPropertyHandle inProperty, uic::render::NodeFlags &outValue) + { + qt3ds::render::CRegisteredString temp; + if (ParseProperty(inProperty, temp)) { + bool isLeftHanded = strcmp(temp.c_str(), "Left Handed") == 0; + outValue.SetLeftHanded(isLeftHanded); + return true; + } + return false; + } + + bool ParseProperty(CUICDMPropertyHandle inProperty, bool &outValue) + { + Option theValue = GetPropertyValue(inProperty); + if (theValue.hasValue()) { + outValue = theValue.getValue(); + return true; + } + return false; + } + bool ParseProperty(CUICDMPropertyHandle inProperty, QT3DSVec2 &outValue) + { + Option theValue = GetPropertyValue(inProperty); + if (theValue.hasValue()) { + outValue = QT3DSVec2(theValue->m_Floats[0], theValue->m_Floats[1]); + return true; + } + return false; + } + bool ParseProperty(CUICDMPropertyHandle inProperty, QT3DSVec3 &outValue) + { + Option theValue = GetPropertyValue(inProperty); + if (theValue.hasValue()) { + outValue = QT3DSVec3(theValue->m_Floats[0], theValue->m_Floats[1], theValue->m_Floats[2]); + return true; + } + return false; + } + bool ParseProperty(CUICDMPropertyHandle inProperty, qt3ds::render::CRegisteredString &outValue) + { + Option theValue = GetPropertyValue(inProperty); + if (theValue.hasValue() && *theValue) { + qt3ds::render::IStringTable &theStrTable(m_Context.m_UICContext.GetStringTable()); + outValue = theStrTable.RegisterStr((*theValue)->GetData()); + return true; + } + return false; + } + + bool ParseAndResolveSourcePath(UICDM::CUICDMPropertyHandle inProperty, + qt3ds::render::CRegisteredString &outValue) + { + if (ParseProperty(inProperty, outValue)) { + if (outValue.IsValid() && outValue.c_str()[0] != '#') { + Q3DStudio::CFilePath theDirectory = m_Context.m_Doc.GetDocumentDirectory(); + Q3DStudio::CFilePath theResolvedPath = + Q3DStudio::CFilePath::CombineBaseAndRelative(theDirectory, outValue.c_str()); + outValue = + m_Context.m_UICContext.GetStringTable().RegisterStr(theResolvedPath.c_str()); + } + return true; + } + return false; + } + + template + bool ParseEnumProperty(UICDM::CUICDMPropertyHandle inProperty, TEnumType &ioValue) + { + qt3ds::render::CRegisteredString temp; + if (ParseProperty(inProperty, temp)) { + uic::render::SEnumNameMap *theNameMap(uic::render::SEnumParseMap::GetMap()); + for (uic::render::SEnumNameMap *theIter = theNameMap; + theIter->m_Name && *theIter->m_Name; ++theIter) { + // hack to match advanced overlay types, whose name start with a '*' + const char8_t *p = temp; + if (*p == '*') + ++p; + if (strcmp(p, theIter->m_Name) == 0) { + ioValue = (TEnumType)theIter->m_Enum; + return true; + } + } + } + return false; + } + + bool ParseNodeFlagsProperty(UICDM::CUICDMPropertyHandle inProperty, + uic::render::NodeFlags &outValue, + uic::render::NodeFlagValues::Enum theFlag) + { + bool temp = false; + if (ParseProperty(inProperty, temp)) { + outValue.ClearOrSet(temp, theFlag); + return true; + } + return false; + } + bool ParseNodeFlagsInverseProperty(UICDM::CUICDMPropertyHandle inProperty, + uic::render::NodeFlags &outValue, + uic::render::NodeFlagValues::Enum theFlag) + { + bool temp = false; + if (ParseProperty(inProperty, temp)) { + outValue.ClearOrSet(!temp, theFlag); + return true; + } + return false; + } + bool ParseProperty(CUICDMPropertyHandle inProperty, uic::render::SImage *&ioImage) + { + Option theData = GetPropertyValue(inProperty); + if (theData.hasValue()) { + UICDM::CUICDMInstanceHandle theInstance( + m_Context.m_Reader.GetInstanceForGuid(*theData)); + SGraphObjectTranslator *imageTranslator = m_Context.GetOrCreateTranslator(theInstance); + if (imageTranslator + && imageTranslator->GetGraphObject().m_Type + == uic::render::GraphObjectTypes::Image) { + SImage *theNewImage = static_cast(&imageTranslator->GetGraphObject()); + ioImage = theNewImage; + } else + ioImage = nullptr; + return true; + } + return false; + } + + bool ParseProperty(CUICDMPropertyHandle inProperty, uic::render::SGraphObject *&ioObjRef) + { + Option theData = GetPropertyValue(inProperty); + if (theData.hasValue()) { + UICDM::CUICDMInstanceHandle theInstance( + m_Context.m_Reader.GetInstanceForObjectRef(m_InstanceHandle, *theData)); + SGraphObjectTranslator *theItemTranslator = + m_Context.GetOrCreateTranslator(theInstance); + if (theItemTranslator) + ioObjRef = &theItemTranslator->GetGraphObject(); + } + return true; + } + + bool ParseProperty(CUICDMPropertyHandle inProperty, uic::render::SNode *&ioNodePtr) + { + Option theData = GetPropertyValue(inProperty); + SNode *theNewNodePtr = nullptr; + if (theData.hasValue()) { + UICDM::CUICDMInstanceHandle theInstance( + m_Context.m_Reader.GetInstanceForObjectRef(m_InstanceHandle, *theData)); + SGraphObjectTranslator *theItemTranslator = + m_Context.GetOrCreateTranslator(theInstance); + if (theItemTranslator) { + SGraphObject &theObject = theItemTranslator->GetGraphObject(); + if (GraphObjectTypes::IsNodeType(theObject.m_Type)) + theNewNodePtr = &static_cast(theObject); + } + } + ioNodePtr = theNewNodePtr; + return true; + } +}; + +// Define parse tables +#define Scene_ClearColor m_Scene.m_BackgroundColor +#define Scene_UseClearColor m_Scene.m_BgColorEnable +#define Node_Rotation m_Node.m_Rotation +#define Node_Position m_Node.m_Position +#define Node_Scale m_Node.m_Scale +#define Node_Pivot m_Node.m_Pivot +#define Node_LocalOpacity m_Node.m_Opacity +#define Node_RotationOrder m_Node.m_RotationOrder +#define Node_LeftHanded m_Node.m_Orientation +#define Layer_TemporalAAEnabled m_Layer.m_TemporalAA +#define Layer_LayerEnableDepthTest m_Layer.m_DisableDepthTest +#define Layer_LayerEnableDepthPrePass m_Layer.m_DisableDepthPrepass +#define Layer_ClearColor m_Layer.m_BackgroundColor +#define Layer_Background m_Layer.m_Background +#define Layer_BlendType m_Layer.m_BlendType +#define Layer_Size m_Layer.m_Size +#define Layer_Location m_Layer.m_Location +#define Layer_ProgressiveAAMode m_Layer.m_ProgressiveAA +#define Layer_MultisampleAAMode m_Layer.m_MultisampleAA +#define Layer_HorizontalFieldValues m_Layer.m_HorizontalFieldValues +#define Layer_Left m_Layer.m_Left +#define Layer_LeftUnits m_Layer.m_LeftUnits +#define Layer_Width m_Layer.m_Width +#define Layer_WidthUnits m_Layer.m_WidthUnits +#define Layer_Right m_Layer.m_Right +#define Layer_RightUnits m_Layer.m_RightUnits +#define Layer_VerticalFieldValues m_Layer.m_VerticalFieldValues +#define Layer_Top m_Layer.m_Top +#define Layer_TopUnits m_Layer.m_TopUnits +#define Layer_Height m_Layer.m_Height +#define Layer_HeightUnits m_Layer.m_HeightUnits +#define Layer_Bottom m_Layer.m_Bottom +#define Layer_BottomUnits m_Layer.m_BottomUnits +#define Layer_AoStrength m_Layer.m_AoStrength +#define Layer_AoDistance m_Layer.m_AoDistance +#define Layer_AoSoftness m_Layer.m_AoSoftness +#define Layer_AoBias m_Layer.m_AoBias +#define Layer_AoSamplerate m_Layer.m_AoSamplerate +#define Layer_AoDither m_Layer.m_AoDither +#define Layer_ShadowStrength m_Layer.m_ShadowStrength +#define Layer_ShadowDist m_Layer.m_ShadowDist +#define Layer_ShadowSoftness m_Layer.m_ShadowSoftness +#define Layer_ShadowBias m_Layer.m_ShadowBias +#define Layer_LightProbe m_Layer.m_LightProbe +#define Layer_ProbeBright m_Layer.m_ProbeBright +#define Layer_FastIbl m_Layer.m_FastIbl +#define Layer_ProbeHorizon m_Layer.m_ProbeHorizon +#define Layer_ProbeFov m_Layer.m_ProbeFov +#define Layer_LightProbe2 m_Layer.m_LightProbe2 +#define Layer_Probe2Fade m_Layer.m_Probe2Fade +#define Layer_Probe2Window m_Layer.m_Probe2Window +#define Layer_Probe2Pos m_Layer.m_Probe2Pos +#define Layer_TexturePath m_Asset.m_SourcePath +#define Camera_ClipNear m_Camera.m_ClipNear +#define Camera_ClipFar m_Camera.m_ClipFar +#define Camera_FOV m_Camera.m_Fov +#define Camera_Orthographic m_Camera.m_Orthographic +#define Camera_ScaleMode m_Camera.m_ScaleMode +#define Camera_ScaleAnchor m_Camera.m_ScaleAnchor +#define Light_LightType m_Light.m_LightType +#define Light_Scope m_Light.m_Scope +#define Light_DiffuseColor m_Light.m_LightColor +#define Light_SpecularColor m_Light.m_SpecularColor +#define Light_AmbientColor m_Light.m_AmbientColor +#define Light_Brightness m_Light.m_Brightness +#define Light_LinearFade m_Light.m_LinearFade +#define Light_ExponentialFade m_Light.m_ExpFade +#define Light_AreaWidth m_Light.m_AreaWidth +#define Light_AreaHeight m_Light.m_AreaHeight +#define Light_CastShadow m_Light.m_CastShadow +#define Light_ShadowBias m_Light.m_ShadowBias +#define Light_ShadowFactor m_Light.m_ShadowFactor +#define Light_ShadowMapRes m_Light.m_ShadowMapRes +#define Light_ShadowMapFar m_Light.m_ShadowMapFar +#define Light_ShadowFilter m_Light.m_ShadowFilter +#define Model_MeshPath m_Asset.m_SourcePath +#define Model_TessellationMode m_Model.m_Tessellation +#define Model_EdgeTess m_Model.m_EdgeTess +#define Model_InnerTess m_Model.m_InnerTess +#define Lightmaps_LightmapIndirect m_Lightmaps.m_LightmapIndirect +#define Lightmaps_LightmapRadiosity m_Lightmaps.m_LightmapRadiosity +#define Lightmaps_LightmapShadow m_Lightmaps.m_LightmapShadow +#define MaterialBase_IblProbe m_MaterialBase.m_IblProbe +#define Material_Lighting m_Material.m_ShaderLighting +#define Material_BlendMode m_Material.m_BlendMode +#define Material_DiffuseColor m_Material.m_DiffuseColor +#define Material_DiffuseMaps_0 m_Material.m_DiffuseMap1 +#define Material_DiffuseMaps_1 m_Material.m_DiffuseMap2 +#define Material_DiffuseMaps_2 m_Material.m_DiffuseMap3 +#define Material_EmissivePower m_Material.m_EmissivePower +#define Material_EmissiveColor m_Material.m_EmissiveColor +#define Material_EmissiveMap m_Material.m_EmissiveMap +#define Material_EmissiveMap2 m_Material.m_EmissiveMap2 +#define Material_SpecularReflection m_Material.m_SpecularReflection +#define Material_SpecularMap m_Material.m_SpecularMap +#define Material_SpecularModel m_Material.m_SpecularModel +#define Material_SpecularTint m_Material.m_SpecularTint +#define Material_IOR m_Material.m_IOR +#define Material_FresnelPower m_Material.m_FresnelPower +#define Material_SpecularAmount m_Material.m_SpecularAmount +#define Material_SpecularRoughness m_Material.m_SpecularRoughness +#define Material_Opacity m_Material.m_Opacity +#define Material_OpacityMap m_Material.m_OpacityMap +#define Material_BumpMap m_Material.m_BumpMap +#define Material_BumpAmount m_Material.m_BumpAmount +#define Material_NormalMap m_Material.m_NormalMap +#define Material_DisplacementMap m_Material.m_DisplacementMap +#define Material_DisplaceAmount m_Material.m_DisplaceAmount +#define Material_TranslucencyMap m_Material.m_TranslucencyMap +#define Material_TranslucentFalloff m_Material.m_TranslucentFalloff +#define Material_DiffuseLightWrap m_Material.m_DiffuseLightWrap +#define Material_ReferencedMaterial m_ReferencedMaterial.m_ReferencedMaterial +#define Image_ImagePath m_Asset.m_SourcePath +#define Image_OffscreenRendererId m_Image.m_SubPresentation +#define Image_Scale_X m_Image.m_RepeatU +#define Image_Scale_Y m_Image.m_RepeatV +#define Image_Pivot_X m_Image.m_PivotU +#define Image_Pivot_Y m_Image.m_PivotV +#define Image_Rotation m_Image.m_RotationUV +#define Image_Position_X m_Image.m_PositionU +#define Image_Position_Y m_Image.m_PositionV +#define Image_MappingMode m_Image.m_TextureMapping +#define Image_HorizontalTilingMode m_Image.m_TilingU +#define Image_VerticalTilingMode m_Image.m_TilingV +#define Text_Text m_Text.m_TextString +#define Text_Font m_Text.m_Font +#define Text_FontSize m_Text.m_Size +#define Text_HorizontalAlignment m_Text.m_HorzAlign +#define Text_VerticalAlignment m_Text.m_VertAlign +#define Text_Leading m_Text.m_Leading +#define Text_Tracking m_Text.m_Tracking +#define Text_TextColor m_Text.m_TextColor +#define Text_EnableAcceleratedFont m_Text.m_EnableAcceleratedFont +#define Path_Width m_Path.m_Width +#define Path_LinearError m_Path.m_LinearError +#define Path_InnerTessAmount m_Path.m_InnerTessAmount +#define Path_EdgeTessAmount m_Path.m_EdgeTessAmount +#define Path_Opacity m_Path.m_Opacity +#define Path_BeginCapping m_Path.m_BeginCap +#define Path_BeginCapOffset m_Path.m_BeginCapOffset +#define Path_BeginCapOpacity m_Path.m_BeginCapOpacity +#define Path_BeginCapWidth m_Path.m_BeginCapWidth +#define Path_EndCapping m_Path.m_EndCap +#define Path_EndCapOffset m_Path.m_EndCapOffset +#define Path_EndCapOpacity m_Path.m_EndCapOpacity +#define Path_EndCapWidth m_Path.m_EndCapWidth +#define Path_PathType m_Path.m_PathType +#define Path_PaintStyle m_Path.m_PaintStyle +#define Path_PathBuffer m_Asset.m_SourcePath +#define SubPath_Closed m_SubPath.m_Closed + +// Fill in implementations for the actual parse tables. +#define HANDLE_UIC_RENDER_PROPERTY(type, name, dirty) \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_UIC_RENDER_VEC3_PROPERTY(type, name, dirty) \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_UIC_RENDER_REAL_VEC2_PROPERTY(type, name, dirty) \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_UIC_RENDER_COLOR_PROPERTY(type, name, dirty) \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_UIC_RENDER_RADIAN_PROPERTY(type, name, dirty) \ + theParser.ParseRadianProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_UIC_RENDER_VEC3_RADIAN_PROPERTY(type, name, dirty) \ + theParser.ParseRadianProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_UIC_RENDER_OPACITY_PROPERTY(type, name, dirty) \ + theParser.ParseOpacityProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_UIC_ROTATION_ORDER_PROPERTY(type, name, dirty) \ + theParser.ParseRotationOrder(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_UIC_NODE_ORIENTATION_PROPERTY(type, name, dirty) \ + theParser.ParseOrientation(inContext.m_ObjectDefinitions.type##_##name, theItem.m_Flags); +#define HANDLE_UIC_RENDER_DEPTH_TEST_PROPERTY(type, name, dirty) \ + if (theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name)) \ + theItem.m_##name = !theItem.m_##name; +#define HANDLE_UIC_NODE_FLAGS_PROPERTY(type, name, dirty) \ + theParser.ParseNodeFlagsProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_Flags, \ + uic::render::NodeFlagValues::name); +#define HANDLE_UIC_NODE_FLAGS_INVERSE_PROPERTY(type, name, dirty) \ + theParser.ParseNodeFlagsInverseProperty(inContext.m_ObjectDefinitions.type##_##name, \ + theItem.m_Flags, uic::render::NodeFlagValues::name); +#define HANDLE_UIC_RENDER_ENUM_PROPERTY(type, name, dirty) \ + theParser.ParseEnumProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_UIC_RENDER_SOURCEPATH_PROPERTY(type, name, dirty) \ + theParser.ParseAndResolveSourcePath(inContext.m_ObjectDefinitions.type##_##name, \ + theItem.m_##name); +#define HANDLE_UIC_RENDER_ARRAY_PROPERTY(type, name, index, dirty) \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name##_##index, \ + theItem.m_##name[index]); +#define HANDLE_UIC_RENDER_VEC2_PROPERTY(type, name, dirty) \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name##_##X, \ + theItem.m_##name.x); \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name##_##Y, theItem.m_##name.y); +#define HANDLE_UIC_RENDER_COLOR_VEC3_PROPERTY( \ + type, name, dirty) // noop by intention already handled by HANDLE_UIC_RENDER_COLOR_PROPERTY +#define HANDLE_UIC_RENDER_TRANSFORM_VEC3_PROPERTY( \ + type, name, dirty) // noop by intention already handled by HANDLE_UIC_RENDER_VEC3_PROPERTY + +struct SSceneTranslator : public SGraphObjectTranslator +{ + SSceneTranslator(UICDM::CUICDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SScene)()) + { + } + + void PushTranslation(STranslation &inContext) override + { + SScene &theItem = static_cast(GetGraphObject()); + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + ITERATE_UIC_RENDER_SCENE_PROPERTIES + SLayer *theCurrentLayer = nullptr; + theItem.m_FirstChild = nullptr; + for (long idx = 0, end = inContext.m_AssetGraph.GetChildCount(GetInstanceHandle()); + idx < end; ++idx) { + SGraphObjectTranslator::PushTranslation(inContext); + UICDM::CUICDMInstanceHandle theLayer = + inContext.m_AssetGraph.GetChild(GetInstanceHandle(), idx); + SGraphObjectTranslator *theTranslator = inContext.GetOrCreateTranslator(theLayer); + if (theTranslator + && theTranslator->GetGraphObject().m_Type == uic::render::GraphObjectTypes::Layer) { + SLayer *theLayerObj = static_cast(&theTranslator->GetGraphObject()); + theLayerObj->m_NextSibling = nullptr; + if (theItem.m_FirstChild == nullptr) + theItem.m_FirstChild = theLayerObj; + else + theCurrentLayer->m_NextSibling = theLayerObj; + theCurrentLayer = theLayerObj; + } + } + } + void ClearChildren() override + { + SScene &theItem = static_cast(GetGraphObject()); + SLayer *theLastChild = nullptr; + for (SLayer *theChild = theItem.m_FirstChild; theChild; + theChild = static_cast(theChild->m_NextSibling)) { + if (theLastChild) + theLastChild->m_NextSibling = nullptr; + theChild->m_Parent = nullptr; + theLastChild = theChild; + } + theItem.m_FirstChild = nullptr; + } + void AppendChild(SGraphObject &inChild) override + { + if (inChild.m_Type != GraphObjectTypes::Layer) { + QT3DS_ASSERT(false); + return; + } + SScene &theItem = static_cast(GetGraphObject()); + SLayer &theLayer = static_cast(inChild); + theItem.AddChild(theLayer); + } + void SetActive(bool /*inActive*/) override + { + // How could we not be active? + } +}; + +struct SNodeTranslator : public SGraphObjectTranslator +{ + SNodeTranslator(UICDM::CUICDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SNode)()) + { + Initialize(); + } + SNodeTranslator(UICDM::CUICDMInstanceHandle inInstance, SNode &inNode) + : SGraphObjectTranslator(inInstance, inNode) + { + Initialize(); + } + void Initialize() + { + SNode &theNode = static_cast(GetGraphObject()); + // Ensure the global transform is valid because we use this before we render sometimes. + theNode.m_GlobalTransform = QT3DSMat44::createIdentity(); + } + static inline bool IsNodeType(uic::render::GraphObjectTypes::Enum inType) + { + return uic::render::GraphObjectTypes::IsNodeType(inType); + } + void PushTranslation(STranslation &inContext) override + { + SGraphObjectTranslator::PushTranslation(inContext); + SNode &theItem = static_cast(GetGraphObject()); + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + ITERATE_UIC_RENDER_NODE_PROPERTIES + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Node.m_BoneId, + theItem.m_SkeletonId); + bool ignoresParent = false; + if (theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Node.m_IgnoresParent, + ignoresParent)) + theItem.m_Flags.SetIgnoreParentTransform(ignoresParent); + } + void AppendChild(SGraphObject &inChild) override + { + if (GraphObjectTypes::IsNodeType(inChild.m_Type) == false) { + QT3DS_ASSERT(false); + return; + } + + SNode &theItem = static_cast(GetGraphObject()); + SNode &theChild = static_cast(inChild); + theItem.AddChild(theChild); + theItem.MarkDirty(uic::render::NodeTransformDirtyFlag::TransformIsDirty); + theChild.MarkDirty(uic::render::NodeTransformDirtyFlag::TransformIsDirty); + } + void ClearChildren() override + { + SNode &theItem = static_cast(GetGraphObject()); + SNode *theLastChild = nullptr; + for (SNode *theChild = theItem.m_FirstChild; theChild; theChild = theChild->m_NextSibling) { + if (theLastChild) + theLastChild->m_NextSibling = nullptr; + theLastChild = theChild; + theChild->m_Parent = nullptr; + } + theItem.m_FirstChild = nullptr; + } + + void SetActive(bool inActive) override + { + SNode &theNode = static_cast(GetGraphObject()); + if (inActive != theNode.m_Flags.IsActive()) { + theNode.m_Flags.SetActive(inActive); + theNode.MarkDirty(uic::render::NodeTransformDirtyFlag::TransformIsDirty); + } + } +}; + +struct SLayerTranslator : public SNodeTranslator +{ + SLayerTranslator(UICDM::CUICDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SNodeTranslator(inInstance, *QT3DS_NEW(inAlloc, SLayer)()) + { + } + void PushTranslation(STranslation &inContext) override + { + SNodeTranslator::PushTranslation(inContext); + SLayer &theItem = static_cast(GetGraphObject()); + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + ITERATE_UIC_RENDER_LAYER_PROPERTIES + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Layer.m_AoSamplerate, + theItem.m_AoSamplerate); + } + void AppendChild(SGraphObject &inChild) override + { + if (GraphObjectTypes::IsNodeType(inChild.m_Type)) { + SNodeTranslator::AppendChild(inChild); + } else if (inChild.m_Type == GraphObjectTypes::Effect) { + SLayer &theItem = static_cast(GetGraphObject()); + theItem.AddEffect(static_cast(inChild)); + } else if (inChild.m_Type == GraphObjectTypes::RenderPlugin) { + SLayer &theItem = static_cast(GetGraphObject()); + theItem.m_RenderPlugin = &static_cast(inChild); + } + } + void ClearChildren() override + { + SNodeTranslator::ClearChildren(); + SLayer &theItem = static_cast(GetGraphObject()); + SEffect *theLastChild = nullptr; + for (SEffect *theChild = theItem.m_FirstEffect; theChild; + theChild = theChild->m_NextEffect) { + if (theLastChild) + theLastChild->m_NextEffect = nullptr; + theLastChild = theChild; + theChild->m_Layer = nullptr; + } + theItem.m_FirstEffect = nullptr; + theItem.m_RenderPlugin = nullptr; + // Don't clear the light probe properties because those are added/removed as part of the + // normal + // property scan, they aren't added as generic children. + } +}; +struct SLightTranslator : public SNodeTranslator +{ + SLightTranslator(UICDM::CUICDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SNodeTranslator(inInstance, *QT3DS_NEW(inAlloc, SLight)()) + { + } + void PushTranslation(STranslation &inContext) override + { + SNodeTranslator::PushTranslation(inContext); + SLight &theItem = static_cast(GetGraphObject()); + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + ITERATE_UIC_RENDER_LIGHT_PROPERTIES + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Light.m_ShadowMapRes, + theItem.m_ShadowMapRes); + } + void AppendChild(SGraphObject &inChild) override { SNodeTranslator::AppendChild(inChild); } + void ClearChildren() override { SNodeTranslator::ClearChildren(); } +}; +struct SCameraTranslator : public SNodeTranslator +{ + SCameraTranslator(UICDM::CUICDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SNodeTranslator(inInstance, *QT3DS_NEW(inAlloc, SCamera)()) + { + } + void PushTranslation(STranslation &inContext) override + { + SNodeTranslator::PushTranslation(inContext); + SCamera &theItem = static_cast(GetGraphObject()); + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + ITERATE_UIC_RENDER_CAMERA_PROPERTIES + } +}; +struct SModelTranslator : public SNodeTranslator +{ + SModelTranslator(UICDM::CUICDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SNodeTranslator(inInstance, *QT3DS_NEW(inAlloc, SModel)()) + { + } + void PushTranslation(STranslation &inContext) override + { + SNodeTranslator::PushTranslation(inContext); + SModel &theItem = static_cast(GetGraphObject()); + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + ITERATE_UIC_RENDER_MODEL_PROPERTIES + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Model.m_PoseRoot, + theItem.m_SkeletonRoot); + + theItem.m_FirstMaterial = nullptr; + for (long idx = 0, end = inContext.m_AssetGraph.GetChildCount(GetInstanceHandle()); + idx < end; ++idx) { + UICDM::CUICDMInstanceHandle theItemHandle = + inContext.m_AssetGraph.GetChild(GetInstanceHandle(), idx); + SGraphObjectTranslator *theTranslator = inContext.GetOrCreateTranslator(theItemHandle); + if (theTranslator && IsMaterial(theTranslator->GetGraphObject())) { + SGraphObject *theMaterial = &theTranslator->GetGraphObject(); + SetNextMaterialSibling(*theMaterial, nullptr); + theItem.AddMaterial(*theMaterial); + } + } + } + void AppendChild(SGraphObject &inChild) override + { + if (GraphObjectTypes::IsNodeType(inChild.m_Type)) { + SNodeTranslator::AppendChild(inChild); + } else if (IsMaterial(inChild)) { + SModel &theItem = static_cast(GetGraphObject()); + theItem.AddMaterial(inChild); + } else { + QT3DS_ASSERT(false); + } + } + void ClearChildren() override + { + SModel &theItem = static_cast(GetGraphObject()); + SNodeTranslator::ClearChildren(); + + SGraphObject *theLastMaterial = nullptr; + for (SGraphObject *theMaterial = theItem.m_FirstMaterial; theMaterial; + theMaterial = uic::render::GetNextMaterialSibling(theMaterial)) { + if (theLastMaterial) + uic::render::SetNextMaterialSibling(*theLastMaterial, nullptr); + theLastMaterial = theMaterial; + } + theItem.m_FirstMaterial = nullptr; + } +}; + +static SFloat2 ToFloat2(const Option &inValue) +{ + if (inValue.hasValue()) + return inValue->getData(); + return SFloat2(); +} + +static float ToFloat(const Option &inValue) +{ + if (inValue.hasValue()) + return inValue->getData(); + return 0.0f; +} + +struct SPathSubPathTranslator : public SGraphObjectTranslator +{ + eastl::vector m_PathBuffer; + SPathSubPathTranslator(UICDM::CUICDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SPathSubPath)()) + { + } + + void PushTranslation(STranslation &inContext) override + { + SPathSubPath &theItem = static_cast(GetGraphObject()); + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + ITERATE_UIC_RENDER_PATH_SUBPATH_PROPERTIES + m_PathBuffer.clear(); + Q3DStudio::IDocumentReader &theReader(inContext.m_Doc.GetDocumentReader()); + QT3DSU32 anchorCount = 0; + for (QT3DSI32 idx = 0, end = inContext.m_AssetGraph.GetChildCount(GetInstanceHandle()); + idx < end; ++idx) { + UICDM::CUICDMInstanceHandle theAnchor = + inContext.m_AssetGraph.GetChild(GetInstanceHandle(), idx); + if (theReader.GetObjectTypeName(theAnchor) == L"PathAnchorPoint") + ++anchorCount; + } + QT3DSU32 anchorIdx = 0; + for (QT3DSI32 idx = 0, end = inContext.m_AssetGraph.GetChildCount(GetInstanceHandle()); + idx < end; ++idx) { + UICDM::CUICDMInstanceHandle theAnchor = + inContext.m_AssetGraph.GetChild(GetInstanceHandle(), idx); + if (theReader.GetObjectTypeName(theAnchor) == L"PathAnchorPoint") { + SFloat2 theAnchorPos = ToFloat2(theReader.GetInstancePropertyValue( + theAnchor, + inContext.m_ObjectDefinitions.m_PathAnchorPoint.m_Position.m_Property)); + float theIncomingAngle = ToFloat(theReader.GetInstancePropertyValue( + theAnchor, + inContext.m_ObjectDefinitions.m_PathAnchorPoint.m_IncomingAngle.m_Property)); + float theIncomingDistance = ToFloat(theReader.GetInstancePropertyValue( + theAnchor, + inContext.m_ObjectDefinitions.m_PathAnchorPoint.m_IncomingDistance.m_Property)); + float theOutgoingDistance = ToFloat(theReader.GetInstancePropertyValue( + theAnchor, + inContext.m_ObjectDefinitions.m_PathAnchorPoint.m_OutgoingDistance.m_Property)); + uic::render::SPathAnchorPoint thePoint(QT3DSVec2(theAnchorPos[0], theAnchorPos[1]), + theIncomingAngle, theIncomingAngle + 180.0f, + theIncomingDistance, theOutgoingDistance); + m_PathBuffer.push_back(thePoint); + ++anchorIdx; + } + } + inContext.m_UICContext.GetPathManager().SetPathSubPathData( + theItem, + qt3ds::foundation::toConstDataRef(m_PathBuffer.begin(), (QT3DSU32)m_PathBuffer.size())); + } + + void AppendChild(SGraphObject &) override {} + + void ClearChildren() override {} + + void SetActive(bool /*inActive*/) override {} +}; + +struct SPathTranslator : public SNodeTranslator +{ + SPathTranslator(UICDM::CUICDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SNodeTranslator(inInstance, *QT3DS_NEW(inAlloc, SPath)()) + { + } + void AppendChild(SGraphObject &inChild) override + { + if (GraphObjectTypes::IsMaterialType(inChild.m_Type)) { + SPath &theItem = static_cast(GetGraphObject()); + theItem.AddMaterial(&inChild); + theItem.m_Flags.SetDirty(true); + } else if (inChild.m_Type == GraphObjectTypes::PathSubPath) { + SPath &theItem = static_cast(GetGraphObject()); + theItem.AddSubPath(static_cast(inChild)); + theItem.m_Flags.SetDirty(true); + } else { + SNodeTranslator::AppendChild(inChild); + } + } + + void ClearChildren() override + { + SNodeTranslator::ClearChildren(); + SPath &theItem = static_cast(GetGraphObject()); + theItem.ClearMaterials(); + theItem.ClearSubPaths(); + } + + void PushTranslation(STranslation &inContext) override + { + SNodeTranslator::PushTranslation(inContext); + SPath &theItem = static_cast(GetGraphObject()); + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + ITERATE_UIC_RENDER_PATH_PROPERTIES + } +}; + +struct SDefaultMaterialTranslator : public SGraphObjectTranslator +{ + SDefaultMaterialTranslator(UICDM::CUICDMInstanceHandle inInstance, + qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SDefaultMaterial)()) + { + } + + void PushTranslation(STranslation &inContext) override + { + SGraphObjectTranslator::PushTranslation(inContext); + SDefaultMaterial &theItem = static_cast(GetGraphObject()); + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + ITERATE_UIC_RENDER_MATERIAL_PROPERTIES + + // UICDM::CUICDMInstanceHandle parent = inContext.m_AssetGraph.GetParent( + // GetInstanceHandle() ); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapIndirect, + theItem.m_Lightmaps.m_LightmapIndirect); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapRadiosity, + theItem.m_Lightmaps.m_LightmapRadiosity); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapShadow, + theItem.m_Lightmaps.m_LightmapShadow); + } + + void AppendChild(SGraphObject &) override {} + void ClearChildren() override {} + + void SetActive(bool /*inActive*/) override {} +}; + +struct SImageTranslator : public SGraphObjectTranslator +{ + SImageTranslator(UICDM::CUICDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SImage)()) + { + } + + void PushTranslation(STranslation &inContext) override + { + SGraphObjectTranslator::PushTranslation(inContext); + SImage &theItem = static_cast(GetGraphObject()); + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + ITERATE_UIC_RENDER_IMAGE_PROPERTIES + + theItem.m_Flags.SetDirty(true); + theItem.m_Flags.SetTransformDirty(true); + } + void AppendChild(SGraphObject &child) override + { + SImage &theItem = static_cast(GetGraphObject()); + if (child.m_Type == GraphObjectTypes::RenderPlugin) + theItem.m_RenderPlugin = &static_cast(child); + } + void ClearChildren() override + { + SImage &theItem = static_cast(GetGraphObject()); + theItem.m_RenderPlugin = nullptr; + } + + void SetActive(bool /*inActive*/) override {} +}; + +struct STextTranslator : public SNodeTranslator +{ + STextTranslator(UICDM::CUICDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SNodeTranslator(inInstance, *QT3DS_NEW(inAlloc, SText)()) + { + } + + void PushTranslation(STranslation &inContext) override + { + SNodeTranslator::PushTranslation(inContext); + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + SText &theItem = static_cast(GetGraphObject()); + ITERATE_UIC_RENDER_TEXT_PROPERTIES + theItem.m_Flags.SetTextDirty(true); + } +}; + +inline qt3ds::QT3DSVec2 ToRenderType(const UICDM::SFloat2 &inType) +{ + return qt3ds::QT3DSVec2(inType.m_Floats[0], inType.m_Floats[1]); +} +inline qt3ds::QT3DSVec3 ToRenderType(const UICDM::SFloat3 &inType) +{ + return qt3ds::QT3DSVec3(inType.m_Floats[0], inType.m_Floats[1], inType.m_Floats[2]); +} + +struct SDynamicObjectTranslator : public SGraphObjectTranslator +{ + typedef eastl::vector> TIdxToPropertyMap; + eastl::basic_string m_ConvertStr; + TIdxToPropertyMap m_PropertyMap; + + SDynamicObjectTranslator(UICDM::CUICDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &, + SDynamicObject &inObject) + : SGraphObjectTranslator(inInstance, inObject) + { + } + + void PushTranslation(STranslation &inContext) override + { + SDynamicObject &theItem = static_cast(GetGraphObject()); + IDynamicObjectSystem &theSystem = inContext.m_UICContext.GetDynamicObjectSystem(); + using namespace uic::render::dynamic; + using qt3ds::foundation::NVConstDataRef; + NVConstDataRef theProperties = + theSystem.GetProperties(theItem.m_ClassName); + if (m_PropertyMap.size() == 0) { + for (QT3DSU32 idx = 0, end = theProperties.size(); idx < end; ++idx) { + const SPropertyDefinition &theDefinition(theProperties[idx]); + qt3ds::foundation::ConvertUTF(theDefinition.m_Name.c_str(), 0, m_ConvertStr); + const wchar_t *thePropName = + reinterpret_cast(m_ConvertStr.c_str()); + UICDM::CUICDMPropertyHandle theProperty = + inContext.m_Reader.FindProperty(GetInstanceHandle(), thePropName); + if (theProperty.Valid()) + m_PropertyMap.push_back(eastl::make_pair(idx, theProperty.GetHandleValue())); + } + } + for (TIdxToPropertyMap::iterator theIter = m_PropertyMap.begin(), end = m_PropertyMap.end(); + theIter != end; ++theIter) { + const SPropertyDefinition &theDefinition(theProperties[theIter->first]); + UICDM::CUICDMPropertyHandle theProperty = theIter->second; + Option theValueOpt = + inContext.m_Reader.GetInstancePropertyValue(GetInstanceHandle(), theProperty); + if (theValueOpt.hasValue()) { + UICDM::SValue &theValue(*theValueOpt); + switch (UICDM::GetValueType(theValue)) { + case UICDM::DataModelDataType::Long: + if (theDefinition.m_DataType == qt3ds::render::NVRenderShaderDataTypes::QT3DSI32) + theItem.SetPropertyValue(theDefinition, UICDM::get(theValue)); + else { + QT3DS_ASSERT(false); + } + break; + case UICDM::DataModelDataType::Bool: + if (theDefinition.m_DataType + == qt3ds::render::NVRenderShaderDataTypes::QT3DSRenderBool) + theItem.SetPropertyValue(theDefinition, UICDM::get(theValue)); + else { + QT3DS_ASSERT(false); + } + break; + case UICDM::DataModelDataType::Float: + if (theDefinition.m_DataType == qt3ds::render::NVRenderShaderDataTypes::QT3DSF32) + theItem.SetPropertyValue(theDefinition, UICDM::get(theValue)); + else { + QT3DS_ASSERT(false); + } + break; + case UICDM::DataModelDataType::Float2: + if (theDefinition.m_DataType == qt3ds::render::NVRenderShaderDataTypes::QT3DSVec2) + theItem.SetPropertyValue( + theDefinition, ToRenderType(UICDM::get(theValue))); + else { + QT3DS_ASSERT(false); + } + break; + case UICDM::DataModelDataType::Float3: + if (theDefinition.m_DataType == qt3ds::render::NVRenderShaderDataTypes::QT3DSVec3) + theItem.SetPropertyValue( + theDefinition, ToRenderType(UICDM::get(theValue))); + else { + QT3DS_ASSERT(false); + } + break; + // Could be either an enum or a texture. + case UICDM::DataModelDataType::String: { + UICDM::TDataStrPtr theData = UICDM::get(theValue); + if (theData) { + eastl::string theStr; + qt3ds::render::ConvertWideUTF(theData->GetData(), 0, theStr); + eastl::string theWorkspace; + theItem.SetPropertyValue( + theDefinition, theStr.c_str(), + inContext.m_Doc.GetDocumentDirectory().GetCharStar(), theWorkspace, + inContext.m_UICContext.GetStringTable()); + } + } break; + default: + QT3DS_ASSERT(false); + } + } + } + } + + void AppendChild(SGraphObject &) override {} + void ClearChildren() override {} +}; + +struct SEffectTranslator : public SDynamicObjectTranslator +{ + // TODO - move this map to inContext and have it looked up by name. + IEffectSystem *m_EffectSystem; + + SEffectTranslator(UICDM::CUICDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc, + SEffect &inEffect) + : SDynamicObjectTranslator(inInstance, inAlloc, inEffect) + , m_EffectSystem(nullptr) + { + } + void PushTranslation(STranslation &inContext) override + { + m_EffectSystem = &inContext.m_UICContext.GetEffectSystem(); + SDynamicObjectTranslator::PushTranslation(inContext); + } + + void SetActive(bool inActive) override + { + SEffect &theItem = static_cast(GetGraphObject()); + if (m_EffectSystem) + theItem.SetActive(inActive, *m_EffectSystem); + else + theItem.m_Flags.SetActive(inActive); + } +}; +struct SCustomMaterialTranslator : public SDynamicObjectTranslator +{ + ICustomMaterialSystem *m_MaterialSystem; + + SCustomMaterialTranslator(UICDM::CUICDMInstanceHandle inInstance, + qt3ds::NVAllocatorCallback &inAlloc, SCustomMaterial &inMaterial) + : SDynamicObjectTranslator(inInstance, inAlloc, inMaterial) + , m_MaterialSystem(nullptr) + { + } + + void PushTranslation(STranslation &inContext) override + { + SDynamicObjectTranslator::PushTranslation(inContext); + SCustomMaterial &theItem = static_cast(GetGraphObject()); + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + ITERATE_UIC_RENDER_CUSTOM_MATERIAL_PROPERTIES + + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapIndirect, + theItem.m_Lightmaps.m_LightmapIndirect); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapRadiosity, + theItem.m_Lightmaps.m_LightmapRadiosity); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapShadow, + theItem.m_Lightmaps.m_LightmapShadow); + } + + void SetActive(bool inActive) override + { + if (m_MaterialSystem) { + SCustomMaterial &theItem = static_cast(GetGraphObject()); + if (inActive != theItem.m_Flags.IsActive()) { + theItem.m_Flags.SetActive(inActive); + m_MaterialSystem->OnMaterialActivationChange(theItem, inActive); + } + } + } +}; +struct SReferencedMaterialTranslator : public SGraphObjectTranslator +{ + SReferencedMaterialTranslator(UICDM::CUICDMInstanceHandle inInstance, + qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SReferencedMaterial)()) + { + } + void PushTranslation(STranslation &inContext) override + { + SGraphObjectTranslator::PushTranslation(inContext); + SReferencedMaterial &theItem = static_cast(GetGraphObject()); + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + ITERATE_UIC_RENDER_REFERENCED_MATERIAL_PROPERTIES + + theItem.m_Dirty.SetDirty(); + if (theItem.m_ReferencedMaterial == &theItem) { + qCCritical(qt3ds::INVALID_OPERATION, + "Referenced material is referencing itself."); + } else if (theItem.m_ReferencedMaterial + && theItem.m_ReferencedMaterial->m_Type == GraphObjectTypes::DefaultMaterial) { + SDefaultMaterial *theDefaultItem = + static_cast(theItem.m_ReferencedMaterial); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapIndirect, + theDefaultItem->m_Lightmaps.m_LightmapIndirect); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapRadiosity, + theDefaultItem->m_Lightmaps.m_LightmapRadiosity); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapShadow, + theDefaultItem->m_Lightmaps.m_LightmapShadow); + } else if (theItem.m_ReferencedMaterial + && theItem.m_ReferencedMaterial->m_Type == GraphObjectTypes::CustomMaterial) { + SCustomMaterial *theDefaultItem = + static_cast(theItem.m_ReferencedMaterial); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapIndirect, + theDefaultItem->m_Lightmaps.m_LightmapIndirect); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapRadiosity, + theDefaultItem->m_Lightmaps.m_LightmapRadiosity); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapShadow, + theDefaultItem->m_Lightmaps.m_LightmapShadow); + } + } + + void AppendChild(SGraphObject &) override {} + + void ClearChildren() override {} + + void SetActive(bool /*inActive*/) override {} +}; +using uic::render::SRenderPlugin; +using uic::render::SRenderPropertyValueUpdate; +using uic::render::IRenderPluginClass; +using uic::render::SRenderPluginPropertyDeclaration; +struct SRenderPluginPropertyUpdateFactory +{ + static void Add(eastl::vector &ioUpdates, float value, + const SRenderPluginPropertyDeclaration &theDec, IRenderPluginClass &) + { + ioUpdates.push_back(SRenderPropertyValueUpdate(theDec.m_Name, value)); + } + static void Add(eastl::vector &ioUpdates, qt3ds::QT3DSI32 value, + const SRenderPluginPropertyDeclaration &theDec, IRenderPluginClass &) + { + ioUpdates.push_back(SRenderPropertyValueUpdate(theDec.m_Name, value)); + } + static void Add(eastl::vector &ioUpdates, bool value, + const SRenderPluginPropertyDeclaration &theDec, IRenderPluginClass &) + { + ioUpdates.push_back(SRenderPropertyValueUpdate(theDec.m_Name, value)); + } + static void Add(eastl::vector &ioUpdates, UICDM::TDataStrPtr value, + const SRenderPluginPropertyDeclaration &theDec, IRenderPluginClass &, + qt3ds::foundation::IStringTable &strTable) + { + if (value) { + ioUpdates.push_back( + SRenderPropertyValueUpdate(theDec.m_Name, strTable.RegisterStr(value->GetData()))); + } + } + static void Add(eastl::vector &ioUpdates, UICDM::SStringRef value, + const SRenderPluginPropertyDeclaration &theDec, IRenderPluginClass &, + qt3ds::foundation::IStringTable &strTable) + { + ioUpdates.push_back( + SRenderPropertyValueUpdate(theDec.m_Name, strTable.RegisterStr(value.m_Id))); + } + static void Add(eastl::vector &ioUpdates, + const UICDM::SFloat2 &value, const SRenderPluginPropertyDeclaration &theDec, + IRenderPluginClass &inClass) + { + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset).first, value.m_Floats[0])); + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset + 1).first, value.m_Floats[1])); + } + + static void Add(eastl::vector &ioUpdates, + const UICDM::SFloat3 &value, const SRenderPluginPropertyDeclaration &theDec, + IRenderPluginClass &inClass) + { + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset).first, value.m_Floats[0])); + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset + 1).first, value.m_Floats[1])); + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset + 2).first, value.m_Floats[2])); + } +}; +struct SRenderPluginTranslator : public SGraphObjectTranslator +{ + eastl::vector m_PropertyUpdates; + + SRenderPluginTranslator(UICDM::CUICDMInstanceHandle inInstance, + qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SRenderPlugin)()) + { + } + + void PushTranslation(STranslation &inContext) override + { + SRenderPlugin &theItem = static_cast(GetGraphObject()); + // First, get the instance via resolving the source path. + CUICDMPropertyHandle sourcepath = + inContext.m_Reader.FindProperty(GetInstanceHandle(), L"sourcepath"); + Option theSourcePath = + inContext.m_Reader.GetInstancePropertyValue(GetInstanceHandle(), sourcepath); + UICDM::TDataStrPtr theData = theSourcePath->getData(); + if (!theData) + return; + + Q3DStudio::CFilePath theFullPath = inContext.m_Doc.GetResolvedPathToDoc(theData->GetData()); + qt3ds::foundation::IStringTable &theStrTable = inContext.m_UICContext.GetStringTable(); + theItem.m_PluginPath = theStrTable.RegisterStr(theFullPath); + uic::render::IRenderPluginInstance *theInstance = + inContext.m_UICContext.GetRenderPluginManager().GetOrCreateRenderPluginInstance( + theItem.m_PluginPath, &theItem); + + // Couldn't load the instance, so we can't render the instance. + if (theInstance == nullptr) + return; + // Grab the instance's parent and get the properties that are specific to just that + // instance. + TInstanceHandleList derivationParents; + std::shared_ptr theDataCore = + inContext.m_StudioSystem.GetFullSystem()->GetCoreSystem()->GetDataCore(); + theDataCore->GetInstanceParents(GetInstanceHandle(), derivationParents); + if (derivationParents.size() == 0) + return; + TPropertyHandleList theSpecificProperties; + theDataCore->GetInstanceProperties(derivationParents[0], theSpecificProperties); + eastl::string propStem; + eastl::string propname; + m_PropertyUpdates.clear(); + uic::render::IRenderPluginClass &theClass = theInstance->GetPluginClass(); + using uic::render::SRenderPluginPropertyDeclaration; + if (theClass.GetRegisteredProperties().size() == 0) { + for (size_t idx = 0, end = theSpecificProperties.size(); idx < end; ++idx) { + SUICDMPropertyDefinition theProperty = + theDataCore->GetProperty(theSpecificProperties[idx]); + UICDM::AdditionalMetaDataType::Value theMetaType = + inContext.m_StudioSystem.GetActionMetaData()->GetAdditionalMetaDataType( + GetInstanceHandle(), theSpecificProperties[idx]); + CRegisteredString thePropName(theStrTable.RegisterStr(theProperty.m_Name.c_str())); + switch (theProperty.m_Type) { + case DataModelDataType::Float: + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, uic::render::SRenderPluginPropertyTypes::Float)); + break; + case DataModelDataType::Float2: + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, uic::render::SRenderPluginPropertyTypes::Vector2)); + break; + case DataModelDataType::Float3: + if (theMetaType != AdditionalMetaDataType::Color) { + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, uic::render::SRenderPluginPropertyTypes::Vector3)); + } else { + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, uic::render::SRenderPluginPropertyTypes::Color)); + } + break; + case DataModelDataType::Long: + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, uic::render::SRenderPluginPropertyTypes::Long)); + break; + case DataModelDataType::String: + case DataModelDataType::StringRef: + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, uic::render::SRenderPluginPropertyTypes::String)); + break; + case DataModelDataType::Bool: + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, uic::render::SRenderPluginPropertyTypes::Boolean)); + break; + default: + // Unsupported plugin property. + QT3DS_ASSERT(false); + break; + } + } + } + for (size_t idx = 0, end = theSpecificProperties.size(); idx < end; ++idx) { + Option thePropValueOpt = inContext.m_Reader.GetInstancePropertyValue( + GetInstanceHandle(), theSpecificProperties[idx]); + if (thePropValueOpt.hasValue()) { + SValue &thePropValue = thePropValueOpt.getValue(); + SUICDMPropertyDefinition theProperty = + theDataCore->GetProperty(theSpecificProperties[idx]); + SRenderPluginPropertyDeclaration theDeclaration(theClass.GetPropertyDeclaration( + theStrTable.RegisterStr(theProperty.m_Name.c_str()))); + + switch (thePropValue.getType()) { + case DataModelDataType::None: + QT3DS_ASSERT(false); + break; + case DataModelDataType::Float: + SRenderPluginPropertyUpdateFactory::Add( + m_PropertyUpdates, thePropValue.getData(), theDeclaration, theClass); + break; + case DataModelDataType::Float2: + SRenderPluginPropertyUpdateFactory::Add(m_PropertyUpdates, + thePropValue.getData(), + theDeclaration, theClass); + break; + case DataModelDataType::Float3: + SRenderPluginPropertyUpdateFactory::Add(m_PropertyUpdates, + thePropValue.getData(), + theDeclaration, theClass); + break; + case DataModelDataType::Long: + SRenderPluginPropertyUpdateFactory::Add( + m_PropertyUpdates, thePropValue.getData(), theDeclaration, theClass); + break; + case DataModelDataType::String: + SRenderPluginPropertyUpdateFactory::Add(m_PropertyUpdates, + thePropValue.getData(), + theDeclaration, theClass, theStrTable); + break; + case DataModelDataType::Bool: + SRenderPluginPropertyUpdateFactory::Add( + m_PropertyUpdates, thePropValue.getData(), theDeclaration, theClass); + break; + case DataModelDataType::StringRef: + SRenderPluginPropertyUpdateFactory::Add(m_PropertyUpdates, + thePropValue.getData(), + theDeclaration, theClass, theStrTable); + break; + default: + QT3DS_ASSERT(false); + break; + } + } + } + theInstance->Update(NVConstDataRef(m_PropertyUpdates.data(), + m_PropertyUpdates.size())); + } + void AppendChild(SGraphObject &) override {} + void ClearChildren() override {} + void SetActive(bool inActive) override + { + SRenderPlugin &theItem = static_cast(GetGraphObject()); + theItem.m_Flags.SetActive(inActive); + } +}; + +struct SAliasTranslator : public SGraphObjectTranslator +{ + SGraphObjectTranslator *m_ReferenceTree; + CUICDMInstanceHandle m_ReferencedInstance; + SAliasTranslator(UICDM::CUICDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SNode)()) + , m_ReferenceTree(nullptr) + { + } + void RecurseAndCreateTranslators(STranslation &inContext, + UICDM::CUICDMInstanceHandle inInstance) + { + for (QT3DSI32 idx = 0, end = inContext.m_AssetGraph.GetChildCount(inInstance); idx < end; + ++idx) { + UICDM::CUICDMInstanceHandle theChild = inContext.m_AssetGraph.GetChild(inInstance, idx); + inContext.GetOrCreateTranslator(theChild, m_InstanceHandle); + RecurseAndCreateTranslators(inContext, theChild); + } + } + void PushTranslation(STranslation &inContext) override + { + STranslatorUICDMParser theParser(inContext, GetInstanceHandle()); + Option theData = theParser.GetPropertyValue( + inContext.m_ObjectDefinitions.m_Alias.m_ReferencedNode); + m_ReferencedInstance = CUICDMInstanceHandle(); + m_ReferenceTree = nullptr; + ((SNode *)m_GraphObject)->m_Flags.SetDirty(true); + if (theData.hasValue()) { + m_ReferencedInstance = + inContext.m_Reader.GetInstanceForObjectRef(GetInstanceHandle(), *theData); + if (inContext.m_Reader.IsInstance(m_ReferencedInstance)) { + m_ReferenceTree = + inContext.GetOrCreateTranslator(m_ReferencedInstance, m_InstanceHandle); + if (m_ReferenceTree + && !GraphObjectTypes::IsNodeType(m_ReferenceTree->GetGraphObject().m_Type)) { + QT3DS_ASSERT(false); + m_ReferenceTree = nullptr; + m_ReferencedInstance = CUICDMInstanceHandle(); + } else { + RecurseAndCreateTranslators(inContext, m_ReferencedInstance); + } + } + } + } + + void AfterRenderGraphIsBuilt(STranslation &inContext) override + { + SNode &theItem = static_cast(GetGraphObject()); + STranslatorUICDMParser theParser(inContext, m_InstanceHandle); + ITERATE_UIC_RENDER_NODE_PROPERTIES + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Node.m_BoneId, + theItem.m_SkeletonId); + bool ignoresParent = false; + if (theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Node.m_IgnoresParent, + ignoresParent)) + theItem.m_Flags.SetIgnoreParentTransform(ignoresParent); + theItem.m_Flags.SetDirty(true); + } + void AppendChild(SGraphObject &inObject) override + { + if (m_ReferenceTree) + m_ReferenceTree->AppendChild(inObject); + } + void ClearChildren() override + { + if (m_ReferenceTree) + m_ReferenceTree->ClearChildren(); + } + void SetActive(bool inActive) override + { + SNode &theItem = static_cast(GetGraphObject()); + theItem.m_Flags.SetActive(inActive); + } + SGraphObject &GetGraphObject() override + { + if (m_ReferenceTree) + return *m_ReferenceTree->m_GraphObject; + return *m_GraphObject; + } + UICDM::CUICDMInstanceHandle GetSceneGraphInstanceHandle() override + { + if (m_ReferencedInstance.Valid()) + return m_ReferencedInstance; + return m_InstanceHandle; + } + CUICDMInstanceHandle GetInstanceHandle() override { return m_InstanceHandle; } + + SGraphObject &GetNonAliasedGraphObject() override { return *m_GraphObject; } +}; +} + +void SGraphObjectTranslator::PushTranslation(STranslation &inTranslatorContext) +{ + Q3DStudio::CString theId = inTranslatorContext.m_Reader.GetFileId(GetInstanceHandle()); + if (theId.size()) + GetGraphObject().m_Id = + inTranslatorContext.m_UICContext.GetStringTable().RegisterStr(theId.c_str()); +} + +bool STranslation::IncludeNode(const SNode &inNode) +{ + SGraphObjectTranslator *theTranslator = inNode.m_UserData.DynamicCast(); + if (theTranslator + && m_Doc.GetDocumentReader().IsCurrentlyActive(theTranslator->GetInstanceHandle())) + return true; + return false; +} + +void STranslation::ReleaseEffect(UICDM::CUICDMInstanceHandle inInstance) +{ + if (m_Reader.IsInstance(inInstance) == false) + return; + + UICDM::ComposerObjectTypes::Enum theType = m_ObjectDefinitions.GetType(inInstance); + UICDM::CUICDMInstanceHandle theParentClass = m_Reader.GetFirstBaseClass(inInstance); + + if (theType == NULL && theParentClass.Valid()) + theType = m_ObjectDefinitions.GetType(theParentClass); + + if (theType == UICDM::ComposerObjectTypes::Effect) { + IEffectSystem &theSystem = m_UICContext.GetEffectSystem(); + if (theParentClass.Valid()) { + Q3DStudio::CString theInstanceName = m_Reader.GetName(theParentClass); + CRegisteredString theNameStr = + m_UICContext.GetStringTable().RegisterStr(theInstanceName); + + if (theSystem.IsEffectRegistered(theNameStr)) { + TInstanceToTranslatorMap::iterator theTranslatorList = + m_TranslatorMap.find(inInstance); + if (theTranslatorList != m_TranslatorMap.end()) + m_TranslatorMap.erase(theTranslatorList); + theSystem.SetEffectRequiresCompilation(theNameStr, true); + } + } + } +} + +SGraphObjectTranslator *STranslation::CreateTranslator(UICDM::CUICDMInstanceHandle inInstance) +{ + SGraphObjectTranslator *theNewTranslator = nullptr; + UICDM::ComposerObjectTypes::Enum theType = m_ObjectDefinitions.GetType(inInstance); + UICDM::CUICDMInstanceHandle theParentClass = m_Reader.GetFirstBaseClass(inInstance); + if (theType == NULL && theParentClass.Valid()) + theType = m_ObjectDefinitions.GetType(theParentClass); + + // For the subset of possible instances, pick out the valid translators. + switch (theType) { + case UICDM::ComposerObjectTypes::Group: + case UICDM::ComposerObjectTypes::Component: + case UICDM::ComposerObjectTypes::Node: + theNewTranslator = QT3DS_NEW(m_Allocator, SNodeTranslator)(inInstance, m_Allocator); + break; + case UICDM::ComposerObjectTypes::Scene: + theNewTranslator = QT3DS_NEW(m_Allocator, SSceneTranslator)(inInstance, m_Allocator); + m_Scene = static_cast(&theNewTranslator->GetGraphObject()); + m_Scene->m_Presentation = &m_Presentation; + break; + case UICDM::ComposerObjectTypes::Layer: + theNewTranslator = QT3DS_NEW(m_Allocator, SLayerTranslator)(inInstance, m_Allocator); + break; + case UICDM::ComposerObjectTypes::Light: + theNewTranslator = QT3DS_NEW(m_Allocator, SLightTranslator)(inInstance, m_Allocator); + break; + case UICDM::ComposerObjectTypes::Camera: + theNewTranslator = QT3DS_NEW(m_Allocator, SCameraTranslator)(inInstance, m_Allocator); + break; + case UICDM::ComposerObjectTypes::Model: + theNewTranslator = QT3DS_NEW(m_Allocator, SModelTranslator)(inInstance, m_Allocator); + break; + case UICDM::ComposerObjectTypes::Image: + theNewTranslator = QT3DS_NEW(m_Allocator, SImageTranslator)(inInstance, m_Allocator); + break; + case UICDM::ComposerObjectTypes::Text: + theNewTranslator = QT3DS_NEW(m_Allocator, STextTranslator)(inInstance, m_Allocator); + break; + case UICDM::ComposerObjectTypes::Material: + theNewTranslator = QT3DS_NEW(m_Allocator, SDefaultMaterialTranslator)(inInstance, m_Allocator); + break; + case UICDM::ComposerObjectTypes::ReferencedMaterial: + theNewTranslator = + QT3DS_NEW(m_Allocator, SReferencedMaterialTranslator)(inInstance, m_Allocator); + break; + case UICDM::ComposerObjectTypes::Alias: + theNewTranslator = QT3DS_NEW(m_Allocator, SAliasTranslator)(inInstance, m_Allocator); + break; + case UICDM::ComposerObjectTypes::Path: + theNewTranslator = QT3DS_NEW(m_Allocator, SPathTranslator)(inInstance, m_Allocator); + break; + case UICDM::ComposerObjectTypes::SubPath: + theNewTranslator = QT3DS_NEW(m_Allocator, SPathSubPathTranslator)(inInstance, m_Allocator); + break; + case UICDM::ComposerObjectTypes::Effect: { + IEffectSystem &theSystem = m_UICContext.GetEffectSystem(); + if (theParentClass.Valid()) { + Q3DStudio::CString theInstanceName = m_Reader.GetName(theParentClass); + CRegisteredString theNameStr = + m_UICContext.GetStringTable().RegisterStr(theInstanceName); + + if (theSystem.IsEffectRegistered(theNameStr) + && theSystem.DoesEffectRequireCompilation(theNameStr)) { + theSystem.UnregisterEffect(theNameStr); + } + + if (!theSystem.IsEffectRegistered(theNameStr)) { + // We assume the effect has already been registered and such. + UICDM::IMetaData &theMetaData(*m_StudioSystem.GetActionMetaData()); + Q3DStudio::CString theInstancePath = m_Reader.GetSourcePath(theParentClass); + Option theMetaEffect = + theMetaData.GetEffectBySourcePath( + m_UICContext.GetStringTable().GetNarrowStr(theInstancePath)); + if (theMetaEffect.hasValue()) { + uic::render::IUIPLoader::CreateEffectClassFromMetaEffect( + theNameStr, m_UICContext.GetFoundation(), theSystem, theMetaEffect, + m_UICContext.GetStringTable()); + theSystem.SetEffectRequiresCompilation(theNameStr, true); + } + } + + if (theSystem.IsEffectRegistered(theNameStr)) { + theNewTranslator = QT3DS_NEW(m_Allocator, SEffectTranslator)( + inInstance, m_Allocator, + *theSystem.CreateEffectInstance(theNameStr, m_Allocator)); + } + } + } break; + case UICDM::ComposerObjectTypes::CustomMaterial: { + ICustomMaterialSystem &theSystem = m_UICContext.GetCustomMaterialSystem(); + if (theParentClass.Valid()) { + Q3DStudio::CString theInstanceName = m_Reader.GetName(theParentClass); + CRegisteredString theNameStr = + m_UICContext.GetStringTable().RegisterStr(theInstanceName); + if (!theSystem.IsMaterialRegistered(theNameStr)) { + // We assume the effect has already been registered and such. + UICDM::IMetaData &theMetaData(*m_StudioSystem.GetActionMetaData()); + Q3DStudio::CString theInstancePath = m_Reader.GetSourcePath(theParentClass); + Option theMaterialData = + theMetaData.GetMaterialBySourcePath( + m_UICContext.GetStringTable().GetNarrowStr(theInstancePath)); + if (theMaterialData.hasValue()) { + uic::render::IUIPLoader::CreateMaterialClassFromMetaMaterial( + theNameStr, m_UICContext.GetFoundation(), theSystem, theMaterialData, + m_UICContext.GetStringTable()); + } + } + if (theSystem.IsMaterialRegistered(theNameStr)) { + theNewTranslator = QT3DS_NEW(m_Allocator, SCustomMaterialTranslator)( + inInstance, m_Allocator, + *theSystem.CreateCustomMaterial(theNameStr, m_Allocator)); + static_cast(theNewTranslator)->m_MaterialSystem = + &theSystem; + } + } + } break; + case UICDM::ComposerObjectTypes::RenderPlugin: { + theNewTranslator = QT3DS_NEW(m_Allocator, SRenderPluginTranslator)(inInstance, m_Allocator); + } break; + } + return theNewTranslator; +} + +bool CompareTranslator(const STranslation::THandleTranslatorPair &first, + const STranslation::THandleTranslatorPair &second) +{ + return first.first == second.first; +} + +struct STranslatorPredicate +{ + CUICDMInstanceHandle m_Instance; + STranslatorPredicate(CUICDMInstanceHandle &ins) + : m_Instance(ins) + { + } + bool operator()(const STranslation::THandleTranslatorPair &first) const + { + return first.first == m_Instance; + } +}; + +Option +FindTranslator(STranslation::THandleTranslatorPairList &inList, + CUICDMInstanceHandle inInstance = CUICDMInstanceHandle()) +{ + STranslation::THandleTranslatorPairList::iterator iter = + eastl::find_if(inList.begin(), inList.end(), STranslatorPredicate(inInstance)); + if (iter != inList.end()) + return *iter; + return Empty(); +} + +SGraphObjectTranslator *STranslation::GetOrCreateTranslator(UICDM::CUICDMInstanceHandle inInstance) +{ + return GetOrCreateTranslator(inInstance, CUICDMInstanceHandle()); +} + +SGraphObjectTranslator * +STranslation::GetOrCreateTranslator(UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMInstanceHandle inAliasInstance) +{ + TInstanceToTranslatorMap::iterator theTranslatorList = + m_TranslatorMap.insert(eastl::make_pair(inInstance, THandleTranslatorPairList())).first; + THandleTranslatorPairList &theList = theTranslatorList->second; + Option theExistingTranslator = + FindTranslator(theList, inAliasInstance); + + if (theExistingTranslator.hasValue()) { + return theExistingTranslator->second; + } + if (m_Reader.IsInstance(inInstance) == false) + return nullptr; + + SGraphObjectTranslator *theNewTranslator = CreateTranslator(inInstance); + if (theNewTranslator != nullptr) { + theNewTranslator->m_AliasInstanceHandle = inAliasInstance; + m_DirtySet.insert(*theNewTranslator); + theList.push_back(THandleTranslatorPair(inAliasInstance, theNewTranslator)); + } + + return theNewTranslator; +} + +STranslation::THandleTranslatorPairList & +STranslation::GetTranslatorsForInstance(UICDM::CUICDMInstanceHandle inInstance) +{ + return m_TranslatorMap.insert(eastl::make_pair(inInstance, THandleTranslatorPairList())) + .first->second; +} + +UICDM::CUICDMInstanceHandle STranslation::GetAnchorPoint(QT3DSU32 inAnchorIndex) +{ + SGraphObjectTranslator *thePathTranslator = + static_cast(m_PathWidget->GetNode().m_UserData.m_UserData); + if (thePathTranslator == nullptr) + return UICDM::CUICDMInstanceHandle(); + UICDM::CUICDMInstanceHandle thePathHandle = thePathTranslator->GetInstanceHandle(); + QT3DSU32 theAnchorIndex = 0; + for (QT3DSI32 idx = 0, end = m_AssetGraph.GetChildCount(thePathHandle); idx < end; ++idx) { + UICDM::CUICDMInstanceHandle theChildInstance = m_AssetGraph.GetChild(thePathHandle, idx); + if (m_Doc.GetDocumentReader().GetObjectTypeName(theChildInstance) == L"SubPath") { + QT3DSI32 numAnchors = m_AssetGraph.GetChildCount(theChildInstance); + QT3DSU32 endIndex = theAnchorIndex + (QT3DSU32)numAnchors; + if (endIndex > inAnchorIndex) { + return m_AssetGraph.GetChild(theChildInstance, inAnchorIndex - theAnchorIndex); + } else + theAnchorIndex = endIndex; + } + } + return UICDM::CUICDMInstanceHandle(); +} + +UICDM::CUICDMInstanceHandle STranslation::GetAnchorPoint(SPathPick &inPick) +{ + return GetAnchorPoint(inPick.m_AnchorIndex); +} + +namespace uic { +namespace studio { + struct SEditCameraLayerTranslator : public SLayerTranslator + { + SEditCameraLayerTranslator(UICDM::CUICDMInstanceHandle inInstance, + qt3ds::NVAllocatorCallback &inAlloc) + : SLayerTranslator(inInstance, inAlloc) + { + } + void PushTranslation(STranslation &) override + { + SLayer &theItem = static_cast(GetGraphObject()); + theItem.m_Flags.SetActive(true); + } + void AppendChild(SGraphObject &inChild) override + { + if (GraphObjectTypes::IsNodeType(inChild.m_Type)) { + SNodeTranslator::AppendChild(inChild); + } + } + }; +} +} + +STranslation::STranslation(IStudioRenderer &inRenderer, IUICRenderContext &inContext) + : m_Renderer(inRenderer) + , m_UICContext(inContext) + , m_Doc(*g_StudioApp.GetCore()->GetDoc()) + , m_Reader(m_Doc.GetDocumentReader()) + , m_ObjectDefinitions( + m_Doc.GetStudioSystem()->GetClientDataModelBridge()->GetObjectDefinitions()) + , m_StudioSystem(*m_Doc.GetStudioSystem()) + , m_FullSystem(*m_Doc.GetStudioSystem()->GetFullSystem()) + , m_AssetGraph(*m_Doc.GetAssetGraph()) + , m_Allocator(inContext.GetRenderContext().GetFoundation()) + , m_TranslatorMap(inContext.GetAllocator(), "STranslation::m_TranslatorMap") + , m_DirtySet(inContext.GetAllocator(), "STranslation::m_DirtySet") + , m_Scene(nullptr) + , m_SignalConnections(inContext.GetAllocator(), "STranslation::m_SignalConnections") + , m_ComponentSecondsDepth(0) + , m_KeyRepeat(0) + , m_EditCameraEnabled(false) + , m_EditLightEnabled(false) + , m_Viewport(0, 0) + , m_EditCameraLayerTranslator(nullptr) + , m_PixelBuffer(inContext.GetAllocator(), "STranslation::m_PixelBuffer") + , m_GuideAllocator(inContext.GetAllocator(), "STranslation::m_GuideAllocator") +{ + m_EditCamera.m_Flags.SetActive(true); + m_EditLight.m_Flags.SetActive(true); + UICDM::CUICDMInstanceHandle theScene = m_AssetGraph.GetRoot(0); + m_GraphIterator.ClearResults(); + m_AssetGraph.GetDepthFirst(m_GraphIterator, theScene); + for (; !m_GraphIterator.IsDone(); ++m_GraphIterator) { + UICDM::CUICDMInstanceHandle theInstance(m_GraphIterator.GetCurrent()); + GetOrCreateTranslator(theInstance); + } + UICDM::IStudioFullSystemSignalProvider *theProvider = m_FullSystem.GetSignalProvider(); + m_SignalConnections.push_back( + theProvider->ConnectInstanceCreated(boost::bind(&STranslation::MarkDirty, this, _1))); + m_SignalConnections.push_back(theProvider->ConnectInstanceDeleted( + boost::bind(&STranslation::ReleaseTranslation, this, _1))); + m_SignalConnections.push_back( + theProvider->ConnectInstancePropertyValue(boost::bind(&STranslation::MarkDirty, this, _1))); + m_SignalConnections.push_back(m_AssetGraph.ConnectChildAdded( + boost::bind(&STranslation::MarkGraphInstanceDirty, this, _1, _2))); + m_SignalConnections.push_back(m_AssetGraph.ConnectChildMoved( + boost::bind(&STranslation::MarkGraphInstanceDirty, this, _1, _2))); + m_SignalConnections.push_back(m_AssetGraph.ConnectChildRemoved( + boost::bind(&STranslation::MarkGraphInstanceDirty, this, _1, _2))); + m_SignalConnections.push_back(theProvider->ConnectBeginComponentSeconds( + boost::bind(&STranslation::MarkBeginComponentSeconds, this, _1))); + m_SignalConnections.push_back(theProvider->ConnectComponentSeconds( + boost::bind(&STranslation::MarkComponentSeconds, this, _1))); + + ::CColor color = CStudioPreferences::GetRulerBackgroundColor(); // Rectangles under tick marks + m_rectColor = QT3DSVec4(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f, + 1.f); + color = CStudioPreferences::GetRulerTickColor(); // Tick marks + m_lineColor = QT3DSVec4(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f, + 1.f); + color = CStudioPreferences::GetGuideColor(); + m_guideColor = QT3DSVec4(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f, + 1.f); + color = CStudioPreferences::GetGuideSelectedColor(); + m_selectedGuideColor = QT3DSVec4(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f, + 1.f); + color = CStudioPreferences::GetGuideFillColor(); // Not sure what this is used for + m_guideFillColor = QT3DSVec4(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f, + 1.f); + color = CStudioPreferences::GetGuideFillSelectedColor(); // Not sure what this is used for + m_selectedGuideFillColor = QT3DSVec4(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f, + 1.f); +} + +void STranslation::BuildRenderGraph(SGraphObjectTranslator &inParent, + CUICDMInstanceHandle inAliasHandle) +{ + SGraphObjectTranslator &theParentTranslator(inParent); + theParentTranslator.ClearChildren(); + if (m_EditCameraEnabled + && theParentTranslator.GetGraphObject().m_Type == GraphObjectTypes::Layer) { + theParentTranslator.AppendChild(m_EditCamera); + if (m_EditLightEnabled) { + m_EditLight.m_Parent = &m_EditCamera; + m_EditCamera.m_FirstChild = &m_EditLight; + } else { + m_EditCamera.m_FirstChild = nullptr; + m_EditLight.m_Parent = nullptr; + } + } + // Alias handles propagate down the scene graph. + if (inParent.GetInstanceHandle() != inParent.GetSceneGraphInstanceHandle()) + inAliasHandle = inParent.GetInstanceHandle(); + for (long idx = 0, end = m_AssetGraph.GetChildCount(inParent.GetSceneGraphInstanceHandle()); + idx < end; ++idx) { + UICDM::CUICDMInstanceHandle theChild( + m_AssetGraph.GetChild(inParent.GetSceneGraphInstanceHandle(), idx)); + SGraphObjectTranslator *theTranslator = GetOrCreateTranslator(theChild, inAliasHandle); + if (theTranslator == nullptr) + continue; + + // We we have edit cameras active, we only render the active layer and we remove any cameras + // in the active layer. Furthermore if our edit light is active, then we also remove any + // active lights in the layer. + if (m_EditCameraEnabled) { + if (theTranslator->GetGraphObject().m_Type == GraphObjectTypes::Layer) { + if (theChild == m_Doc.GetActiveLayer()) { + if (m_EditCameraLayerTranslator == nullptr) + m_EditCameraLayerTranslator = + QT3DS_NEW(m_Allocator, SEditCameraLayerTranslator)(theChild, m_Allocator); + else + m_EditCameraLayerTranslator->GetInstanceHandle() = theChild; + theTranslator = m_EditCameraLayerTranslator; + theParentTranslator.AppendChild(theTranslator->GetGraphObject()); + BuildRenderGraph(*m_EditCameraLayerTranslator); + } + } else { + theParentTranslator.AppendChild(theTranslator->GetGraphObject()); + BuildRenderGraph(theChild, inAliasHandle); + + if (theTranslator->GetGraphObject().m_Type == GraphObjectTypes::Effect) + theTranslator->SetActive(false); + else if (theTranslator->GetGraphObject().m_Type == GraphObjectTypes::Camera) + theTranslator->SetActive(false); + else if (theTranslator->GetGraphObject().m_Type == GraphObjectTypes::Light + && m_EditLightEnabled == true) + theTranslator->SetActive(false); + else + theTranslator->SetActive(m_Reader.IsCurrentlyActive(theChild)); + } + } else // Else build the graph and it will be an exact copy of the asset graph. + { + theParentTranslator.AppendChild(theTranslator->GetGraphObject()); + if (m_Reader.IsCurrentlyActive(theChild)) { + BuildRenderGraph(theChild, inAliasHandle); + theTranslator->SetActive(true); + } else { + theTranslator->SetActive(false); + DeactivateScan(*theTranslator, inAliasHandle); + } + } + } + if (GraphObjectTypes::Layer == theParentTranslator.GetGraphObject().m_Type) + m_UICContext.GetRenderer().ChildrenUpdated( + static_cast(theParentTranslator.GetGraphObject())); + + // Allow certain nodes to override their children. + theParentTranslator.AfterRenderGraphIsBuilt(*this); +} + +void STranslation::DeactivateScan(SGraphObjectTranslator &inParent, + CUICDMInstanceHandle inAliasHandle) +{ + SGraphObjectTranslator &theParentTranslator(inParent); + // Alias handles propagate down the scene graph. + if (inParent.GetInstanceHandle() != inParent.GetSceneGraphInstanceHandle()) + inAliasHandle = inParent.GetInstanceHandle(); + for (long idx = 0, end = m_AssetGraph.GetChildCount(inParent.GetSceneGraphInstanceHandle()); + idx < end; ++idx) { + UICDM::CUICDMInstanceHandle theChild( + m_AssetGraph.GetChild(inParent.GetSceneGraphInstanceHandle(), idx)); + SGraphObjectTranslator *theTranslator = GetOrCreateTranslator(theChild, inAliasHandle); + if (theTranslator == nullptr) + continue; + theTranslator->SetActive(false); + DeactivateScan(*theTranslator, inAliasHandle); + } +} + +// We build the render graph every time we render. This may seem wasteful +void STranslation::BuildRenderGraph(UICDM::CUICDMInstanceHandle inParent, + CUICDMInstanceHandle inAliasHandle) +{ + SGraphObjectTranslator *theParentTranslator = GetOrCreateTranslator(inParent, inAliasHandle); + if (theParentTranslator == nullptr) + return; + if (m_Reader.IsCurrentlyActive(inParent) == false) { + theParentTranslator->SetActive(false); + return; + } + BuildRenderGraph(*theParentTranslator, inAliasHandle); +} + +void STranslation::ReleaseTranslation(Q3DStudio::TIdentifier inInstance) +{ + m_TranslatorMap.erase(inInstance); +} + +void STranslation::MarkDirty(UICDM::CUICDMInstanceHandle inInstance) +{ + // Anchor points are not handled individually. + if (m_Reader.GetObjectTypeName(inInstance) == L"PathAnchorPoint") + inInstance = m_AssetGraph.GetParent(inInstance); + GetOrCreateTranslator(inInstance); + + THandleTranslatorPairList &theTranslators = GetTranslatorsForInstance(inInstance); + for (size_t idx = 0, end = theTranslators.size(); idx < end; ++idx) { + m_DirtySet.insert(*theTranslators[(eastl::allocator::size_type)idx].second); + } + RequestRender(); +} + +void STranslation::PreRender() +{ + // Run through the entire asset graph and mark active or inactive if we have an + // associated render representation. + // If we cache all the components and some of their state then we don't have to do this + // but for now it is more stable to run through the graph. + // There is always one root, the scene. + TIdentifier theRoot = m_AssetGraph.GetRoot(0); + ClearDirtySet(); + BuildRenderGraph(theRoot); + m_UICContext.SetScaleMode(uic::render::ScaleModes::ExactSize); + m_UICContext.SetMatteColor(QT3DSVec4(.13f, .13f, .13f, 1.0f)); + QT3DSVec2 theViewportDims(GetViewportDimensions()); + // Ensure the camera points where it should + if (m_EditCameraEnabled) { + m_EditCameraInfo.ApplyToCamera(m_EditCamera, GetViewportDimensions()); + m_EditLight.MarkDirty(uic::render::NodeTransformDirtyFlag::TransformIsDirty); + } + + if (m_Scene) { + CStudioProjectSettings *theSettings = m_Doc.GetCore()->GetStudioProjectSettings(); + CPt thePresSize = theSettings->GetPresentationSize(); + // The presentation sizes are used for when we have to render a layer offscreen. If their + // width and height + // isn't set, then they use the presentation dimensions. + m_Presentation.m_PresentationDimensions = + QT3DSVec2((QT3DSF32)thePresSize.x, (QT3DSF32)thePresSize.y); + QT3DSVec2 theViewportDims(GetViewportDimensions()); + m_UICContext.SetWindowDimensions( + uic::render::SWindowDimensions((QT3DSU32)theViewportDims.x, (QT3DSU32)theViewportDims.y)); + m_UICContext.SetPresentationDimensions( + uic::render::SWindowDimensions((QT3DSU32)m_Presentation.m_PresentationDimensions.x, + (QT3DSU32)m_Presentation.m_PresentationDimensions.y)); + + // set if we draw geometry in wireframe mode + m_UICContext.SetWireframeMode(CStudioPreferences::IsWireframeModeOn()); + + if (m_EditCameraEnabled) { + m_Presentation.m_PresentationDimensions = theViewportDims; + m_UICContext.SetPresentationDimensions( + uic::render::SWindowDimensions((QT3DSU32)theViewportDims.x, (QT3DSU32)theViewportDims.y)); + ::CColor theEditCameraBackground = CStudioPreferences::GetEditViewBackgroundColor(); + m_UICContext.SetSceneColor(QT3DSVec4(theEditCameraBackground.GetRed() / 255.0f, + theEditCameraBackground.GetGreen() / 255.0f, + theEditCameraBackground.GetBlue() / 255.0f, 1.0f)); + } else { + + TIdentifier theRoot = m_AssetGraph.GetRoot(0); + SGraphObjectTranslator *theSceneTranslator = GetOrCreateTranslator(theRoot); + if (theSceneTranslator) { + SScene &theScene = static_cast(theSceneTranslator->GetGraphObject()); + if (theScene.m_UseClearColor) + m_UICContext.SetSceneColor(QT3DSVec4(theScene.m_ClearColor, 1.0f)); + else + m_UICContext.SetSceneColor(QT3DSVec4(QT3DSVec3(0.0f), 1.0f)); + } + } + } + if (m_EditCameraEnabled == false && g_StudioApp.IsAuthorZoom()) { + if (m_Presentation.m_PresentationDimensions.x > theViewportDims.x + || m_Presentation.m_PresentationDimensions.y > theViewportDims.y) { + m_UICContext.SetScaleMode(uic::render::ScaleModes::FitSelected); + } + } +} + +static void CreatePixelRect(STranslation &inTranslation, QT3DSF32 left, QT3DSF32 right, QT3DSF32 bottom, + QT3DSF32 top, QT3DSVec4 color) +{ + SPGRect *theRect = QT3DS_NEW(inTranslation.m_GuideAllocator, SPGRect)(); + theRect->m_Left = left; + theRect->m_Right = right; + theRect->m_Top = top; + theRect->m_Bottom = bottom; + theRect->m_FillColor = color; + inTranslation.m_GuideContainer.push_back(theRect); +} + +static void CreatePixelVertLine(STranslation &inTranslation, QT3DSF32 inXPos, QT3DSF32 inBottom, + QT3DSF32 inTop, QT3DSVec4 color) +{ + SPGVertLine *theLine = QT3DS_NEW(inTranslation.m_GuideAllocator, SPGVertLine)(); + theLine->m_X = inXPos; + theLine->m_Bottom = inBottom; + theLine->m_Top = inTop; + theLine->m_LineColor = color; + inTranslation.m_GuideContainer.push_back(theLine); +} + +static void CreatePixelHorzLine(STranslation &inTranslation, QT3DSF32 inYPos, QT3DSF32 inLeft, + QT3DSF32 inRight, QT3DSVec4 color) +{ + SPGHorzLine *theLine = QT3DS_NEW(inTranslation.m_GuideAllocator, SPGHorzLine)(); + theLine->m_Y = inYPos; + theLine->m_Left = inLeft; + theLine->m_Right = inRight; + theLine->m_LineColor = color; + inTranslation.m_GuideContainer.push_back(theLine); +} + +static void CreateTopBottomTickMarks(STranslation &inTranslation, QT3DSF32 posX, QT3DSF32 innerBottom, + QT3DSF32 innerTop, QT3DSF32 outerBottom, QT3DSF32 outerTop, + QT3DSF32 lineHeight, QT3DSVec4 lineColor) +{ + CreatePixelVertLine(inTranslation, posX, innerBottom - lineHeight, innerBottom, lineColor); + CreatePixelVertLine(inTranslation, posX, innerTop, innerTop + lineHeight, lineColor); +} + +static void DrawTickMarksOnHorizontalRects(STranslation &inTranslation, QT3DSF32 innerLeft, + QT3DSF32 innerRight, QT3DSF32 innerBottom, QT3DSF32 innerTop, + QT3DSF32 outerBottom, QT3DSF32 outerTop, QT3DSVec4 lineColor) +{ + QT3DSF32 centerPosX = floor(innerLeft + (innerRight - innerLeft) / 2.0f + .5f); + CreateTopBottomTickMarks(inTranslation, centerPosX, innerBottom, innerTop, outerBottom, + outerTop, 15, lineColor); + for (QT3DSU32 incrementor = 10; + (centerPosX + incrementor) < innerRight && (centerPosX - incrementor) > innerLeft; + incrementor += 10) { + QT3DSF32 rightEdge = centerPosX + incrementor; + QT3DSF32 leftEdge = centerPosX - incrementor; + QT3DSF32 lineHeight = 0; + if (incrementor % 100 == 0) + lineHeight = 11; + else if (incrementor % 20) + lineHeight = 4; + else + lineHeight = 2; + + if (rightEdge < innerRight) + CreateTopBottomTickMarks(inTranslation, rightEdge, innerBottom, innerTop, outerBottom, + outerTop, lineHeight, lineColor); + if (leftEdge > innerLeft) + CreateTopBottomTickMarks(inTranslation, leftEdge, innerBottom, innerTop, outerBottom, + outerTop, lineHeight, lineColor); + } +} + +static void CreateLeftRightTickMarks(STranslation &inTranslation, QT3DSF32 inYPos, QT3DSF32 innerLeft, + QT3DSF32 innerRight, QT3DSF32 outerLeft, QT3DSF32 outerRight, + QT3DSF32 lineLength, QT3DSVec4 lineColor) +{ + CreatePixelHorzLine(inTranslation, inYPos, innerLeft - lineLength, innerLeft, lineColor); + CreatePixelHorzLine(inTranslation, inYPos, innerRight, innerRight + lineLength, lineColor); +} + +static void DrawTickMarksOnVerticalRects(STranslation &inTranslation, QT3DSF32 innerLeft, + QT3DSF32 innerRight, QT3DSF32 innerBottom, QT3DSF32 innerTop, + QT3DSF32 outerLeft, QT3DSF32 outerRight, QT3DSVec4 lineColor) +{ + QT3DSF32 centerPosY = floor(innerBottom + (innerTop - innerBottom) / 2.0f + .5f); + CreateLeftRightTickMarks(inTranslation, centerPosY, innerLeft, innerRight, outerLeft, + outerRight, 15, lineColor); + for (QT3DSU32 incrementor = 10; + (centerPosY + incrementor) < innerTop && (centerPosY - incrementor) > innerBottom; + incrementor += 10) { + QT3DSF32 topEdge = centerPosY + incrementor; + QT3DSF32 bottomEdge = centerPosY - incrementor; + QT3DSF32 lineHeight = 0; + if (incrementor % 100 == 0) + lineHeight = 11; + else if (incrementor % 20) + lineHeight = 4; + else + lineHeight = 2; + + if (topEdge < innerTop) + CreateLeftRightTickMarks(inTranslation, topEdge, innerLeft, innerRight, outerLeft, + outerRight, lineHeight, lineColor); + if (bottomEdge > innerBottom) + CreateLeftRightTickMarks(inTranslation, bottomEdge, innerLeft, innerRight, outerLeft, + outerRight, lineHeight, lineColor); + } +} + +class IGuideElementFactory +{ +protected: + virtual ~IGuideElementFactory() {} +public: + virtual void CreateLine(QT3DSF32 inPos) = 0; + virtual void CreateRect(QT3DSF32 inPosMin, QT3DSF32 inPosMax) = 0; +}; + +static void CreateGuide(IGuideElementFactory &inFactory, QT3DSF32 inPos, QT3DSF32 inWidth) +{ + QT3DSF32 halfWidth = inWidth / 2.0f; + QT3DSF32 leftLine = floor(inPos + 1.0f - halfWidth); + inFactory.CreateLine(leftLine); + // Then we are done if not enough width + if (inWidth < 2.0f) + return; + + QT3DSF32 rightLine = leftLine + inWidth - 1; + inFactory.CreateLine(rightLine); + + if (inWidth < 3.0f) + return; + QT3DSF32 rectStart = leftLine + 1; + QT3DSF32 rectStop = rectStart + inWidth - 2.0f; + inFactory.CreateRect(rectStart, rectStop); +} + +struct SHorizontalGuideFactory : public IGuideElementFactory +{ + STranslation &m_Translation; + QT3DSF32 m_Start; + QT3DSF32 m_Stop; + QT3DSVec4 m_LineColor; + QT3DSVec4 m_FillColor; + SHorizontalGuideFactory(STranslation &trans, QT3DSF32 start, QT3DSF32 stop, QT3DSVec4 lineColor, + QT3DSVec4 fillColor) + : m_Translation(trans) + , m_Start(start) + , m_Stop(stop) + , m_LineColor(lineColor) + , m_FillColor(fillColor) + { + } + void CreateLine(QT3DSF32 inPos) override + { + CreatePixelHorzLine(m_Translation, inPos, m_Start, m_Stop, m_LineColor); + } + + void CreateRect(QT3DSF32 inPosMin, QT3DSF32 inPosMax) override + { + CreatePixelRect(m_Translation, m_Start, m_Stop, inPosMin, inPosMax, m_FillColor); + } +}; + +struct SVerticalGuideFactory : public IGuideElementFactory +{ + STranslation &m_Translation; + QT3DSF32 m_Start; + QT3DSF32 m_Stop; + QT3DSVec4 m_LineColor; + QT3DSVec4 m_FillColor; + SVerticalGuideFactory(STranslation &trans, QT3DSF32 start, QT3DSF32 stop, QT3DSVec4 lineColor, + QT3DSVec4 fillColor) + : m_Translation(trans) + , m_Start(start) + , m_Stop(stop) + , m_LineColor(lineColor) + , m_FillColor(fillColor) + { + } + void CreateLine(QT3DSF32 inPos) override + { + CreatePixelVertLine(m_Translation, inPos, m_Start, m_Stop, m_LineColor); + } + + void CreateRect(QT3DSF32 inPosMin, QT3DSF32 inPosMax) override + { + CreatePixelRect(m_Translation, inPosMin, inPosMax, m_Start, m_Stop, m_FillColor); + } +}; + +void STranslation::Render(int inWidgetId, bool inDrawGuides) +{ + // For now, we just render. + // Next step will be to get the bounding boxes and such setup. + // but we will want a custom renderer to do that. + if (m_Scene) { + // Note that begin frame is called before we allocate the bounding box and axis widgets so + // that we can take advantage of the renderer's per-frame-allocator. + m_UICContext.BeginFrame(); + // Render the bounding boxes and extra widgets. + // This is called *before* the render because these sort of appendages need to be added + // to the layer renderables. + UICDM::TInstanceHandleList theHandles = m_Doc.GetSelectedValue().GetSelectedInstances(); + + // Don't show the bounding box or pivot for the component we are *in* the component + SGraphObjectTranslator *theTranslator = nullptr; + long theToolMode = g_StudioApp.GetToolMode(); + bool isEditCamera = m_EditCameraEnabled; + int theCameraToolMode = isEditCamera ? (theToolMode & (STUDIO_CAMERATOOL_MASK)) : 0; + long theModifiers = CHotKeys::GetCurrentKeyModifiers(); + bool shouldDisplayWidget = false; + if (theCameraToolMode == 0) { + switch (theToolMode) { + default: + break; + case STUDIO_TOOLMODE_MOVE: + case STUDIO_TOOLMODE_ROTATE: + case STUDIO_TOOLMODE_SCALE: + shouldDisplayWidget = true; + break; + }; + } + + SDisableUseClearColor color(*this, isEditCamera); + bool selectedPath = false; + + for (size_t selectedIdx = 0, selectedEnd = theHandles.size(); selectedIdx < selectedEnd; + ++selectedIdx) { + UICDM::CUICDMInstanceHandle theInstance = theHandles[selectedIdx]; + if (theInstance + != m_Doc.GetDocumentReader().GetComponentForSlide(m_Doc.GetActiveSlide())) { + if (m_Doc.GetDocumentReader().GetObjectTypeName(theInstance) + == L"PathAnchorPoint") { + theInstance = m_AssetGraph.GetParent(m_AssetGraph.GetParent(theInstance)); + shouldDisplayWidget = false; + } + theTranslator = GetOrCreateTranslator(theInstance); + // Get the tool mode right now. + if (theTranslator) { + GraphObjectTypes::Enum theType(theTranslator->GetGraphObject().m_Type); + if (CStudioPreferences::IsBoundingBoxesOn()) { + switch (theType) { + case GraphObjectTypes::Node: + DrawGroupBoundingBoxes(*theTranslator); + break; + case GraphObjectTypes::Text: + case GraphObjectTypes::Model: + case GraphObjectTypes::Layer: + case GraphObjectTypes::Light: + case GraphObjectTypes::Path: + DrawNonGroupBoundingBoxes(*theTranslator); + break; + } + } + // Don't draw the axis if there is a widget. + if (CStudioPreferences::ShouldDisplayPivotPoint() + && shouldDisplayWidget == false) { + switch (theTranslator->GetGraphObject().m_Type) { + case GraphObjectTypes::Node: + case GraphObjectTypes::Text: + case GraphObjectTypes::Model: + DrawAxis(*theTranslator); + break; + } + } + if (theType == GraphObjectTypes::Path && selectedPath == false) { + selectedPath = true; + if (!m_PathWidget) + m_PathWidget = uic::widgets::IPathWidget::CreatePathWidget( + m_UICContext.GetAllocator(), m_UICContext); + m_PathWidget->SetNode( + static_cast(theTranslator->GetGraphObject())); + m_UICContext.GetRenderer().AddRenderWidget(*m_PathWidget); + } + } + } + } + + if (theHandles.size() > 1) + theTranslator = nullptr; + + uic::widgets::IStudioWidget *theNextWidget(nullptr); + if (theTranslator && GraphObjectTypes::IsNodeType(theTranslator->GetGraphObject().m_Type) + && theTranslator->GetGraphObject().m_Type != GraphObjectTypes::Layer) { + + uic::render::SNode &theNode( + static_cast(theTranslator->GetGraphObject())); + SCamera *theRenderCamera = m_UICContext.GetRenderer().GetCameraForNode(theNode); + bool isActiveCamera = theRenderCamera == (static_cast(&theNode)); + if (shouldDisplayWidget && isActiveCamera == false) { + switch (theToolMode) { + default: + QT3DS_ASSERT(false); + break; + case STUDIO_TOOLMODE_MOVE: + // Render translation widget + if (!m_TranslationWidget) + m_TranslationWidget = uic::widgets::IStudioWidget::CreateTranslationWidget( + m_UICContext.GetAllocator()); + theNextWidget = m_TranslationWidget.mPtr; + break; + case STUDIO_TOOLMODE_ROTATE: + if (!m_RotationWidget) + m_RotationWidget = uic::widgets::IStudioWidget::CreateRotationWidget( + m_UICContext.GetAllocator()); + theNextWidget = m_RotationWidget.mPtr; + break; + + case STUDIO_TOOLMODE_SCALE: + if (!m_ScaleWidget) + m_ScaleWidget = uic::widgets::IStudioWidget::CreateScaleWidget( + m_UICContext.GetAllocator()); + theNextWidget = m_ScaleWidget.mPtr; + break; + } + if (theNextWidget) { + theNextWidget->SetNode(static_cast(theTranslator->GetGraphObject())); + m_UICContext.GetRenderer().AddRenderWidget(*theNextWidget); + } + } + } + if (m_LastRenderedWidget.mPtr && m_LastRenderedWidget.mPtr != theNextWidget) + ResetWidgets(); + + m_LastRenderedWidget = theNextWidget; + if (m_LastRenderedWidget) { + m_LastRenderedWidget->SetSubComponentId(inWidgetId); + switch (g_StudioApp.GetMinpulationMode()) { + case StudioManipulationModes::Local: + m_LastRenderedWidget->SetRenderWidgetMode(uic::render::RenderWidgetModes::Local); + break; + case StudioManipulationModes::Global: + m_LastRenderedWidget->SetRenderWidgetMode(uic::render::RenderWidgetModes::Global); + break; + default: + QT3DS_ASSERT(false); + break; + } + } + + m_Scene->PrepareForRender(GetViewportDimensions(), m_UICContext); + + m_UICContext.RunRenderTasks(); + + m_Scene->Render(GetViewportDimensions(), m_UICContext, SScene::DoNotClear); + + if (inDrawGuides && m_EditCameraEnabled == false && g_StudioApp.IsAuthorZoom() == false) { + m_GuideContainer.clear(); + // Figure out the matte area. + NVRenderRect theContextViewport = m_UICContext.GetContextViewport(); + NVRenderRect thePresentationViewport = m_UICContext.GetPresentationViewport(); + m_UICContext.GetRenderContext().SetViewport(theContextViewport); + QT3DSI32 innerLeft = thePresentationViewport.m_X; + QT3DSI32 innerRight = thePresentationViewport.m_X + thePresentationViewport.m_Width; + QT3DSI32 innerBottom = thePresentationViewport.m_Y; + QT3DSI32 innerTop = thePresentationViewport.m_Y + thePresentationViewport.m_Height; + + QT3DSI32 outerLeft = innerLeft - 16; + QT3DSI32 outerRight = innerRight + 16; + QT3DSI32 outerBottom = innerBottom - 16; + QT3DSI32 outerTop = innerTop + 16; + // Retain the rects for picking purposes. + m_InnerRect = SRulerRect(innerLeft, innerTop, innerRight, innerBottom); + m_OuterRect = SRulerRect(outerLeft, outerTop, outerRight, outerBottom); + + // Draw tick marks around the presentation + CreatePixelRect(*this, (QT3DSF32)outerLeft, (QT3DSF32)innerLeft, (QT3DSF32)innerBottom, + (QT3DSF32)innerTop, m_rectColor); + CreatePixelRect(*this, (QT3DSF32)innerRight, (QT3DSF32)outerRight, + (QT3DSF32)innerBottom, (QT3DSF32)innerTop, m_rectColor); + CreatePixelRect(*this, (QT3DSF32)innerLeft, (QT3DSF32)innerRight, (QT3DSF32)outerBottom, + (QT3DSF32)innerBottom, m_rectColor); + CreatePixelRect(*this, (QT3DSF32)innerLeft, (QT3DSF32)innerRight, (QT3DSF32)innerTop, + (QT3DSF32)outerTop, m_rectColor); + DrawTickMarksOnHorizontalRects(*this, (QT3DSF32)innerLeft, (QT3DSF32)innerRight, + (QT3DSF32)innerBottom, (QT3DSF32)innerTop, + (QT3DSF32)outerBottom, (QT3DSF32)outerTop, m_lineColor); + DrawTickMarksOnVerticalRects(*this, (QT3DSF32)innerLeft, (QT3DSF32)innerRight, + (QT3DSF32)innerBottom, (QT3DSF32)innerTop, + (QT3DSF32)outerLeft, (QT3DSF32)outerRight, m_lineColor); + UICDM::TGuideHandleList theGuides = m_Doc.GetDocumentReader().GetGuides(); + UICDM::CUICDMGuideHandle theSelectedGuide; + Q3DStudio::SSelectedValue theSelection = m_Doc.GetSelectedValue(); + if (theSelection.getType() == Q3DStudio::SelectedValueTypes::Guide) + theSelectedGuide = theSelection.getData(); + + // Draw guides + for (size_t guideIdx = 0, guideEnd = theGuides.size(); guideIdx < guideEnd; + ++guideIdx) { + UICDM::SGuideInfo theInfo = + m_Doc.GetDocumentReader().GetGuideInfo(theGuides[guideIdx]); + bool isGuideSelected = theGuides[guideIdx] == theSelectedGuide; + QT3DSVec4 theColor = isGuideSelected ? m_selectedGuideColor : m_guideColor; + QT3DSVec4 theFillColor = isGuideSelected ? m_selectedGuideFillColor + : m_guideFillColor; + switch (theInfo.m_Direction) { + case UICDM::GuideDirections::Horizontal: { + SHorizontalGuideFactory theFactory(*this, (QT3DSF32)innerLeft, (QT3DSF32)innerRight, + theColor, theFillColor); + CreateGuide(theFactory, (QT3DSF32)m_InnerRect.m_Bottom + theInfo.m_Position, + (QT3DSF32)theInfo.m_Width); + } break; + case UICDM::GuideDirections::Vertical: { + SVerticalGuideFactory theFactory(*this, (QT3DSF32)innerBottom, (QT3DSF32)innerTop, + theColor, theFillColor); + CreateGuide(theFactory, (QT3DSF32)m_InnerRect.m_Left + theInfo.m_Position, + (QT3DSF32)theInfo.m_Width); + } break; + default: + QT3DS_ASSERT(false); + break; + } + } + m_UICContext.GetPixelGraphicsRenderer().Render( + qt3ds::foundation::toDataRef(m_GuideContainer.data(), m_GuideContainer.size())); + + m_GuideContainer.clear(); + m_GuideAllocator.reset(); + } + + m_UICContext.EndFrame(); + + if (m_ZoomRender.hasValue()) { + RenderZoomRender(*m_ZoomRender); + m_ZoomRender = Empty(); + } + + // Render the pick buffer, useful for debugging why a widget wasn't hit. + /* + if ( m_PickBuffer ) + { + qt3ds::render::NVRenderContext& theRenderContext( m_UICContext.GetRenderContext() ); + qt3ds::render::STextureDetails thePickDetails = m_PickBuffer->GetTextureDetails(); + theRenderContext.SetViewport( qt3ds::render::NVRenderRect( 0, 0, thePickDetails.m_Width, + thePickDetails.m_Height ) ); + uic::render::SCamera theCamera; + theCamera.MarkDirty( uic::render::NodeTransformDirtyFlag::TransformIsDirty ); + theCamera.m_Flags.SetOrthographic( true ); + QT3DSVec2 theDimensions( (QT3DSF32)thePickDetails.m_Width, (QT3DSF32)thePickDetails.m_Height ); + theCamera.CalculateGlobalVariables( render::NVRenderRectF( 0, 0, theDimensions.x, + theDimensions.y ), theDimensions ); + QT3DSMat44 theVP; + theCamera.CalculateViewProjectionMatrix( theVP ); + theRenderContext.SetCullingEnabled( false ); + theRenderContext.SetBlendingEnabled( false ); + theRenderContext.SetDepthTestEnabled( false ); + theRenderContext.SetDepthWriteEnabled( false ); + m_UICContext.GetRenderer().RenderQuad( theDimensions, theVP, *m_PickBuffer ); + }*/ + } +} + +void STranslation::ResetWidgets() +{ + if (m_ScaleWidget) + m_ScaleWidget->SetAxisScale(QT3DSVec3(1, 1, 1)); + if (m_RotationWidget) + m_RotationWidget->ClearRotationEdges(); + m_CumulativeRotation = 0.0f; +} + +void STranslation::DoPrepareForDrag(SNode *inSelectedNode) +{ + if (inSelectedNode == nullptr) + return; + + m_MouseDownNode = *inSelectedNode; + m_MouseDownParentGlobalTransformInverse = Empty(); + m_MouseDownParentRotationInverse = Empty(); + m_MouseDownGlobalRotation = Empty(); + // Orphan this node manually since it is a straight copy + m_MouseDownNode.m_Parent = nullptr; + m_MouseDownNode.m_FirstChild = nullptr; + m_MouseDownNode.m_NextSibling = nullptr; + SCamera *theCamera = m_UICContext.GetRenderer().GetCameraForNode(*inSelectedNode); + m_CumulativeRotation = 0.0f; + if (theCamera == nullptr) + return; + m_MouseDownCamera = *theCamera; + m_LastPathDragValue = Empty(); +} + +void STranslation::EndDrag() +{ + ResetWidgets(); +} + +bool STranslation::IsPathWidgetActive() +{ + UICDM::TInstanceHandleList theHandles = m_Doc.GetSelectedValue().GetSelectedInstances(); + for (size_t selectedIdx = 0, selectedEnd = theHandles.size(); selectedIdx < selectedEnd; + ++selectedIdx) { + UICDM::CUICDMInstanceHandle theInstance(theHandles[selectedIdx]); + if (m_Doc.GetDocumentReader().GetObjectTypeName(theInstance) == L"PathAnchorPoint") + theInstance = m_AssetGraph.GetParent(m_AssetGraph.GetParent(theInstance)); + SGraphObjectTranslator *theTranslator = GetOrCreateTranslator(theInstance); + if (theTranslator && theTranslator->GetGraphObject().m_Type == GraphObjectTypes::Path) + return true; + } + return false; +} + +inline uic::render::SLayer *GetLayerForNode(const uic::render::SNode &inNode) +{ + SNode *theNode; + // empty loop intentional + for (theNode = const_cast(&inNode); + theNode && theNode->m_Type != GraphObjectTypes::Layer; theNode = theNode->m_Parent) { + } + if (theNode && theNode->m_Type == GraphObjectTypes::Layer) + return static_cast(theNode); + return nullptr; +} + +void STranslation::RenderZoomRender(SZoomRender &inRender) +{ + SLayer *theLayer(inRender.m_Layer); + CPt thePoint(inRender.m_Point); + if (theLayer) { + uic::render::IUICRenderer &theRenderer(m_UICContext.GetRenderer()); + Option thePickSetup( + theRenderer.GetLayerPickSetup(*theLayer, QT3DSVec2((QT3DSF32)thePoint.x, (QT3DSF32)thePoint.y), + uic::render::SWindowDimensions(16, 16))); + if (thePickSetup.hasValue()) { + qt3ds::render::NVRenderContext &theRenderContext(m_UICContext.GetRenderContext()); + theRenderContext.SetViewport(qt3ds::render::NVRenderRect(0, 0, 100, 100)); + theRenderContext.SetScissorRect(qt3ds::render::NVRenderRect(0, 0, 100, 100)); + theRenderContext.SetDepthWriteEnabled(true); + theRenderContext.SetScissorTestEnabled(true); + theRenderContext.SetClearColor(QT3DSVec4(.2, .2, .2, 0)); + theRenderContext.Clear(qt3ds::render::NVRenderClearFlags( + qt3ds::render::NVRenderClearValues::Color | qt3ds::render::NVRenderClearValues::Depth)); + theRenderer.RunLayerRender(*theLayer, thePickSetup->m_ViewProjection); + theRenderContext.SetScissorTestEnabled(false); + } + } +} + +void STranslation::DrawBoundingBox(SNode &inNode, QT3DSVec3 inColor) +{ + qt3ds::NVBounds3 theBounds = inNode.GetBounds(m_UICContext.GetBufferManager(), + m_UICContext.GetPathManager(), true, this); + uic::render::IRenderWidget &theBBoxWidget = uic::render::IRenderWidget::CreateBoundingBoxWidget( + inNode, theBounds, inColor, m_UICContext.GetRenderer().GetPerFrameAllocator()); + m_UICContext.GetRenderer().AddRenderWidget(theBBoxWidget); +} + +void STranslation::DrawLightBoundingBox(SNode &inNode, QT3DSVec3 inColor) +{ + SLight *theLight = reinterpret_cast(&inNode); + if (theLight->m_LightType != uic::render::RenderLightTypes::Area) { + return; + } + + qt3ds::NVBounds3 theBounds( + qt3ds::QT3DSVec3(-theLight->m_AreaWidth * 0.5f, -theLight->m_AreaHeight * 0.5f, 0.0f), + qt3ds::QT3DSVec3(theLight->m_AreaWidth * 0.5f, theLight->m_AreaHeight * 0.5f, 0.0f)); + uic::render::IRenderWidget &theBBoxWidget = uic::render::IRenderWidget::CreateBoundingBoxWidget( + inNode, theBounds, inColor, m_UICContext.GetRenderer().GetPerFrameAllocator()); + m_UICContext.GetRenderer().AddRenderWidget(theBBoxWidget); +} + +void STranslation::DrawAxis(SGraphObjectTranslator &inTranslator) +{ + if (GraphObjectTypes::IsNodeType(inTranslator.GetGraphObject().m_Type)) { + uic::render::IRenderWidget &theAxisWidget = uic::render::IRenderWidget::CreateAxisWidget( + static_cast(inTranslator.GetGraphObject()), + m_UICContext.GetRenderer().GetPerFrameAllocator()); + m_UICContext.GetRenderer().AddRenderWidget(theAxisWidget); + } else { + QT3DS_ASSERT(false); + } +} + +Option STranslation::PickWidget(CPt inMouseCoords, TranslationSelectMode::Enum, + uic::widgets::IStudioWidgetBase &inWidget) +{ + SNode &theNode = inWidget.GetNode(); + SGraphObjectTranslator *theWidgetTranslator = + theNode.m_UserData.DynamicCast(); + SLayer *theLayer = GetLayerForNode(theNode); + if (theLayer && theWidgetTranslator) { + Option thePickSetup( + m_UICContext.GetRenderer().GetLayerPickSetup( + *theLayer, QT3DSVec2((QT3DSF32)inMouseCoords.x, (QT3DSF32)inMouseCoords.y), + uic::render::SWindowDimensions(4, 4))); + if (thePickSetup.hasValue()) { + qt3ds::render::NVRenderContext &theContext(m_UICContext.GetRenderContext()); + qt3ds::render::NVRenderContextScopedProperty + __currentrt(theContext, &qt3ds::render::NVRenderContext::GetRenderTarget, + &qt3ds::render::NVRenderContext::SetRenderTarget); + qt3ds::render::NVRenderFrameBuffer *theFBO = + m_UICContext.GetResourceManager().AllocateFrameBuffer(); + const QT3DSU32 fboDims = 8; + if (!m_PickBuffer) { + m_PickBuffer = theContext.CreateTexture2D(); + m_PickBuffer->SetTextureData(qt3ds::foundation::NVDataRef(), 0, fboDims, + fboDims, + qt3ds::render::NVRenderTextureFormats::LuminanceAlpha8); + } + qt3ds::render::NVRenderRenderBuffer *theRenderBuffer = + m_UICContext.GetResourceManager().AllocateRenderBuffer( + fboDims, fboDims, qt3ds::render::NVRenderRenderBufferFormats::Depth16); + theFBO->Attach(qt3ds::render::NVRenderFrameBufferAttachments::Color0, + qt3ds::render::NVRenderTextureOrRenderBuffer(*m_PickBuffer)); + theFBO->Attach(qt3ds::render::NVRenderFrameBufferAttachments::Depth, + qt3ds::render::NVRenderTextureOrRenderBuffer(*theRenderBuffer)); + qt3ds::render::NVRenderRect theViewport(0, 0, fboDims, fboDims); + theContext.SetViewport(theViewport); + theContext.SetDepthWriteEnabled(true); + theContext.SetDepthTestEnabled(true); + theContext.SetScissorTestEnabled(false); + theContext.SetBlendingEnabled(false); + theContext.SetClearColor(QT3DSVec4(0, 0, 0, 0)); + theContext.Clear(qt3ds::render::NVRenderClearFlags( + qt3ds::render::NVRenderClearValues::Color | qt3ds::render::NVRenderClearValues::Depth)); + inWidget.RenderPick(thePickSetup->m_ProjectionPreMultiply, theContext, + uic::render::SWindowDimensions(4, 4)); + // Now read the pixels back. + m_PixelBuffer.resize(fboDims * fboDims * 3); + theContext.ReadPixels(theViewport, qt3ds::render::NVRenderReadPixelFormats::RGB8, + m_PixelBuffer); + m_UICContext.GetResourceManager().Release(*theFBO); + m_UICContext.GetResourceManager().Release(*theRenderBuffer); + eastl::hash_map tallies; + QT3DSU32 numPixels = fboDims * fboDims; + for (QT3DSU32 idx = 0; idx < numPixels; ++idx) { + qt3ds::QT3DSU16 theChannelAmount = + m_PixelBuffer[idx * 3] + (m_PixelBuffer[idx * 3 + 1] << 8); + if (theChannelAmount) + tallies.insert(eastl::make_pair(theChannelAmount, (QT3DSU32)0)).first->second += 1; + } + QT3DSU32 tallyMaxTally = 0; + QT3DSU32 tallyMaxIdx = 0; + for (eastl::hash_map::iterator iter = tallies.begin(), + end = tallies.end(); + iter != end; ++iter) { + if (iter->second > tallyMaxTally) { + tallyMaxTally = iter->second; + tallyMaxIdx = iter->first; + } + } + if (tallyMaxIdx > 0) { + return tallyMaxIdx; + } + } + } + return Empty(); +} + +SStudioPickValue STranslation::Pick(CPt inMouseCoords, TranslationSelectMode::Enum inSelectMode) +{ + bool requestRender = false; + + if (m_Doc.GetDocumentReader().AreGuidesEditable()) { + UICDM::TGuideHandleList theGuides = m_Doc.GetDocumentReader().GetGuides(); + CPt renderSpacePt(inMouseCoords.x - (long)m_InnerRect.m_Left, + (long)GetViewportDimensions().y - inMouseCoords.y + - (long)m_InnerRect.m_Bottom); + for (size_t guideIdx = 0, guideEnd = theGuides.size(); guideIdx < guideEnd; ++guideIdx) { + UICDM::SGuideInfo theGuideInfo = + m_Doc.GetDocumentReader().GetGuideInfo(theGuides[guideIdx]); + float width = (theGuideInfo.m_Width / 2.0f) + 2.0f; + switch (theGuideInfo.m_Direction) { + case UICDM::GuideDirections::Horizontal: + if (fabs((float)renderSpacePt.y - theGuideInfo.m_Position) <= width) + return theGuides[guideIdx]; + break; + case UICDM::GuideDirections::Vertical: + if (fabs((float)renderSpacePt.x - theGuideInfo.m_Position) <= width) + return theGuides[guideIdx]; + break; + } + } + } + if (IsPathWidgetActive()) { + Option picked = PickWidget(inMouseCoords, inSelectMode, *m_PathWidget); + if (picked.hasValue()) { + RequestRender(); + DoPrepareForDrag(&m_PathWidget->GetNode()); + return m_PathWidget->PickIndexToPickValue(*picked); + } + } + // Pick against the widget first if possible. + if (m_LastRenderedWidget) { + Option picked = PickWidget(inMouseCoords, inSelectMode, *m_LastRenderedWidget); + if (picked.hasValue()) { + RequestRender(); + DoPrepareForDrag(&m_LastRenderedWidget->GetNode()); + return m_LastRenderedWidget->PickIndexToPickValue(*picked); + } + } + if (m_Scene && m_Scene->m_FirstChild) { + uic::render::SUICRenderPickResult thePickResult = + m_UICContext.GetRenderer().Pick(*m_Scene->m_FirstChild, GetViewportDimensions(), + QT3DSVec2((QT3DSF32)inMouseCoords.x, (QT3DSF32)inMouseCoords.y)); + if (thePickResult.m_HitObject) { + const SGraphObject &theObject = *thePickResult.m_HitObject; + if (theObject.m_Type == GraphObjectTypes::Model + || theObject.m_Type == GraphObjectTypes::Text + || theObject.m_Type == GraphObjectTypes::Path) { + const SNode &theTranslatorModel(static_cast(theObject)); + SGraphObjectTranslator *theTranslator = + theTranslatorModel.m_UserData.DynamicCast(); + const SNode *theModelPtr = &theTranslatorModel; + if (theTranslator->GetPossiblyAliasedInstanceHandle() + != theTranslator->GetInstanceHandle()) { + theTranslator = + GetOrCreateTranslator(theTranslator->GetPossiblyAliasedInstanceHandle()); + theModelPtr = + static_cast(&theTranslator->GetNonAliasedGraphObject()); + } + CUICDMInstanceHandle theActiveComponent = + m_Reader.GetComponentForSlide(m_Doc.GetActiveSlide()); + if (inSelectMode == TranslationSelectMode::Group) { + // Bounce up the hierarchy till one of two conditions are met + // the parent is a layer or the our component is the active component + // but the parent's is not. + while (theTranslator && GraphObjectTypes::IsNodeType( + theTranslator->GetGraphObject().m_Type)) { + SNode *myNode = static_cast(&theTranslator->GetGraphObject()); + if (myNode->m_Parent == nullptr) { + theTranslator = nullptr; + break; + } + SNode *parentNode = myNode->m_Parent; + SGraphObjectTranslator *theParentTranslator = + parentNode->m_UserData.DynamicCast(); + CUICDMInstanceHandle myComponent = + m_Reader.GetAssociatedComponent(theTranslator->GetInstanceHandle()); + CUICDMInstanceHandle myParentComponent = m_Reader.GetAssociatedComponent( + theParentTranslator->GetInstanceHandle()); + if (parentNode->m_Type == GraphObjectTypes::Layer) { + if (myParentComponent != theActiveComponent) + theTranslator = nullptr; + break; + } + if (myComponent == theActiveComponent + && myParentComponent != theActiveComponent) + break; + theTranslator = theParentTranslator; + } + } else { + // Bounce up until we get into the active component and then stop. + while (inSelectMode == TranslationSelectMode::Single && theTranslator + && GraphObjectTypes::IsNodeType(theTranslator->GetGraphObject().m_Type) + && m_Reader.GetAssociatedComponent(theTranslator->GetInstanceHandle()) + != theActiveComponent) { + SNode *theNode = static_cast(&theTranslator->GetGraphObject()); + theNode = theNode->m_Parent; + if (theNode && theNode->m_Type != GraphObjectTypes::Layer) + theTranslator = + theNode->m_UserData.DynamicCast(); + else + theTranslator = nullptr; + } + } + + if (theTranslator) { + QT3DS_ASSERT(GraphObjectTypes::IsNodeType(theTranslator->GetGraphObject().m_Type)); + DoPrepareForDrag(static_cast(&theTranslator->GetGraphObject())); + return theTranslator->GetInstanceHandle(); + } + } + } + if (requestRender) + RequestRender(); + } + return SStudioPickValue(); +} + +qt3ds::foundation::Option STranslation::PickRulers(CPt inMouseCoords) +{ + CPt renderSpacePt(inMouseCoords.x, (long)GetViewportDimensions().y - inMouseCoords.y); + // If mouse is inside outer rect but outside inner rect. + if (m_OuterRect.Contains(renderSpacePt.x, renderSpacePt.y) + && !m_InnerRect.Contains(renderSpacePt.x, renderSpacePt.y)) { + std::shared_ptr theGuideSystem = + m_StudioSystem.GetFullSystem()->GetCoreSystem()->GetGuideSystem(); + if (renderSpacePt.x >= m_InnerRect.m_Left && renderSpacePt.x <= m_InnerRect.m_Right) { + return UICDM::SGuideInfo((QT3DSF32)renderSpacePt.y - (QT3DSF32)m_InnerRect.m_Bottom, + UICDM::GuideDirections::Horizontal); + } else if (renderSpacePt.y >= m_InnerRect.m_Bottom + && renderSpacePt.y <= m_InnerRect.m_Top) { + return UICDM::SGuideInfo((QT3DSF32)renderSpacePt.x - (QT3DSF32)m_InnerRect.m_Left, + UICDM::GuideDirections::Vertical); + } + } + return qt3ds::foundation::Option(); +} + +QT3DSVec3 STranslation::GetIntendedPosition(UICDM::CUICDMInstanceHandle inInstance, CPt inPos) +{ + ClearDirtySet(); + SGraphObjectTranslator *theTranslator = GetOrCreateTranslator(inInstance); + if (theTranslator == nullptr) + return QT3DSVec3(0, 0, 0); + if (GraphObjectTypes::IsNodeType(theTranslator->GetGraphObject().m_Type) == false) + return QT3DSVec3(0, 0, 0); + SNode *theNode = static_cast(&theTranslator->GetGraphObject()); + SCamera *theCamera = m_UICContext.GetRenderer().GetCameraForNode(*theNode); + { + // Get the node's parent + CUICDMInstanceHandle theParent = m_AssetGraph.GetParent(inInstance); + SGraphObjectTranslator *theParentTranslator = GetOrCreateTranslator(theParent); + if (theParentTranslator + && GraphObjectTypes::IsNodeType(theParentTranslator->GetGraphObject().m_Type)) + theCamera = m_UICContext.GetRenderer().GetCameraForNode( + *static_cast(&theParentTranslator->GetGraphObject())); + } + if (theCamera == nullptr) + return QT3DSVec3(0, 0, 0); + + QT3DSVec3 theGlobalPos(theNode->GetGlobalPos()); + return m_UICContext.GetRenderer().UnprojectToPosition(*theCamera, theGlobalPos, + QT3DSVec2((QT3DSF32)inPos.x, (QT3DSF32)inPos.y)); +} + +static void CheckLockToAxis(QT3DSF32 &inXDistance, QT3DSF32 &inYDistance, bool inLockToAxis) +{ + if (inLockToAxis) { + if (fabs(inXDistance) > fabs(inYDistance)) + inYDistance = 0; + else + inXDistance = 0; + } +} + +void STranslation::ApplyPositionalChange(QT3DSVec3 inDiff, SNode &inNode, + CUpdateableDocumentEditor &inEditor) +{ + if (m_MouseDownParentGlobalTransformInverse.isEmpty()) { + if (inNode.m_Parent) + m_MouseDownParentGlobalTransformInverse = + inNode.m_Parent->m_GlobalTransform.getInverse(); + else + m_MouseDownParentGlobalTransformInverse = QT3DSMat44::createIdentity(); + } + QT3DSMat44 theGlobalTransform = m_MouseDownNode.m_GlobalTransform; + QT3DSMat44 theNewLocalTransform = + m_MouseDownParentGlobalTransformInverse.getValue() * theGlobalTransform; + QT3DSVec3 theOldPos = theNewLocalTransform.column3.getXYZ(); + theOldPos.z *= -1; + + theGlobalTransform.column3 += QT3DSVec4(inDiff, 0.0f); + theNewLocalTransform = m_MouseDownParentGlobalTransformInverse.getValue() * theGlobalTransform; + QT3DSVec3 thePos = theNewLocalTransform.column3.getXYZ(); + thePos.z *= -1; + + QT3DSVec3 theDiff = thePos - theOldPos; + + SetPosition(m_MouseDownNode.m_Position + theDiff, inEditor); +} + +void STranslation::TranslateSelectedInstanceAlongCameraDirection( + CPt inOriginalCoords, CPt inMouseCoords, CUpdateableDocumentEditor &inEditor) +{ + SNode *theNode = GetSelectedNode(); + if (theNode == nullptr) + return; + SCamera *theCamera = m_UICContext.GetRenderer().GetCameraForNode(*theNode); + if (theCamera == nullptr) + return; + QT3DSF32 theYDistance = QT3DSF32(inMouseCoords.y - inOriginalCoords.y); + if (fabs(theYDistance) == 0) + return; + + QT3DSF32 theMouseMultiplier = 1.0f / 2.0f; + QT3DSF32 theDistanceMultiplier = 1.0f + theYDistance * theMouseMultiplier; + QT3DSVec3 theCameraDir = m_MouseDownCamera.GetDirection(); + + QT3DSVec3 theDiff = theCameraDir * theDistanceMultiplier; + ApplyPositionalChange(theDiff, *theNode, inEditor); +} + +void STranslation::TranslateSelectedInstance(CPt inOriginalCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor, bool inLockToAxis) +{ + SNode *theNode = GetSelectedNode(); + if (theNode == nullptr) + return; + uic::render::IUICRenderer &theRenderer(m_UICContext.GetRenderer()); + + QT3DSF32 theXDistance = QT3DSF32(inMouseCoords.x - inOriginalCoords.x); + QT3DSF32 theYDistance = QT3DSF32(inMouseCoords.y - inOriginalCoords.y); + if (fabs(theXDistance) == 0 && fabs(theYDistance) == 0) + return; + + CheckLockToAxis(theXDistance, theYDistance, inLockToAxis); + + inMouseCoords.x = inOriginalCoords.x + (long)theXDistance; + inMouseCoords.y = inOriginalCoords.y + (long)theYDistance; + QT3DSVec3 theNodeGlobal = m_MouseDownNode.GetGlobalPos(); + QT3DSVec3 theOriginalPos = theRenderer.UnprojectToPosition( + *theNode, theNodeGlobal, QT3DSVec2((QT3DSF32)inOriginalCoords.x, (QT3DSF32)inOriginalCoords.y)); + QT3DSVec3 theNewPos = theRenderer.UnprojectToPosition( + *theNode, theNodeGlobal, QT3DSVec2((QT3DSF32)inMouseCoords.x, (QT3DSF32)inMouseCoords.y)); + + QT3DSVec3 theDiff = theNewPos - theOriginalPos; + ApplyPositionalChange(theDiff, *theNode, inEditor); +} + +void STranslation::ScaleSelectedInstanceZ(CPt inOriginalCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor) +{ + SNode *theNode = GetSelectedNode(); + if (theNode == nullptr) + return; + + // Scale scales uniformly and responds to mouse Y only. + QT3DSF32 theYDistance = (QT3DSF32)inMouseCoords.y - (QT3DSF32)inOriginalCoords.y; + if (fabs(theYDistance) == 0) + return; + + QT3DSF32 theMouseMultiplier = 1.0f / 40.0f; + QT3DSF32 theScaleMultiplier = 1.0f + theYDistance * theMouseMultiplier; + + SetScale(QT3DSVec3(m_MouseDownNode.m_Scale.x, m_MouseDownNode.m_Scale.y, + m_MouseDownNode.m_Scale.z * theScaleMultiplier), + inEditor); +} + +void STranslation::ScaleSelectedInstance(CPt inOriginalCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor) +{ + SNode *theNode = GetSelectedNode(); + if (theNode == nullptr) + return; + + // Scale scales uniformly and responds to mouse Y only. + QT3DSF32 theYDistance = (QT3DSF32)inMouseCoords.y - (QT3DSF32)inOriginalCoords.y; + if (fabs(theYDistance) == 0) + return; + + QT3DSF32 theMouseMultiplier = 1.0f / 40.0f; + QT3DSF32 theScaleMultiplier = 1.0f + theYDistance * theMouseMultiplier; + + SetScale(m_MouseDownNode.m_Scale * theScaleMultiplier, inEditor); +} + +void STranslation::CalculateNodeGlobalRotation(SNode &inNode) +{ + if (inNode.m_Parent) + CalculateNodeGlobalRotation(*inNode.m_Parent); + if (m_MouseDownParentRotationInverse.isEmpty()) { + m_MouseDownParentRotationInverse = QT3DSMat33::createIdentity(); + m_MouseDownGlobalRotation = QT3DSMat33::createIdentity(); + } + + QT3DSMat44 localRotation; + inNode.CalculateRotationMatrix(localRotation); + if (inNode.m_Flags.IsLeftHanded()) + SNode::FlipCoordinateSystem(localRotation); + QT3DSMat33 theRotation; + SNode::GetMatrixUpper3x3(theRotation, localRotation); + + m_MouseDownParentRotationInverse = m_MouseDownGlobalRotation; + m_MouseDownGlobalRotation = m_MouseDownGlobalRotation.getValue() * theRotation; +} + +void STranslation::ApplyRotationToSelectedInstance(const QT3DSQuat &inFinalRotation, SNode &inNode, + CUpdateableDocumentEditor &inEditor, + bool inIsMouseRelative) +{ + if (m_MouseDownParentRotationInverse.isEmpty()) { + CalculateNodeGlobalRotation(inNode); + m_MouseDownParentRotationInverse = m_MouseDownParentRotationInverse->getInverse(); + } + QT3DSMat33 theRotationMatrix(inFinalRotation); + + QT3DSMat33 theFinalGlobal = theRotationMatrix * m_MouseDownGlobalRotation.getValue(); + QT3DSMat33 theLocalGlobal = m_MouseDownParentRotationInverse.getValue() * theFinalGlobal; + QT3DSVec3 theRotations = inNode.GetRotationVectorFromRotationMatrix(theLocalGlobal); + theRotations = uic::render::SRotationHelper::ToNearestAngle(inNode.m_Rotation, theRotations, + inNode.m_RotationOrder); + SetRotation(theRotations, inEditor); + // Trackball rotation is relative to the previous mouse position. + // Rotation manipulator rotation is relative to only the original mouse down position + // so inIsMouseRelative is false for rotations that are relative to the original mouse down + // position. + if (inIsMouseRelative) + m_MouseDownGlobalRotation = theFinalGlobal; +} + +void STranslation::RotateSelectedInstanceAboutCameraDirectionVector( + CPt inPreviousMouseCoords, CPt inMouseCoords, CUpdateableDocumentEditor &inEditor) +{ + SNode *theNode = GetSelectedNode(); + if (theNode == nullptr) + return; + SCamera *theCamera = m_UICContext.GetRenderer().GetCameraForNode(*theNode); + if (theCamera == nullptr) + return; + + QT3DSVec3 theDirection = m_MouseDownCamera.GetDirection(); + QT3DSF32 theYDistance = (QT3DSF32)inMouseCoords.y - (QT3DSF32)inPreviousMouseCoords.y; + QT3DSQuat theYRotation(-1.0f * theYDistance * g_RotationScaleFactor, theDirection); + + ApplyRotationToSelectedInstance(theYRotation, *theNode, inEditor); +} + +// This method never feels right to me. It is difficult to apply it to a single axis (of course for +// that +// you can use the inspector palette). +void STranslation::RotateSelectedInstance(CPt inOriginalCoords, CPt inPreviousCoords, + CPt inMouseCoords, CUpdateableDocumentEditor &inEditor, + bool inLockToAxis) +{ + SNode *theNode = GetSelectedNode(); + if (theNode == nullptr) + return; + SCamera *theCamera = m_UICContext.GetRenderer().GetCameraForNode(*theNode); + if (theCamera == nullptr) + return; + // We want to do a similar translation to what we did below but we need to calculate the + // parent's + // global rotation without scale included. + + QT3DSF32 theXDistance = (QT3DSF32)inMouseCoords.x - (QT3DSF32)inPreviousCoords.x; + QT3DSF32 theYDistance = (QT3DSF32)inMouseCoords.y - (QT3DSF32)inPreviousCoords.y; + bool xIsZero = fabs(theXDistance) < .001f; + bool yIsZero = fabs(theYDistance) < .001f; + if (xIsZero && yIsZero) + return; + + if (inLockToAxis) { + QT3DSF32 originalDistX = (QT3DSF32)inMouseCoords.x - (QT3DSF32)inOriginalCoords.x; + QT3DSF32 originalDistY = (QT3DSF32)inMouseCoords.y - (QT3DSF32)inOriginalCoords.y; + if (inLockToAxis) { + if (fabs(originalDistX) > fabs(originalDistY)) + theYDistance = 0; + else + theXDistance = 0; + } + } + + QT3DSVec3 theXAxis = m_MouseDownCamera.m_GlobalTransform.column0.getXYZ(); + QT3DSVec3 theYAxis = m_MouseDownCamera.m_GlobalTransform.column1.getXYZ(); + + QT3DSVec3 theFinalAxis = theXDistance * theYAxis + theYDistance * theXAxis; + QT3DSF32 theTotalDistance = theFinalAxis.normalize(); + QT3DSQuat theRotation(theTotalDistance * g_RotationScaleFactor / 2.0f, theFinalAxis); + + ApplyRotationToSelectedInstance(theRotation, *theNode, inEditor); +} + +inline void NiceAdd(QT3DSF32 &ioValue, QT3DSF32 inIncrement) +{ + QT3DSF32 temp = ioValue + inIncrement; + // Round to nearest .5 + QT3DSF32 sign = temp >= 0 ? 1.0f : -1.0f; + QT3DSU32 largerValue = (QT3DSU32)(fabs(temp * 10.0f)); + + QT3DSU32 leftover = largerValue % 10; + // Round down to zero + largerValue -= leftover; + if (leftover < 2) + leftover = 0; + else if (leftover > 7) { + leftover = 0; + largerValue += 10; + } else + leftover = 5; + largerValue += leftover; + + ioValue = sign * (QT3DSF32)largerValue / 10.0f; +} + +static inline QT3DSVec3 GetAxis(QT3DSU32 inIndex, QT3DSMat33 &inMatrix) +{ + QT3DSVec3 retval(0, 0, 0); + switch (inIndex) { + case 0: + retval = inMatrix.column0; + break; + case 1: + retval = inMatrix.column1; + break; + case 2: + retval = inMatrix.column2; + break; + default: + QT3DS_ASSERT(false); + break; + } + retval.normalize(); + return retval; +} + +inline Option GetScaleAlongAxis(const QT3DSVec3 &inAxis, const QT3DSVec3 &inObjToOriginal, + const QT3DSVec3 &inObjToCurrent) +{ + QT3DSF32 lhs = inAxis.dot(inObjToCurrent); + QT3DSF32 rhs = inAxis.dot(inObjToOriginal); + if (fabs(rhs) > .001f) + return lhs / rhs; + return Empty(); +} + +// Make a nice rotation from the incoming rotation +static inline QT3DSF32 MakeNiceRotation(QT3DSF32 inAngle) +{ + TODEG(inAngle); + inAngle *= 10.0f; + QT3DSF32 sign = inAngle > 0.0f ? 1.0f : -1.0f; + // Attempt to ensure angle is prtty clean + QT3DSU32 clampedAngle = (QT3DSU32)(fabs(inAngle) + .5f); + QT3DSU32 leftover = clampedAngle % 10; + clampedAngle -= leftover; + if (leftover <= 2) + leftover = 0; + else if (leftover <= 7) + leftover = 5; + else + leftover = 10; + clampedAngle += leftover; + QT3DSF32 retval = (QT3DSF32)clampedAngle; + retval = (retval * sign) / 10.0f; + TORAD(retval); + return retval; +} + +static inline QT3DSF32 ShortestAngleDifference(QT3DSF32 inCumulative, QT3DSF32 inNewTotal) +{ + QT3DSF32 diff = uic::render::SRotationHelper::ToMinimalAngle(inNewTotal - inCumulative); + return inCumulative + diff; +} + +Option +STranslation::PrepareWidgetDrag(uic::widgets::StudioWidgetComponentIds::Enum inComponentId, + uic::widgets::StudioWidgetTypes::Enum inWidgetId, + uic::render::RenderWidgetModes::Enum inWidgetMode, SNode &inNode, + CPt inOriginalCoords, CPt inPreviousMouseCoords, CPt inMouseCoords) +{ + SDragPreparationResult retval; + retval.m_ComponentId = inComponentId; + retval.m_WidgetType = inWidgetId; + retval.m_WidgetMode = inWidgetMode; + uic::render::IUICRenderer &theRenderer(m_UICContext.GetRenderer()); + retval.m_Renderer = &theRenderer; + retval.m_Node = &inNode; + retval.m_Layer = GetLayerForNode(inNode); + retval.m_Camera = theRenderer.GetCameraForNode(inNode); + uic::render::SWindowDimensions theUnsignedDimensions(m_UICContext.GetWindowDimensions()); + QT3DSVec2 theWindowDimensions((QT3DSF32)theUnsignedDimensions.m_Width, + (QT3DSF32)theUnsignedDimensions.m_Height); + if (retval.m_Camera == nullptr || retval.m_Layer == nullptr) + return Empty(); + + SCamera &theCamera(*retval.m_Camera); + SLayer &theLayer(*retval.m_Layer); + QT3DSVec2 theLayerOriginalCoords = m_UICContext.GetRenderer().GetLayerMouseCoords( + *retval.m_Layer, QT3DSVec2((QT3DSF32)inOriginalCoords.x, (QT3DSF32)inOriginalCoords.y), + theWindowDimensions, true); + + QT3DSVec2 theLayerMouseCoords = m_UICContext.GetRenderer().GetLayerMouseCoords( + *retval.m_Layer, QT3DSVec2((QT3DSF32)inMouseCoords.x, (QT3DSF32)inMouseCoords.y), + theWindowDimensions, true); + + QT3DSVec2 thePreviousLayerMouseCoords = m_UICContext.GetRenderer().GetLayerMouseCoords( + *retval.m_Layer, QT3DSVec2((QT3DSF32)inPreviousMouseCoords.x, (QT3DSF32)inPreviousMouseCoords.y), + theWindowDimensions, true); + QT3DSMat44 theGlobalTransform(QT3DSMat44::createIdentity()); + if (inWidgetMode == uic::render::RenderWidgetModes::Local) { + theGlobalTransform = m_MouseDownNode.m_GlobalTransform; + } + retval.m_GlobalTransform = theGlobalTransform; + QT3DSMat33 theNormalMat(theGlobalTransform.column0.getXYZ(), theGlobalTransform.column1.getXYZ(), + theGlobalTransform.column2.getXYZ()); + theNormalMat = theNormalMat.getInverse().getTranspose(); + retval.m_NormalMatrix = theNormalMat; + qt3ds::render::NVRenderRectF theLayerRect(theRenderer.GetLayerRect(theLayer)); + SRay theOriginalRay = + theCamera.Unproject(theLayerOriginalCoords, theLayerRect, theWindowDimensions); + SRay theCurrentRay = + theCamera.Unproject(theLayerMouseCoords, theLayerRect, theWindowDimensions); + SRay thePreviousRay = + theCamera.Unproject(thePreviousLayerMouseCoords, theLayerRect, theWindowDimensions); + retval.m_OriginalRay = theOriginalRay; + retval.m_CurrentRay = theCurrentRay; + retval.m_PreviousRay = thePreviousRay; + QT3DSVec3 theAxis; + QT3DSVec3 thePlaneNormal; + bool isPlane = false; + QT3DSVec3 globalPos = inNode.GetGlobalPivot(); + QT3DSVec3 camGlobalPos = theCamera.GetGlobalPos(); + QT3DSVec3 theCamDirection; + retval.m_GlobalPos = globalPos; + retval.m_CameraGlobalPos = camGlobalPos; + if (theCamera.m_Flags.IsOrthographic()) + theCamDirection = theCamera.GetDirection(); + else { + theCamDirection = globalPos - camGlobalPos; + // The normal will be normalized below. + } + theCamDirection.normalize(); + retval.m_CameraDirection = theCamDirection; + retval.m_AxisIndex = 0; + switch (inComponentId) { + default: + QT3DS_ASSERT(false); + break; + case uic::widgets::StudioWidgetComponentIds::XAxis: + theAxis = QT3DSVec3(1, 0, 0); + break; + case uic::widgets::StudioWidgetComponentIds::YAxis: + theAxis = QT3DSVec3(0, 1, 0); + retval.m_AxisIndex = 1; + break; + case uic::widgets::StudioWidgetComponentIds::ZAxis: + theAxis = QT3DSVec3(0, 0, -1); + retval.m_AxisIndex = 2; + break; + case uic::widgets::StudioWidgetComponentIds::XPlane: + thePlaneNormal = QT3DSVec3(1, 0, 0); + isPlane = true; + break; + case uic::widgets::StudioWidgetComponentIds::YPlane: + thePlaneNormal = QT3DSVec3(0, 1, 0); + isPlane = true; + break; + case uic::widgets::StudioWidgetComponentIds::ZPlane: + thePlaneNormal = QT3DSVec3(0, 0, -1); + isPlane = true; + break; + case uic::widgets::StudioWidgetComponentIds::CameraPlane: { + isPlane = true; + thePlaneNormal = theCamDirection; + } break; + } + retval.m_IsPlane = isPlane; + if (inWidgetId == uic::widgets::StudioWidgetTypes::Rotation) { + if (isPlane == false) { + theAxis = theNormalMat.transform(theAxis); + theAxis.normalize(); + thePlaneNormal = theAxis; + retval.m_Plane = qt3ds::NVPlane(thePlaneNormal, -1.0f * thePlaneNormal.dot(globalPos)); + } else { + if (inComponentId != uic::widgets::StudioWidgetComponentIds::CameraPlane) { + thePlaneNormal = theNormalMat.transform(thePlaneNormal); + } + thePlaneNormal.normalize(); + retval.m_Plane = qt3ds::NVPlane(thePlaneNormal, -1.0f * (thePlaneNormal.dot(globalPos))); + } + } else { + if (isPlane == false) { + theAxis = theNormalMat.transform(theAxis); + theAxis.normalize(); + QT3DSVec3 theCameraToObj = globalPos - camGlobalPos; + QT3DSVec3 theTemp = theAxis.cross(theOriginalRay.m_Direction); + // Then the axis is parallel to the camera, we can't drag meaningfullly + if (theTemp.magnitudeSquared() < .05f) { + // Attempt to find a better axis by moving the object back towards the camera. + QT3DSF32 theSign = theCameraToObj.dot(theCamDirection) > 0.0 ? -1.0f : 1.0f; + QT3DSF32 theDistance = theCameraToObj.dot(theCamDirection); + QT3DSVec3 thePoint = globalPos + (theDistance * theSign) * theAxis; + QT3DSVec3 theNewDir = thePoint - camGlobalPos; + theNewDir.normalize(); + theTemp = theAxis.cross(theNewDir); + // Attempt again to find a better cross + if (theTemp.magnitudeSquared() < .05f) + return Empty(); + } + thePlaneNormal = theTemp.cross(theAxis); + thePlaneNormal.normalize(); + retval.m_Plane = qt3ds::NVPlane(thePlaneNormal, -1.0f * thePlaneNormal.dot(globalPos)); + } else { + thePlaneNormal = theNormalMat.transform(thePlaneNormal); + thePlaneNormal.normalize(); + retval.m_Plane = qt3ds::NVPlane(thePlaneNormal, -1.0f * (thePlaneNormal.dot(globalPos))); + } + } + retval.m_Axis = theAxis; + retval.m_OriginalPlaneCoords = theOriginalRay.Intersect(retval.m_Plane); + retval.m_CurrentPlaneCoords = theCurrentRay.Intersect(retval.m_Plane); + retval.m_PreviousPlaneCoords = thePreviousRay.Intersect(retval.m_Plane); + return retval; +} + +void STranslation::PerformWidgetDrag(int inWidgetSubComponent, CPt inOriginalCoords, + CPt inPreviousMouseCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor) +{ + if (inWidgetSubComponent == 0 || m_LastRenderedWidget == nullptr) { + QT3DS_ASSERT(false); + return; + } + Option thePrepResult(PrepareWidgetDrag( + static_cast(inWidgetSubComponent), + m_LastRenderedWidget->GetWidgetType(), m_LastRenderedWidget->GetRenderWidgetMode(), + m_LastRenderedWidget->GetNode(), inOriginalCoords, inPreviousMouseCoords, inMouseCoords)); + if (!thePrepResult.hasValue()) + return; + + Option theOriginalPlaneCoords(thePrepResult->m_OriginalPlaneCoords); + Option theCurrentPlaneCoords(thePrepResult->m_CurrentPlaneCoords); + Option thePreviousPlaneCoords(thePrepResult->m_PreviousPlaneCoords); + QT3DSVec3 globalPos(thePrepResult->m_GlobalPos); + bool isPlane(thePrepResult->m_IsPlane); + QT3DSVec3 theAxis(thePrepResult->m_Axis); + QT3DSU32 axisIndex(thePrepResult->m_AxisIndex); + SNode *theNode(thePrepResult->m_Node); + SRay theCurrentRay(thePrepResult->m_CurrentRay); + SRay theOriginalRay(thePrepResult->m_OriginalRay); + QT3DSVec3 thePlaneNormal(thePrepResult->m_Plane.n); + QT3DSVec3 theCamDirection(thePrepResult->m_CameraDirection); + QT3DSVec3 camGlobalPos(thePrepResult->m_CameraGlobalPos); + + switch (m_LastRenderedWidget->GetWidgetType()) { + default: + QT3DS_ASSERT(false); + return; + case uic::widgets::StudioWidgetTypes::Scale: { + if (theOriginalPlaneCoords.hasValue() && theCurrentPlaneCoords.hasValue()) { + QT3DSVec3 objToOriginal = globalPos - *theOriginalPlaneCoords; + QT3DSVec3 objToCurrent = globalPos - *theCurrentPlaneCoords; + QT3DSVec3 theScaleMultiplier(1, 1, 1); + if (!isPlane) { + // Ensure that we only have a scale vector in the direction of the axis. + objToOriginal = theAxis * (theAxis.dot(objToOriginal)); + objToCurrent = theAxis * (theAxis.dot(objToCurrent)); + QT3DSF32 objToOriginalDot = theAxis.dot(objToOriginal); + if (fabs(objToOriginalDot) > .001f) + theScaleMultiplier[axisIndex] = + theAxis.dot(objToCurrent) / theAxis.dot(objToOriginal); + else + theScaleMultiplier[axisIndex] = 0.0f; + } + + QT3DSMat33 theNodeAxisMatrix(theNode->m_GlobalTransform.column0.getXYZ(), + theNode->m_GlobalTransform.column1.getXYZ(), + theNode->m_GlobalTransform.column2.getXYZ()); + theNodeAxisMatrix = theNodeAxisMatrix.getInverse().getTranspose(); + QT3DSVec3 &theLocalXAxis(theNodeAxisMatrix.column0); + QT3DSVec3 &theLocalYAxis(theNodeAxisMatrix.column1); + QT3DSVec3 &theLocalZAxis(theNodeAxisMatrix.column2); + theLocalXAxis.normalize(); + theLocalYAxis.normalize(); + theLocalZAxis.normalize(); + + Option theXScale = GetScaleAlongAxis(theLocalXAxis, objToOriginal, objToCurrent); + Option theYScale = GetScaleAlongAxis(theLocalYAxis, objToOriginal, objToCurrent); + Option theZScale = GetScaleAlongAxis(theLocalZAxis, objToOriginal, objToCurrent); + QT3DSVec3 theScale = m_MouseDownNode.m_Scale; + if (theXScale.isEmpty() && theYScale.isEmpty() && theZScale.isEmpty()) { + theScale = QT3DSVec3(0, 0, 0); + } else { + if (theXScale.hasValue()) + theScale.x *= *theXScale; + if (theYScale.hasValue()) + theScale.y *= *theYScale; + if (theZScale.hasValue()) + theScale.z *= *theZScale; + } + m_LastRenderedWidget->SetAxisScale(theScaleMultiplier); + SetScale(theScale, inEditor); + } + } break; + case uic::widgets::StudioWidgetTypes::Rotation: { + QT3DSF32 theIntersectionCosine = theOriginalRay.m_Direction.dot(thePlaneNormal); + QT3DSVec3 objToPrevious; + QT3DSVec3 objToCurrent; + /* + long theModifiers = CHotKeys::GetCurrentKeyModifiers(); + if ( theModifiers & CHotKeys::MODIFIER_SHIFT ) + { + DebugBreak(); + } + */ + if (!theOriginalPlaneCoords.hasValue() || !theCurrentPlaneCoords.hasValue()) + return; + if (fabs(theIntersectionCosine) > .08f) { + objToPrevious = globalPos - *theOriginalPlaneCoords; + objToCurrent = globalPos - *theCurrentPlaneCoords; + objToPrevious.normalize(); + QT3DSF32 lineLen = objToCurrent.normalize(); + QT3DSF32 cosAngle = objToPrevious.dot(objToCurrent); + QT3DSVec3 theCrossProd = objToPrevious.cross(objToCurrent); + QT3DSF32 theCrossPlaneDot = theCrossProd.dot(thePlaneNormal); + QT3DSF32 angleSign = theCrossPlaneDot >= 0.0f ? 1.0f : -1.0f; + QT3DSF32 angleRad = acos(cosAngle) * angleSign; + angleRad = MakeNiceRotation(angleRad); + QT3DSQuat theRotation(angleRad, thePlaneNormal); + m_CumulativeRotation = ShortestAngleDifference(m_CumulativeRotation, angleRad); + m_LastRenderedWidget->SetRotationEdges(-1.0f * objToPrevious, thePlaneNormal, + m_CumulativeRotation, lineLen); + ApplyRotationToSelectedInstance(theRotation, *theNode, inEditor, false); + } + // In this case we are viewing the plane of rotation pretty much dead on, so we need to + // assume + // the camera and the object are both in the plane of rotation. In this case we *sort* of + // need to + // do trackball rotation but force it to one plane of rotation. + else { + // Setup a plane 600 units away from the camera and have the gadget run from there. + + // This keeps rotation consistent. + QT3DSVec3 thePlaneSpot = theCamDirection * -600.0f + camGlobalPos; + qt3ds::NVPlane theCameraPlaneAtObject(theCamDirection, + -1.0f * (theCamDirection.dot(thePlaneSpot))); + theCurrentPlaneCoords = theCurrentRay.Intersect(theCameraPlaneAtObject); + theOriginalPlaneCoords = theOriginalRay.Intersect(theCameraPlaneAtObject); + QT3DSVec3 theChangeVector = *theOriginalPlaneCoords - *theCurrentPlaneCoords; + // Remove any component of the change vector that doesn't lie in the plane. + theChangeVector = + theChangeVector - theChangeVector.dot(thePlaneNormal) * thePlaneNormal; + QT3DSF32 theDistance = theChangeVector.normalize(); + // We want about 90* per 200 units in imaginary 600-units-from-camera space. + QT3DSF32 theScaleFactor = 1.0f / 200.0f; + if (thePrepResult->m_Camera->m_Flags.IsOrthographic()) + theScaleFactor = 1.0f / 100.0f; + + QT3DSF32 theDeg = 90.0f * theDistance * theScaleFactor; + // Check the sign of the angle. + QT3DSVec3 theCurrentIsectDir = camGlobalPos - *theCurrentPlaneCoords; + QT3DSVec3 thePreviousIsectDir = camGlobalPos - *theOriginalPlaneCoords; + QT3DSVec3 theCrossProd = theCurrentIsectDir.cross(thePreviousIsectDir); + QT3DSF32 theAngleSign = theCrossProd.dot(thePlaneNormal) > 0.0f ? 1.0f : -1.0f; + theDeg *= theAngleSign; + QT3DSF32 theRad(theDeg); + TORAD(theRad); + theRad = MakeNiceRotation(theRad); + QT3DSQuat theRotation(theRad, thePlaneNormal); + ApplyRotationToSelectedInstance(theRotation, *theNode, inEditor, false); + } + } break; + case uic::widgets::StudioWidgetTypes::Translation: { + if (theOriginalPlaneCoords.hasValue() && theCurrentPlaneCoords.hasValue()) { + QT3DSVec3 theDiff = *theCurrentPlaneCoords - *theOriginalPlaneCoords; + if (isPlane) { + ApplyPositionalChange(theDiff, *theNode, inEditor); + } else { + QT3DSVec3 theMovement = theAxis * theAxis.dot(theDiff); + ApplyPositionalChange(theMovement, *theNode, inEditor); + } + } + } break; + } +} + +static float RoundToNearest(float inValue, float inMin, float inMax, float inRound) +{ + float half = (inMin + inMax) / 2.0f; + inValue -= half; + inValue = inRound * floor(inValue / inRound + .5f); + inValue += half; + inValue -= inMin; + return inValue; +} + +void STranslation::PerformGuideDrag(CUICDMGuideHandle inGuide, CPt inPoint, + CUpdateableDocumentEditor &inEditor) +{ + UICDM::SGuideInfo theInfo = m_Doc.GetDocumentReader().GetGuideInfo(inGuide); + CPt renderSpacePt(inPoint.x, (long)GetViewportDimensions().y - inPoint.y); + switch (theInfo.m_Direction) { + case UICDM::GuideDirections::Horizontal: + theInfo.m_Position = RoundToNearest((float)renderSpacePt.y, (float)m_InnerRect.m_Bottom, + (float)m_InnerRect.m_Top, 10.0f); + break; + case UICDM::GuideDirections::Vertical: + theInfo.m_Position = RoundToNearest((float)renderSpacePt.x, (float)m_InnerRect.m_Left, + (float)m_InnerRect.m_Right, 10.0f); + break; + default: + QT3DS_ASSERT(FALSE); + break; + break; + } + inEditor.EnsureEditor(L"Drag Guide", __FILE__, __LINE__).UpdateGuide(inGuide, theInfo); + inEditor.FireImmediateRefresh(UICDM::CUICDMInstanceHandle()); +} + +void STranslation::CheckGuideInPresentationRect(CUICDMGuideHandle inGuide, + CUpdateableDocumentEditor &inEditor) +{ + UICDM::SGuideInfo theInfo = m_Doc.GetDocumentReader().GetGuideInfo(inGuide); + bool inPresentation = false; + QT3DSF32 presHeight = (QT3DSF32)m_InnerRect.m_Top - (QT3DSF32)m_InnerRect.m_Bottom; + QT3DSF32 presWidth = (QT3DSF32)m_InnerRect.m_Right - (QT3DSF32)m_InnerRect.m_Left; + switch (theInfo.m_Direction) { + case UICDM::GuideDirections::Horizontal: + inPresentation = 0.0f <= theInfo.m_Position && presHeight >= theInfo.m_Position; + break; + case UICDM::GuideDirections::Vertical: + inPresentation = 0.0f <= theInfo.m_Position && presWidth >= theInfo.m_Position; + break; + } + if (!inPresentation) + inEditor.EnsureEditor(L"Delete Guide", __FILE__, __LINE__).DeleteGuide(inGuide); +} + +namespace { + +QT3DSF32 degToRad(const QT3DSF32 a) +{ + return (QT3DSF32)0.01745329251994329547 * a; +} + +/** +\brief Converts radians to degrees. +*/ +QT3DSF32 radToDeg(const QT3DSF32 a) +{ + return (QT3DSF32)57.29577951308232286465 * a; +} +} + +void STranslation::PerformPathDrag(uic::studio::SPathPick &inPathPick, CPt inOriginalCoords, + CPt inPreviousMouseCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor) +{ + Option thePrepResult(PrepareWidgetDrag( + uic::widgets::StudioWidgetComponentIds::ZPlane, + uic::widgets::StudioWidgetTypes::Translation, uic::render::RenderWidgetModes::Local, + m_PathWidget->GetNode(), inOriginalCoords, inPreviousMouseCoords, inMouseCoords)); + if (!thePrepResult.hasValue()) + return; + + Option theOriginalPlaneCoords(thePrepResult->m_OriginalPlaneCoords); + Option theCurrentPlaneCoords(thePrepResult->m_CurrentPlaneCoords); + Option thePreviousPlaneCoords(thePrepResult->m_PreviousPlaneCoords); + if (theOriginalPlaneCoords.hasValue() && theCurrentPlaneCoords.hasValue()) { + QT3DSVec3 theGlobalDiff = *theCurrentPlaneCoords - *theOriginalPlaneCoords; + QT3DSMat44 theGlobalInverse = thePrepResult->m_GlobalTransform.getInverse(); + QT3DSVec3 theCurrentPos = theGlobalInverse.transform(*theCurrentPlaneCoords); + QT3DSVec3 theOldPos = theGlobalInverse.transform(*theOriginalPlaneCoords); + QT3DSVec3 theDiff = theCurrentPos - theOldPos; + // Now find the anchor point; nontrivial. + SPathTranslator *theTranslator = + reinterpret_cast(thePrepResult->m_Node->m_UserData.m_UserData); + UICDM::CUICDMInstanceHandle thePathHandle = theTranslator->GetInstanceHandle(); + UICDM::CUICDMInstanceHandle theAnchorHandle = GetAnchorPoint(inPathPick); + + if (theAnchorHandle.Valid()) { + UICDM::CUICDMPropertyHandle thePosProperty = + m_ObjectDefinitions.m_PathAnchorPoint.m_Position.m_Property; + UICDM::CUICDMPropertyHandle theAngleProperty = + m_ObjectDefinitions.m_PathAnchorPoint.m_IncomingAngle.m_Property; + UICDM::CUICDMPropertyHandle theIncomingDistanceProperty = + m_ObjectDefinitions.m_PathAnchorPoint.m_IncomingDistance.m_Property; + UICDM::CUICDMPropertyHandle theOutgoingDistanceProperty = + m_ObjectDefinitions.m_PathAnchorPoint.m_OutgoingDistance.m_Property; + + IDocumentReader &theReader(m_Doc.GetDocumentReader()); + SFloat2 anchorPos = + *theReader.GetTypedInstancePropertyValue(theAnchorHandle, thePosProperty); + QT3DSVec2 anchorPosVec = QT3DSVec2(anchorPos[0], anchorPos[1]); + if (m_LastPathDragValue.hasValue() == false) { + SPathAnchorDragInitialValue initialValue; + initialValue.m_Position = anchorPosVec; + initialValue.m_IncomingAngle = theReader.GetTypedInstancePropertyValue( + theAnchorHandle, theAngleProperty); + initialValue.m_IncomingDistance = theReader.GetTypedInstancePropertyValue( + theAnchorHandle, theIncomingDistanceProperty); + initialValue.m_OutgoingDistance = theReader.GetTypedInstancePropertyValue( + theAnchorHandle, theOutgoingDistanceProperty); + m_LastPathDragValue = initialValue; + } + SPathAnchorDragInitialValue &lastValue(*m_LastPathDragValue); + QT3DSVec2 theCurrentValue; + switch (inPathPick.m_Property) { + case SPathPick::Anchor: + theCurrentValue = lastValue.m_Position; + break; + case SPathPick::IncomingControl: + theCurrentValue = uic::render::IPathManagerCore::GetControlPointFromAngleDistance( + lastValue.m_Position, lastValue.m_IncomingAngle, lastValue.m_IncomingDistance); + break; + case SPathPick::OutgoingControl: + theCurrentValue = uic::render::IPathManagerCore::GetControlPointFromAngleDistance( + lastValue.m_Position, lastValue.m_IncomingAngle + 180.0f, + lastValue.m_OutgoingDistance); + break; + default: + QT3DS_ASSERT(false); + break; + } + theCurrentValue[0] += theDiff.x; + theCurrentValue[1] += theDiff.y; + Q3DStudio::IDocumentEditor &theEditor = + inEditor.EnsureEditor(L"Anchor Point Drag", __FILE__, __LINE__); + switch (inPathPick.m_Property) { + case SPathPick::Anchor: + theEditor.SetInstancePropertyValue(theAnchorHandle, thePosProperty, + SFloat2(theCurrentValue.x, theCurrentValue.y)); + break; + case SPathPick::IncomingControl: { + QT3DSVec2 angleDistance = + uic::render::IPathManagerCore::GetAngleDistanceFromControlPoint( + anchorPosVec, theCurrentValue); + float angleDiff = angleDistance.x - lastValue.m_IncomingAngle; + float minimalDiff = + radToDeg(uic::render::SRotationHelper::ToMinimalAngle(degToRad(angleDiff))); + float newAngle = lastValue.m_IncomingAngle + minimalDiff; + theEditor.SetInstancePropertyValue(theAnchorHandle, theAngleProperty, newAngle); + theEditor.SetInstancePropertyValue(theAnchorHandle, theIncomingDistanceProperty, + angleDistance.y); + } break; + case SPathPick::OutgoingControl: { + QT3DSVec2 angleDistance = + uic::render::IPathManagerCore::GetAngleDistanceFromControlPoint( + anchorPosVec, theCurrentValue); + angleDistance.x += 180.0f; + float angleDiff = angleDistance.x - lastValue.m_IncomingAngle; + float minimalDiff = + radToDeg(uic::render::SRotationHelper::ToMinimalAngle(degToRad(angleDiff))); + float newAngle = lastValue.m_IncomingAngle + minimalDiff; + theEditor.SetInstancePropertyValue(theAnchorHandle, theAngleProperty, newAngle); + theEditor.SetInstancePropertyValue(theAnchorHandle, theOutgoingDistanceProperty, + angleDistance.y); + } break; + } + + inEditor.FireImmediateRefresh(m_AssetGraph.GetParent(theAnchorHandle)); + } + } +} + +// Pulled directly from old studio's Node.cpp. +void STranslation::OnNudge(ENudgeDirection inDirection, int inToolmode, int inFlags, + CUpdateableDocumentEditor &inEditor) +{ + Q_UNUSED(inFlags); + SNode *theSelectedNode = GetSelectedNode(); + if (theSelectedNode == nullptr) + return; + ; + + // Increment the key press count + m_KeyRepeat++; + + // Increment the acceleration for every 5 key presses + float theAcceleration = static_cast(qt3ds::foundation::floor(m_KeyRepeat / 5.0)) + 1.0f; + + CUICDMPropertyHandle thePropertyHandle; + SFloat3 theValue; + const wchar_t *theCommandName = L""; + UICDM::CUICDMInstanceHandle theInstanceHandle = m_Doc.GetSelectedInstance(); + CDispatchDataModelImmediateScope __dispatchScope(*m_Doc.GetCore()->GetDispatch(), + theInstanceHandle); + // See what tool mode we are in + switch (inToolmode) { + // We want to nudge the position vector + case STUDIO_TOOLMODE_MOVE: + thePropertyHandle = m_ObjectDefinitions.m_Node.m_Position; + theValue = + m_Reader.GetTypedInstancePropertyValue(theInstanceHandle, thePropertyHandle); + theCommandName = L"Set Position"; + break; + + // We want to nudge the rotation vector + case STUDIO_TOOLMODE_ROTATE: + thePropertyHandle = m_ObjectDefinitions.m_Node.m_Rotation; + theValue = m_Reader.GetTypedInstancePropertyValue(theInstanceHandle, + thePropertyHandle); + theCommandName = L"Set Rotation"; + break; + + // We want to nudge the scale vector + case STUDIO_TOOLMODE_SCALE: + thePropertyHandle = m_ObjectDefinitions.m_Node.m_Scale; + theValue = m_Reader.GetTypedInstancePropertyValue(theInstanceHandle, + thePropertyHandle); + theCommandName = L"Set Scale"; + break; + + // We should always have a tool mode, but just in case, default to position + default: + thePropertyHandle = m_ObjectDefinitions.m_Node.m_Position; + theValue = m_Reader.GetTypedInstancePropertyValue(theInstanceHandle, + thePropertyHandle); + theCommandName = L"Set Position"; + break; + } + + // If we are in rotate mode, we need to switch the x and y values because we want to rotate + // *around* the specified axis + if ((inToolmode) == STUDIO_TOOLMODE_ROTATE) { + // Switch from positive x to negative y + if (inDirection == NUDGE_POS_X) { + inDirection = NUDGE_NEG_Y; + } + // Switch from positive y to negative x + else if (inDirection == NUDGE_POS_Y) { + inDirection = NUDGE_NEG_X; + } + // Switch from negative x to positive y + else if (inDirection == NUDGE_NEG_X) { + inDirection = NUDGE_POS_Y; + } + // Switch from negative y to positive x + else if (inDirection == NUDGE_NEG_Y) { + inDirection = NUDGE_POS_X; + } + } + + float theNudgeAmount = static_cast(CStudioPreferences::GetNudgeAmount()); + + // Now check which value to change (x, y, or z) and whether to increment or decrement + switch (inDirection) { + // Nudge along the positive x-axis + case NUDGE_POS_X: + theValue.m_Floats[0] += (theNudgeAmount * theAcceleration); + break; + + // Nudge along the positive y-axis + case NUDGE_POS_Y: + theValue.m_Floats[1] += (theNudgeAmount * theAcceleration); + break; + + // Nudge along the positive z-axis + case NUDGE_POS_Z: + theValue.m_Floats[2] += (theNudgeAmount * theAcceleration); + break; + + // Nudge along the negative x-axis + case NUDGE_NEG_X: + theValue.m_Floats[0] -= (theNudgeAmount * theAcceleration); + break; + + // Nudge along the negative y-axis + case NUDGE_NEG_Y: + theValue.m_Floats[1] -= (theNudgeAmount * theAcceleration); + break; + + // Nudge along the negative z-axis + case NUDGE_NEG_Z: + theValue.m_Floats[2] -= (theNudgeAmount * theAcceleration); + break; + } + + inEditor.EnsureEditor(theCommandName, __FILE__, __LINE__) + .SetInstancePropertyValue(theInstanceHandle, thePropertyHandle, theValue); +} + +SNode *STranslation::GetEditCameraLayer() +{ + if (m_EditCameraLayerTranslator) + return static_cast(&m_EditCameraLayerTranslator->GetGraphObject()); + return nullptr; +} + +PickTargetAreas::Enum STranslation::GetPickArea(CPt inPoint) +{ + qt3ds::render::NVRenderRectF displayViewport = m_UICContext.GetDisplayViewport(); + QT3DSVec2 thePickPoint((QT3DSF32)inPoint.x, + m_UICContext.GetWindowDimensions().m_Height - (QT3DSF32)inPoint.y); + QT3DSF32 left = displayViewport.m_X; + QT3DSF32 right = displayViewport.m_X + displayViewport.m_Width; + QT3DSF32 top = displayViewport.m_Y + displayViewport.m_Height; + QT3DSF32 bottom = displayViewport.m_Y; + if (thePickPoint.x < left || thePickPoint.x > right || thePickPoint.y < bottom + || thePickPoint.y > top) + return PickTargetAreas::Matte; + return PickTargetAreas::Presentation; +} diff --git a/src/Authoring/Studio/Render/StudioRendererTranslation.h b/src/Authoring/Studio/Render/StudioRendererTranslation.h new file mode 100644 index 00000000..7698d8ec --- /dev/null +++ b/src/Authoring/Studio/Render/StudioRendererTranslation.h @@ -0,0 +1,691 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 UIC_STUDIO_RENDERER_TRANSLATION_H +#define UIC_STUDIO_RENDERER_TRANSLATION_H +#pragma once +#include "StudioRendererImpl.h" +#include "UICRenderLayer.h" +#include "UICRenderer.h" +#include "StudioWidget.h" +#include "render/Qt3DSRenderTexture2D.h" +#include "foundation/AutoDeallocatorAllocator.h" +#include "foundation/FastAllocator.h" +#include "StudioPickValues.h" +#include "UICDMGuides.h" +#include "PathWidget.h" +#include "StudioPreferences.h" + +namespace uic { +namespace studio { + struct SGraphObjectTranslator; + extern QT3DSU32 g_GraphObjectTranslatorTag; + inline void InitializePointerTags(IStringTable &) { g_GraphObjectTranslatorTag = 0x0088BEEF; } +} +} +namespace uic { +namespace render { + template <> + struct SPointerTag + { + static QT3DSU32 GetTag() { return uic::studio::g_GraphObjectTranslatorTag; } + }; +} +} + +namespace uic { +namespace studio { + + typedef std::shared_ptr TSignalConnection; + + struct STranslation; + + struct SGraphObjectTranslator + { + protected: + UICDM::CUICDMInstanceHandle m_InstanceHandle; + + public: + // This will never be null. The reason it is a pointer is because + // alias translators need to switch which graph object they point to + UICDM::CUICDMInstanceHandle m_AliasInstanceHandle; + SGraphObject *m_GraphObject; + QT3DSU32 m_DirtyIndex; + SGraphObjectTranslator(UICDM::CUICDMInstanceHandle inInstance, SGraphObject &inObj) + : m_InstanceHandle(inInstance) + , m_GraphObject(&inObj) + , m_DirtyIndex(QT3DS_MAX_U32) + { + m_GraphObject->m_UserData = uic::render::STaggedPointer(this); + } + // The destructors will not be called at this time for most of the objects + // but they will be released. + virtual ~SGraphObjectTranslator() {} + // Push new data into the UIC render graph. + virtual void PushTranslation(STranslation &inTranslatorContext); + virtual void AfterRenderGraphIsBuilt(STranslation &) {} + virtual void SetActive(bool inActive) = 0; + virtual void ClearChildren() = 0; + virtual void AppendChild(SGraphObject &inChild) = 0; + virtual SGraphObject &GetGraphObject() { return *m_GraphObject; } + virtual SGraphObject &GetNonAliasedGraphObject() { return *m_GraphObject; } + virtual UICDM::CUICDMInstanceHandle GetInstanceHandle() { return m_InstanceHandle; } + virtual UICDM::CUICDMInstanceHandle GetSceneGraphInstanceHandle() + { + return m_InstanceHandle; + } + virtual UICDM::CUICDMInstanceHandle GetPossiblyAliasedInstanceHandle() + { + if (m_AliasInstanceHandle.Valid()) + return m_AliasInstanceHandle; + return GetInstanceHandle(); + } + }; + + struct STranslatorGetDirty + { + QT3DSU32 operator()(const SGraphObjectTranslator &inTrans) const + { + return inTrans.m_DirtyIndex; + } + }; + struct STranslatorSetDirty + { + void operator()(SGraphObjectTranslator &inTrans, QT3DSU32 idx) const + { + inTrans.m_DirtyIndex = idx; + } + }; + + typedef InvasiveSet + TTranslatorDirtySet; + + struct TranslationSelectMode + { + enum Enum { + Group = 0, + Single = 1, + NestedComponentSingle, + }; + }; + + struct EditCameraTypes + { + enum Enum { + SceneCamera = 0, + Perspective, + Orthographic, + Directional, + }; + }; + + const QT3DSF32 g_EditCameraFOV = 45.0f; + const QT3DSF32 g_RotationScaleFactor = 2 * M_PI / 180.0f; + + struct SEditCameraPersistentInformation + { + QT3DSVec3 m_Position; + QT3DSVec3 m_Direction; + QT3DSF32 m_ViewRadius; + EditCameraTypes::Enum m_CameraType; + QT3DSQuat m_Rotation; + SEditCameraPersistentInformation() + : m_Position(0, 0, 0) + , m_Direction(0, 0, 0) + , m_ViewRadius(600) + , m_CameraType(EditCameraTypes::Perspective) + , m_Rotation(QT3DSQuat::createIdentity()) + { + } + + void ApplyToCamera(SCamera &inCamera, QT3DSVec2 inViewport) + { + // Setup shared default values. + inCamera.m_ClipFar = 2000000.0f; + inCamera.m_ClipNear = 1.0f; + if (m_CameraType == EditCameraTypes::Perspective) { + inCamera.m_FOV = g_EditCameraFOV; + TORAD(inCamera.m_FOV); + inCamera.m_Flags.SetOrthographic(false); + } else + inCamera.m_Flags.SetOrthographic(true); + + QT3DSVec3 theDirection = m_Direction; + theDirection.normalize(); + + // The goal is to setup a global transform that + QT3DSMat44 thePivotMatrix = QT3DSMat44::createIdentity(); + thePivotMatrix.column3.x = m_Position.x; + thePivotMatrix.column3.y = m_Position.y; + thePivotMatrix.column3.z = m_Position.z; + QT3DSMat44 theGlobalTransform = thePivotMatrix; + + QT3DSVec3 theUpDir(QT3DSVec3(0, 1, 0)); + QT3DSF32 theTestLen = theDirection.cross(theUpDir).magnitudeSquared(); + if (theTestLen < .01f) + theUpDir = QT3DSVec3(0, 0, 1) * theDirection.dot(QT3DSVec3(0, 1, 0)); + theUpDir.normalize(); + QT3DSMat33 theLookAtMatrix = inCamera.GetLookAtMatrix(theUpDir, theDirection); + QT3DSMat33 theFinalMatrix = theLookAtMatrix * QT3DSMat33(m_Rotation); + QT3DSMat44 theRotationTransform = QT3DSMat44(theFinalMatrix.column0, theFinalMatrix.column1, + theFinalMatrix.column2, QT3DSVec3(0, 0, 0)); + + // The view radius dictates the zoom. + QT3DSF32 theZoom = 1.0f; + if (inCamera.m_Flags.IsOrthographic()) { + QT3DSF32 theViewport = NVMin(inViewport.x, inViewport.y); + theZoom = (m_ViewRadius * 2.0f) / theViewport; + } else { + // We know the hypotenuse is 600. + // So if we want to zoom the scene, we do this. + theZoom = m_ViewRadius / (sinf(inCamera.m_FOV / 2.0f) * 600.f); + } + QT3DSMat44 theScaleMatrix = QT3DSMat44(QT3DSVec4(theZoom, theZoom, theZoom, 1)); + QT3DSMat44 thePositionMatrix = QT3DSMat44::createIdentity(); + thePositionMatrix.column3.x = m_Position.x; + thePositionMatrix.column3.y = m_Position.y; + thePositionMatrix.column3.z = m_Position.z + 600; + theGlobalTransform = theGlobalTransform * theRotationTransform; + theGlobalTransform = theGlobalTransform * theScaleMatrix; + theGlobalTransform = theGlobalTransform * thePivotMatrix.getInverse(); + theGlobalTransform = theGlobalTransform * thePositionMatrix; + // This works because the camera has no hierarchy. + inCamera.m_LocalTransform = theGlobalTransform; + inCamera.m_Flags.SetTransformDirty(false); + inCamera.MarkDirty(uic::render::NodeTransformDirtyFlag::TransformNotDirty); + } + + bool IsOrthographic() const { return m_CameraType != EditCameraTypes::Perspective; } + + bool SupportsRotation() const { return m_CameraType != EditCameraTypes::Directional; } + }; + struct MovementTypes + { + enum Enum { + Unknown = 0, + Translate, + TranslateAlongCameraDirection, + Scale, + ScaleZ, + Rotation, + RotationAboutCameraDirection, + }; + }; + + struct SEditCameraLayerTranslator; + struct SZoomRender + { + CPt m_Point; + uic::render::SLayer *m_Layer; + SZoomRender(CPt inPoint, uic::render::SLayer *inLayer) + : m_Point(inPoint) + , m_Layer(inLayer) + { + } + SZoomRender() + : m_Layer(nullptr) + { + } + }; + + struct PickTargetAreas + { + enum Enum { + Presentation, + Matte, + }; + }; + + struct SRulerRect + { + QT3DSI32 m_Left; + QT3DSI32 m_Top; + QT3DSI32 m_Right; + QT3DSI32 m_Bottom; + SRulerRect() + : m_Left(0) + , m_Top(0) + , m_Right(0) + , m_Bottom(0) + { + } + SRulerRect(QT3DSI32 l, QT3DSI32 t, QT3DSI32 r, QT3DSI32 b) + : m_Left(l) + , m_Top(t) + , m_Right(r) + , m_Bottom(b) + { + } + bool Contains(QT3DSI32 x, QT3DSI32 y) const + { + return x >= m_Left && x <= m_Right && y >= m_Bottom && y <= m_Top; + } + }; + + struct SDragPreparationResult + { + uic::render::IUICRenderer *m_Renderer; + SNode *m_Node; + SLayer *m_Layer; + SCamera *m_Camera; + qt3ds::render::NVPlane m_Plane; + QT3DSVec3 m_GlobalPos; + QT3DSVec3 m_CameraGlobalPos; + QT3DSVec3 m_CameraDirection; + QT3DSVec3 m_Axis; + QT3DSMat44 m_GlobalTransform; + QT3DSMat33 m_NormalMatrix; + QT3DSU32 m_AxisIndex; + uic::widgets::StudioWidgetComponentIds::Enum m_ComponentId; + uic::widgets::StudioWidgetTypes::Enum m_WidgetType; + uic::render::RenderWidgetModes::Enum m_WidgetMode; + SRay m_OriginalRay; + SRay m_CurrentRay; + SRay m_PreviousRay; + Option m_OriginalPlaneCoords; + Option m_CurrentPlaneCoords; + Option m_PreviousPlaneCoords; + bool m_IsPlane; + SDragPreparationResult() {} + }; + + struct SPathAnchorDragInitialValue + { + QT3DSVec2 m_Position; + float m_IncomingAngle; + float m_IncomingDistance; + float m_OutgoingDistance; + SPathAnchorDragInitialValue() {} + }; + + struct STranslation : public uic::render::IUICRenderNodeFilter + { + typedef eastl::pair + THandleTranslatorPair; + typedef eastl::vector THandleTranslatorPairList; + // Now that we have aliases, one instance handle can map to several translators. One + // translator, however, only + // maps to one instance handle. + typedef nvhash_map> + TInstanceToTranslatorMap; + IStudioRenderer &m_Renderer; + IUICRenderContext &m_UICContext; + CDoc &m_Doc; + IDocumentReader &m_Reader; + SComposerObjectDefinitions &m_ObjectDefinitions; + UICDM::CStudioSystem &m_StudioSystem; + UICDM::CStudioFullSystem &m_FullSystem; + Q3DStudio::CGraph &m_AssetGraph; + + // allocator for scene graph and translators + qt3ds::foundation::SSAutoDeallocatorAllocator m_Allocator; + // All translator related containers must come after the allocator + TInstanceToTranslatorMap m_TranslatorMap; + TTranslatorDirtySet m_DirtySet; + uic::render::SPresentation m_Presentation; + uic::render::SScene *m_Scene; + Q3DStudio::CGraphIterator m_GraphIterator; + nvvector m_SignalConnections; + QT3DSI32 m_ComponentSecondsDepth; + SNode m_MouseDownNode; + SCamera m_MouseDownCamera; + Option m_MouseDownParentGlobalTransformInverse; + Option m_MouseDownParentRotationInverse; + Option m_MouseDownGlobalRotation; + QT3DSI32 m_KeyRepeat; + bool m_EditCameraEnabled; + bool m_EditLightEnabled; + SEditCameraPersistentInformation m_EditCameraInfo; + SCamera m_EditCamera; + SLight m_EditLight; + QT3DSVec2 m_Viewport; + SEditCameraLayerTranslator *m_EditCameraLayerTranslator; + Option m_ZoomRender; + NVScopedRefCounted m_TranslationWidget; + NVScopedRefCounted m_RotationWidget; + NVScopedRefCounted m_ScaleWidget; + NVScopedRefCounted m_LastRenderedWidget; + NVScopedRefCounted m_PathWidget; + NVScopedRefCounted m_PickBuffer; + Option m_LastPathDragValue; + nvvector m_PixelBuffer; + QT3DSF32 m_CumulativeRotation; + eastl::vector m_GuideContainer; + qt3ds::foundation::SFastAllocator<> m_GuideAllocator; + // The rects are maintained from last render because the render context + // doesn't guarantee the rects it returns are valid outside of begin/end render calls. + SRulerRect m_OuterRect; + SRulerRect m_InnerRect; // presentation rect. + + QT3DSVec4 m_rectColor; + QT3DSVec4 m_lineColor; + QT3DSVec4 m_guideColor; + QT3DSVec4 m_selectedGuideColor; + QT3DSVec4 m_guideFillColor; + QT3DSVec4 m_selectedGuideFillColor; + + STranslation(IStudioRenderer &inRenderer, IUICRenderContext &inContext); + void MarkBeginComponentSeconds(UICDM::CUICDMSlideHandle) { ++m_ComponentSecondsDepth; } + + void MarkComponentSeconds(UICDM::CUICDMSlideHandle) + { + m_ComponentSecondsDepth = NVMax(0, m_ComponentSecondsDepth - 1); + if (m_ComponentSecondsDepth == 0) + RequestRender(); + } + + void ReleaseTranslation(Q3DStudio::TIdentifier inInstance); + + void MarkGraphInstanceDirty(Q3DStudio::TIdentifier inInstance, + Q3DStudio::TIdentifier /*inParent*/) + { + MarkDirty(inInstance); + } + + void MarkDirty(UICDM::CUICDMInstanceHandle inInstance); + + void MarkDirty(UICDM::CUICDMInstanceHandle *inInstance, long inInstanceCount) + { + for (long idx = 0; idx < inInstanceCount; ++idx) + MarkDirty(inInstance[idx]); + } + + void DrawBoundingBox(SNode &inNode, QT3DSVec3 inColor); + void DrawLightBoundingBox(SNode &inNode, QT3DSVec3 inColor); + + void DrawChildBoundingBoxes(SNode &inNode) + { + ::CColor color = CStudioPreferences::GetGroupBoundingBoxColor(); + QT3DSVec3 colorVec(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f); + for (SNode *theChild = inNode.m_FirstChild; theChild; + theChild = theChild->m_NextSibling) { + if (IncludeNode(*theChild)) + DrawBoundingBox(*theChild, colorVec); + } + } + + void DrawGroupBoundingBoxes(SGraphObjectTranslator &inTranslator) + { + SNode &theNode = static_cast(inTranslator.GetGraphObject()); + if (theNode.m_FirstChild) { + ::CColor color = CStudioPreferences::GetGroupBoundingBoxColor(); + QT3DSVec3 colorVec(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f); + DrawBoundingBox(theNode, colorVec); + if (inTranslator.GetGraphObject().m_Type != GraphObjectTypes::Layer) + DrawChildBoundingBoxes(theNode); + } + } + + void DrawNonGroupBoundingBoxes(SGraphObjectTranslator &inTranslator) + { + SNode &theNode = static_cast(inTranslator.GetGraphObject()); + if (inTranslator.GetGraphObject().m_Type == GraphObjectTypes::Light) { + ::CColor color = CStudioPreferences::GetLightBoundingBoxColor(); + QT3DSVec3 colorVec(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f); + DrawLightBoundingBox(theNode, colorVec); + } else if (inTranslator.GetGraphObject().m_Type != GraphObjectTypes::Layer) { + ::CColor color = CStudioPreferences::GetSingleBoundingBoxColor(); + QT3DSVec3 colorVec(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f); + DrawBoundingBox(theNode, colorVec); + DrawChildBoundingBoxes(theNode); + } else { + ::CColor color = CStudioPreferences::GetSingleBoundingBoxColor(); + QT3DSVec3 colorVec(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f); + m_UICContext.GetRenderer().RenderLayerRect( + static_cast(inTranslator.GetGraphObject()), colorVec); + } + } + + void DrawAxis(SGraphObjectTranslator &inTranslator); + + void SetViewport(QT3DSF32 inWidth, QT3DSF32 inHeight) { m_Viewport = QT3DSVec2(inWidth, inHeight); } + + QT3DSVec2 GetViewportDimensions() { return m_Viewport; } + + void ClearDirtySet() + { + // The dirty set may be modified while this operation is taking place in the case of + // alias nodes. + for (qt3ds::QT3DSU32 idx = 0; idx < (qt3ds::QT3DSU32)m_DirtySet.size(); ++idx) { + if (m_Reader.IsInstance(m_DirtySet[idx]->GetInstanceHandle())) + m_DirtySet[idx]->PushTranslation(*this); + } + m_DirtySet.clear(); + } + // We build the render graph every time we render. This may seem wasteful + void BuildRenderGraph(UICDM::CUICDMInstanceHandle inParent, + CUICDMInstanceHandle inAliasHandle = UICDM::CUICDMInstanceHandle()); + void + BuildRenderGraph(SGraphObjectTranslator &inParent, + UICDM::CUICDMInstanceHandle inAliasHandle = UICDM::CUICDMInstanceHandle()); + void + DeactivateScan(SGraphObjectTranslator &inParent, + UICDM::CUICDMInstanceHandle inAliasHandle = UICDM::CUICDMInstanceHandle()); + void PreRender(); + void Render(int inWidgetId, bool inDrawGuides); + void EndRender(); + void DoPrepareForDrag(SNode *inSelectedNode); + void ResetWidgets(); + void EndDrag(); + bool IsPathWidgetActive(); + + void PrepareForDrag() { DoPrepareForDrag(GetSelectedNode()); } + + SStudioPickValue Pick(CPt inMouseCoords, TranslationSelectMode::Enum inSelectMode); + Option PickWidget(CPt inMouseCoords, TranslationSelectMode::Enum inSelectMode, + uic::widgets::IStudioWidgetBase &inWidget); + + qt3ds::foundation::Option PickRulers(CPt inMouseCoords); + + SNode *GetSelectedNode() + { + UICDM::CUICDMInstanceHandle theHandle = m_Doc.GetSelectedInstance(); + SGraphObjectTranslator *theTranslator = GetOrCreateTranslator(theHandle); + if (theTranslator + && GraphObjectTypes::IsNodeType(theTranslator->GetGraphObject().m_Type)) + return static_cast(&theTranslator->GetGraphObject()); + return nullptr; + } + static inline SFloat3 ToDataModel(const QT3DSVec3 &inValue) + { + return SFloat3(inValue.x, inValue.y, inValue.z); + } + + static inline SFloat3 ToDataModelRotation(const QT3DSVec3 &inValue) + { + SFloat3 retval = ToDataModel(inValue); + TODEG(retval.m_Floats[0]); + TODEG(retval.m_Floats[1]); + TODEG(retval.m_Floats[2]); + return retval; + } + + void SetPosition(const QT3DSVec3 &inPosition, CUpdateableDocumentEditor &inEditor) + { + inEditor.EnsureEditor(L"Set Position", __FILE__, __LINE__) + .SetInstancePropertyValue(m_Doc.GetSelectedInstance(), + m_ObjectDefinitions.m_Node.m_Position, + ToDataModel(inPosition)); + inEditor.FireImmediateRefresh(m_Doc.GetSelectedInstance()); + } + void SetRotation(const QT3DSVec3 &inRotation, CUpdateableDocumentEditor &inEditor) + { + inEditor.EnsureEditor(L"Set Rotation", __FILE__, __LINE__) + .SetInstancePropertyValue(m_Doc.GetSelectedInstance(), + m_ObjectDefinitions.m_Node.m_Rotation, + ToDataModelRotation(inRotation)); + inEditor.FireImmediateRefresh(m_Doc.GetSelectedInstance()); + } + void SetScale(const QT3DSVec3 &inScale, CUpdateableDocumentEditor &inEditor) + { + inEditor.EnsureEditor(L"Set Scale", __FILE__, __LINE__) + .SetInstancePropertyValue(m_Doc.GetSelectedInstance(), + m_ObjectDefinitions.m_Node.m_Scale, ToDataModel(inScale)); + inEditor.FireImmediateRefresh(m_Doc.GetSelectedInstance()); + } + + QT3DSVec3 GetIntendedPosition(UICDM::CUICDMInstanceHandle inInstance, CPt inPos); + + void ApplyPositionalChange(QT3DSVec3 inDiff, SNode &inNode, + CUpdateableDocumentEditor &inEditor); + + void TranslateSelectedInstanceAlongCameraDirection(CPt inOriginalCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor); + + void TranslateSelectedInstance(CPt inOriginalCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor, bool inLockToAxis); + + void ScaleSelectedInstanceZ(CPt inOriginalCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor); + + void ScaleSelectedInstance(CPt inOriginalCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor); + + void CalculateNodeGlobalRotation(SNode &inNode); + + void ApplyRotationToSelectedInstance(const QT3DSQuat &inFinalRotation, SNode &inNode, + CUpdateableDocumentEditor &inEditor, + bool inIsMouseRelative = true); + + void RotateSelectedInstanceAboutCameraDirectionVector(CPt inPreviousMouseCoords, + CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor); + + // This method never feels right to me. It is difficult to apply it to a single axis (of + // course for that + // you can use the inspector palette). + void RotateSelectedInstance(CPt inOriginalCoords, CPt inPreviousMouseCoords, + CPt inMouseCoords, CUpdateableDocumentEditor &inEditor, + bool inLockToAxis); + + Option + PrepareWidgetDrag(uic::widgets::StudioWidgetComponentIds::Enum inComponentId, + uic::widgets::StudioWidgetTypes::Enum inWidgetId, + uic::render::RenderWidgetModes::Enum inWidgetMode, SNode &inNode, + CPt inOriginalCoords, CPt inPreviousMouseCoords, CPt inMouseCoords); + + void PerformWidgetDrag(int inWidgetSubComponent, CPt inOriginalCoords, + CPt inPreviousMouseCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor); + + void PerformGuideDrag(CUICDMGuideHandle inGuide, CPt inPoint, + CUpdateableDocumentEditor &inEditor); + void CheckGuideInPresentationRect(CUICDMGuideHandle inGuide, + CUpdateableDocumentEditor &inEditor); + + void PerformPathDrag(uic::studio::SPathPick &inPathPick, CPt inOriginalCoords, + CPt inPreviousMouseCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor); + + // Pulled directly from old studio's Node.cpp. + void OnNudge(ENudgeDirection inDirection, int inToolmode, int inFlags, + CUpdateableDocumentEditor &inEditor); + + void OnNudgeFinished() { m_KeyRepeat = 0; } + + void RequestRender() + { + if (m_ComponentSecondsDepth == 0) + m_Renderer.RequestRender(); + } + + void RenderZoomRender(SZoomRender &inRender); + + // IUICRenderNodeFilter + bool IncludeNode(const SNode &inNode) override; + + PickTargetAreas::Enum GetPickArea(CPt inPoint); + + SNode *GetEditCameraLayer(); + + void ReleaseEffect(UICDM::CUICDMInstanceHandle inInstance); + // Create a new translator for this type. Do not add to any maps or anything else. + SGraphObjectTranslator *CreateTranslator(UICDM::CUICDMInstanceHandle inInstance); + // Returns the canonical translator for a given instance or creates a new translator if none + // exist. + SGraphObjectTranslator *GetOrCreateTranslator(UICDM::CUICDMInstanceHandle inInstance); + // Create a new aliased translator for this type. + SGraphObjectTranslator *GetOrCreateTranslator(UICDM::CUICDMInstanceHandle inInstance, + UICDM::CUICDMInstanceHandle inAliasInstance); + THandleTranslatorPairList & + GetTranslatorsForInstance(UICDM::CUICDMInstanceHandle inInstance); + UICDM::CUICDMInstanceHandle GetAnchorPoint(SPathPick &inPick); + UICDM::CUICDMInstanceHandle GetAnchorPoint(QT3DSU32 inAnchorIndex); + }; + + struct SDisableUseClearColor + { + SGraphObjectTranslator *m_SceneTranslator; + bool m_PreviousUseClearColor; + bool m_DisableUseClearColor; + + SDisableUseClearColor(STranslation &inTranslation, bool disableUseClearColor) + : m_SceneTranslator(nullptr) + , m_PreviousUseClearColor(false) + , m_DisableUseClearColor(disableUseClearColor) + { + if (m_DisableUseClearColor) { + TIdentifier theRoot = inTranslation.m_AssetGraph.GetRoot(0); + m_SceneTranslator = inTranslation.GetOrCreateTranslator(theRoot); + if (m_SceneTranslator) { + SScene &theScene = static_cast(m_SceneTranslator->GetGraphObject()); + m_PreviousUseClearColor = theScene.m_UseClearColor; + SetUseClearColor(false); + } + } + } + + ~SDisableUseClearColor() + { + if (m_DisableUseClearColor) { + SetUseClearColor(m_PreviousUseClearColor); + } + } + + void SetUseClearColor(bool inUseClearColor) + { + if (m_SceneTranslator) { + SScene &theScene = static_cast(m_SceneTranslator->GetGraphObject()); + theScene.m_UseClearColor = inUseClearColor; + } + } + }; +} +} + +#endif diff --git a/src/Authoring/Studio/Render/StudioRotationWidget.cpp b/src/Authoring/Studio/Render/StudioRotationWidget.cpp new file mode 100644 index 00000000..813cf7ac --- /dev/null +++ b/src/Authoring/Studio/Render/StudioRotationWidget.cpp @@ -0,0 +1,437 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "StudioWidgetImpl.h" +#include "foundation/Qt3DSAtomic.h" +#include "render/Qt3DSRenderContext.h" +#include "render/Qt3DSRenderVertexBuffer.h" +#include "UICRenderNode.h" +#include "foundation/Qt3DSContainers.h" +#include "UICRenderShaderCodeGeneratorV2.h" +#include "UICRenderCamera.h" +#include "render/Qt3DSRenderShaderProgram.h" +#include "StudioUtils.h" + +using namespace uic::widgets; + +namespace { + +struct SRotationWidget : public SStudioWidgetImpl +{ + typedef SStudioWidgetImpl TBase; + NVRenderInputAssembler *m_XAxis; + NVRenderInputAssembler *m_YAxis; + NVRenderInputAssembler *m_ZAxis; + NVRenderInputAssembler *m_CameraAxis; + // We use a rect to clear the Z buffer. + NVRenderInputAssembler *m_CameraRect; + + NVRenderShaderProgram *m_ZClearShader; + + volatile QT3DSI32 mRefCount; + + SRotationWidget(NVAllocatorCallback &inAlloc) + : TBase(inAlloc) + , m_XAxis(nullptr) + , m_YAxis(nullptr) + , m_ZAxis(nullptr) + , m_CameraAxis(nullptr) + , m_CameraRect(nullptr) + , m_ZClearShader(nullptr) + , mRefCount(0) + { + } + + QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Allocator) + + NVRenderInputAssembler *CreateRing(IRenderWidgetContext &inWidgetContext, + NVRenderContext &inRenderContext, QT3DSVec3 inDirection, + QT3DSF32 inInnerRadius, QT3DSF32 inOuterRadius, QT3DSF32 inRingColor, + const char *inRingName) + { + QT3DS_ASSERT(inInnerRadius <= inOuterRadius); + CRegisteredString theItemName = inRenderContext.GetStringTable().RegisterStr(inRingName); + NVRenderInputAssembler *retval = inWidgetContext.GetInputAssembler(theItemName); + if (retval) { + return retval; + } + + TResultVecType theVertexData(m_Allocator, "SRotationWidget::theVertexData"); + + QT3DSI32 numSubDivisions = 50; + QT3DSF32 arcRad = 360.0f / (QT3DSF32)numSubDivisions; + TORAD(arcRad); + QT3DSVec3 tempCross = inDirection.cross(QT3DSVec3(0, 1, 0)); + if (tempCross.magnitudeSquared() < .05f) + tempCross = inDirection.cross(QT3DSVec3(1, 0, 0)); + + QT3DSVec3 upDir = inDirection.cross(tempCross); + QT3DSVec3 leftDir = upDir.cross(inDirection); + upDir.normalize(); + leftDir.normalize(); + + QT3DSF32 ringWidth = inOuterRadius - inInnerRadius; + QT3DSF32 ringHalfWidth = ringWidth / 2.0f; + QT3DSF32 middleRadius = inInnerRadius + ringHalfWidth; + + for (QT3DSI32 idx = 0, numLooper = numSubDivisions; idx < numLooper; ++idx) { + QT3DSF32 startDeg = idx * 360.0f / numSubDivisions; + QT3DSF32 endDeg = (idx + 1) * 360.0f / numSubDivisions; + QT3DSF32 startRad(startDeg); + QT3DSF32 endRad(endDeg); + TORAD(startRad); + TORAD(endRad); + QT3DSF32 startSin = NVSin(startRad); + QT3DSF32 endSin = NVSin(endRad); + QT3DSF32 startCos = NVCos(startRad); + QT3DSF32 endCos = NVCos(endRad); + + QT3DSVec3 startDir = startSin * upDir + startCos * leftDir; + QT3DSVec3 endDir = endSin * upDir + endCos * leftDir; + + QT3DSVec3 discStart = startDir * inInnerRadius; + QT3DSVec3 discEnd = endDir * inInnerRadius; + QT3DSVec3 ringStart = startDir * inOuterRadius; + QT3DSVec3 ringEnd = endDir * inOuterRadius; + + QT3DSVec3 middleStart = startDir * (middleRadius); + QT3DSVec3 middleEnd = endDir * (middleRadius); + QT3DSVec3 middleTopLeft = middleStart + inDirection * ringHalfWidth; + QT3DSVec3 middleTopRight = middleStart - inDirection * ringHalfWidth; + QT3DSVec3 middleBottomLeft = middleEnd + inDirection * ringHalfWidth; + QT3DSVec3 middleBottomRight = middleEnd - inDirection * ringHalfWidth; + + // Now two tris for the ring + theVertexData.push_back(QT3DSVec4(discStart, inRingColor)); + theVertexData.push_back(QT3DSVec4(ringStart, inRingColor)); + theVertexData.push_back(QT3DSVec4(ringEnd, inRingColor)); + theVertexData.push_back(QT3DSVec4(ringEnd, inRingColor)); + theVertexData.push_back(QT3DSVec4(discEnd, inRingColor)); + theVertexData.push_back(QT3DSVec4(discStart, inRingColor)); + // Two tris for the ring that is perpendicular to the viewer + theVertexData.push_back(QT3DSVec4(middleTopLeft, inRingColor)); + theVertexData.push_back(QT3DSVec4(middleTopRight, inRingColor)); + theVertexData.push_back(QT3DSVec4(middleBottomRight, inRingColor)); + theVertexData.push_back(QT3DSVec4(middleBottomRight, inRingColor)); + theVertexData.push_back(QT3DSVec4(middleBottomLeft, inRingColor)); + theVertexData.push_back(QT3DSVec4(middleTopLeft, inRingColor)); + } + + QT3DSU32 stride; + QT3DSU32 offset = 0; + NVRenderAttribLayout *theAttribLayout = &inWidgetContext.CreateAttributeLayout( + IStudioWidget::GetVertexBufferAttributesAndStride(stride)); + NVRenderVertexBuffer *theVertexBuffer = &inWidgetContext.GetOrCreateVertexBuffer( + theItemName, stride, toU8DataRef(theVertexData.begin(), theVertexData.size())); + retval = &inWidgetContext.GetOrCreateInputAssembler( + theItemName, theAttribLayout, toConstDataRef(&theVertexBuffer, 1), nullptr, + toConstDataRef(&stride, 1), toConstDataRef(&offset, 1)); + + return retval; + } + + NVRenderInputAssembler *CreateRect(IRenderWidgetContext &inWidgetContext, + NVRenderContext &inRenderContext, QT3DSVec3 inDirection, + QT3DSF32 inHalfWidth, const char *inItemName) + { + CRegisteredString theItemName = inRenderContext.GetStringTable().RegisterStr(inItemName); + NVRenderInputAssembler *retval = inWidgetContext.GetInputAssembler(theItemName); + if (retval) { + return retval; + } + + QT3DSVec3 tempCross = inDirection.cross(QT3DSVec3(0, 1, 0)); + if (tempCross.magnitudeSquared() < .05f) + tempCross = inDirection.cross(QT3DSVec3(1, 0, 0)); + + QT3DSVec3 upDir = inDirection.cross(tempCross); + QT3DSVec3 leftDir = upDir.cross(inDirection); + + TResultVecType theVertexData(m_Allocator, "SRotationWidget::theVertexData"); + + theVertexData.push_back(QT3DSVec4(upDir * inHalfWidth, 0.0f)); + theVertexData.push_back(QT3DSVec4(leftDir * inHalfWidth, 0.0f)); + theVertexData.push_back(QT3DSVec4(upDir * -1.0f * inHalfWidth, 0.0f)); + + theVertexData.push_back(QT3DSVec4(upDir * -1.0f * inHalfWidth, 0.0f)); + theVertexData.push_back(QT3DSVec4(leftDir * -1.0f * inHalfWidth, 0.0f)); + theVertexData.push_back(QT3DSVec4(upDir * inHalfWidth, 0.0f)); + + QT3DSU32 stride; + QT3DSU32 offset = 0; + NVRenderAttribLayout *theAttribLayout = &inWidgetContext.CreateAttributeLayout( + IStudioWidget::GetVertexBufferAttributesAndStride(stride)); + NVRenderVertexBuffer *theVertexBuffer = &inWidgetContext.GetOrCreateVertexBuffer( + theItemName, stride, toU8DataRef(theVertexData.begin(), theVertexData.size())); + + retval = &inWidgetContext.GetOrCreateInputAssembler( + theItemName, theAttribLayout, toConstDataRef(&theVertexBuffer, 1), nullptr, + toConstDataRef(&stride, 1), toConstDataRef(&offset, 1)); + return retval; + } + + NVRenderShaderProgram *CreateZClearShader(IRenderWidgetContext &inWidgetContext, + NVRenderContext &inRenderContext, + const char *inItemName) + { + CRegisteredString theItemName = inRenderContext.GetStringTable().RegisterStr(inItemName); + NVRenderShaderProgram *retval = inWidgetContext.GetShader(theItemName); + if (retval) { + return retval; + } + + uic::render::IShaderProgramGenerator &theGenerator(inWidgetContext.GetProgramGenerator()); + theGenerator.BeginProgram(); + uic::render::IShaderStageGenerator &theVertexGenerator( + *theGenerator.GetStage(uic::render::ShaderGeneratorStages::Vertex)); + uic::render::IShaderStageGenerator &theFragmentGenerator( + *theGenerator.GetStage(uic::render::ShaderGeneratorStages::Fragment)); + theVertexGenerator.AddIncoming("attr_pos", "vec3"); + theVertexGenerator.AddUniform("model_view_projection", "mat4"); + theVertexGenerator.Append("void main() {"); + theVertexGenerator.Append("\tgl_Position = model_view_projection * vec4(attr_pos, 1.0);"); + theVertexGenerator.Append("}"); + theFragmentGenerator.Append("void main() {"); + theFragmentGenerator.Append("\tgl_FragColor.rgb = vec3(0.0, 0.0, 0.0);"); + theFragmentGenerator.Append("\tgl_FragColor.a = 1.0;"); + theFragmentGenerator.Append("}"); + return inWidgetContext.CompileAndStoreShader(theItemName); + } + + static inline QT3DSVec3 ToFixedCameraPos(const QT3DSVec3 &inCameraPos, const SCamera &inCamera) + { + if (inCamera.m_Flags.IsOrthographic()) { + return QT3DSVec3(inCameraPos.x, inCameraPos.y, -600.f); + } + QT3DSF32 multiplier = -600.f / inCameraPos.z; + return inCameraPos * multiplier; + } + + void Render(IRenderWidgetContext &inWidgetContext, NVRenderContext &inRenderContext) override + { + // Widgets have to clear the depth buffer; they shouldn't interact with other components + // but they should self-occlude. + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.Clear(qt3ds::render::NVRenderClearValues::Depth); + inRenderContext.SetBlendFunction(qt3ds::render::NVRenderBlendFunctionArgument( + qt3ds::render::NVRenderSrcBlendFunc::SrcAlpha, + qt3ds::render::NVRenderDstBlendFunc::OneMinusSrcAlpha, + qt3ds::render::NVRenderSrcBlendFunc::One, + qt3ds::render::NVRenderDstBlendFunc::OneMinusSrcAlpha)); + inRenderContext.SetBlendEquation(qt3ds::render::NVRenderBlendEquationArgument( + NVRenderBlendEquation::Add, NVRenderBlendEquation::Add)); + + float pixelRatio = float(devicePixelRatio()); + QT3DSF32 theRingRadius = 100.0f * pixelRatio; + QT3DSF32 theRingWidth = 2.0f * pixelRatio; + QT3DSF32 theRingInner = theRingRadius; + QT3DSF32 theRingOuter = theRingRadius + theRingWidth; + if (m_XAxis == nullptr) { + TBase::SetupRender(inWidgetContext, inRenderContext); + m_PickShader = IStudioWidget::CreateWidgetPickShader(inWidgetContext, inRenderContext); + ; + m_XAxis = CreateRing(inWidgetContext, inRenderContext, QT3DSVec3(-1, 0, 0), theRingInner, + theRingOuter, 0.0f, "RotationWidgetXAxis"); + m_YAxis = CreateRing(inWidgetContext, inRenderContext, QT3DSVec3(0, -1, 0), theRingInner, + theRingOuter, 0.0f, "RotationWidgetYAxis"); + m_ZAxis = CreateRing(inWidgetContext, inRenderContext, QT3DSVec3(0, 0, -1), theRingInner, + theRingOuter, 0.0f, "RotationWidgetZAxis"); + m_CameraAxis = + CreateRing(inWidgetContext, inRenderContext, QT3DSVec3(0, 0, -1), theRingInner + 5, + theRingOuter + 5, 0.0f, "RotationWidgetCameraAxis"); + m_CameraRect = CreateRect(inWidgetContext, inRenderContext, QT3DSVec3(0, 0, -1), 200.0f, + "RotationWidgetZClear"); + m_ZClearShader = + CreateZClearShader(inWidgetContext, inRenderContext, "RotationWidgetZClear"); + } + QT3DSVec3 theXColor(GetXAxisColor()); + QT3DSVec3 theYColor(GetYAxisColor()); + QT3DSVec3 theZColor(GetZAxisColor()); + QT3DSVec3 theRingColor(QT3DSVec3(.8, .8, .8)); + + QT3DSMat44 theMVP = TBase::SetupMVP(inWidgetContext); + inRenderContext.SetCullingEnabled(false); + QT3DSMat44 theCameraMVP = m_WidgetInfo.m_LayerProjection * m_CameraTranslationScale; + + inRenderContext.SetBlendingEnabled(false); + inRenderContext.SetColorWritesEnabled(false); + inRenderContext.SetDepthTestEnabled(false); + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.SetActiveShader(m_ZClearShader); + inRenderContext.SetInputAssembler(m_CameraRect); + m_ZClearShader->SetPropertyValue("model_view_projection", theCameraMVP); + inRenderContext.Draw(NVRenderDrawMode::Triangles, m_CameraRect->GetVertexCount(), 0); + + inRenderContext.SetColorWritesEnabled(true); + inRenderContext.SetActiveShader(m_Shader); + m_Shader->SetPropertyValue("model_view_projection", theCameraMVP); + inRenderContext.SetDepthTestEnabled(false); + inRenderContext.SetDepthWriteEnabled(false); + RenderSingleToneGeometry(StudioWidgetComponentIds::CameraPlane, theRingColor, + inRenderContext, m_CameraAxis); + + inRenderContext.SetDepthTestEnabled(true); + inRenderContext.SetActiveShader(m_Shader); + m_Shader->SetPropertyValue("model_view_projection", theMVP); + RenderSingleToneGeometry(StudioWidgetComponentIds::XAxis, theXColor, inRenderContext, + m_XAxis); + RenderSingleToneGeometry(StudioWidgetComponentIds::YAxis, theYColor, inRenderContext, + m_YAxis); + RenderSingleToneGeometry(StudioWidgetComponentIds::ZAxis, theZColor, inRenderContext, + m_ZAxis); + + if (m_RotationWedge.hasValue()) { + BeginImmediateDrawing(inWidgetContext, inRenderContext); + + QT3DSMat33 theMVPRotation(m_WidgetInfo.m_CameraGlobalInverse.column0.getXYZ(), + m_WidgetInfo.m_CameraGlobalInverse.column1.getXYZ(), + m_WidgetInfo.m_CameraGlobalInverse.column2.getXYZ()); + theMVPRotation = theMVPRotation.getInverse().getTranspose(); + + QT3DSVec3 theRotationAxis = theMVPRotation.transform(m_RotationWedge->m_RotationAxis); + QT3DSVec3 theStartDirection = theMVPRotation.transform(m_RotationWedge->m_StartDirection); + theRotationAxis.normalize(); + theStartDirection.normalize(); + QT3DSQuat theRotation(m_RotationWedge->m_Angle, theRotationAxis); + QT3DSVec3 theEndDirection = theRotation.rotate(theStartDirection); + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.Clear(qt3ds::render::NVRenderClearValues::Depth); + inRenderContext.SetDepthWriteEnabled(false); + inRenderContext.SetDepthTestEnabled(false); + inRenderContext.SetBlendingEnabled(true); + QT3DSVec4 lineColor(1, 1, 1, .7); + QT3DSVec4 fillColor(1, 1, 1, .2); + switch (m_Highlight) { + default: + break; + case StudioWidgetComponentIds::XAxis: + lineColor = QT3DSVec4(theXColor, .7); + fillColor = QT3DSVec4(theXColor, .2); + break; + case StudioWidgetComponentIds::YAxis: + lineColor = QT3DSVec4(theYColor, .7); + fillColor = QT3DSVec4(theYColor, .2); + break; + case StudioWidgetComponentIds::ZAxis: + lineColor = QT3DSVec4(theZColor, .7); + fillColor = QT3DSVec4(theZColor, .2); + break; + } + QT3DSVec3 theStartPos(m_WidgetInfo.m_Position); + QT3DSF32 theStartLineLen = theRingOuter * m_WidgetInfo.m_Scale; + if (m_Highlight == StudioWidgetComponentIds::CameraPlane) + theStartLineLen = (theRingOuter + 5) * m_WidgetInfo.m_Scale; + // Get the end line length in camera space. + QT3DSVec3 theGlobalStart = m_Node->GetGlobalPivot(); + QT3DSQuat theGlobalRot(m_RotationWedge->m_Angle, m_RotationWedge->m_RotationAxis); + QT3DSVec3 theGlobalDir = theGlobalRot.rotate(m_RotationWedge->m_StartDirection); + QT3DSVec3 theGlobalEnd = theGlobalStart + theGlobalDir * m_RotationWedge->m_EndLineLen; + // Transform both start, end into camera space and get the length of the resulting + // vector + QT3DSVec3 theCameraStart = m_WidgetInfo.m_CameraGlobalInverse.transform(theGlobalStart); + QT3DSVec3 theCameraEnd = m_WidgetInfo.m_CameraGlobalInverse.transform(theGlobalEnd); + QT3DSF32 theCameraEndLineLen = QT3DSVec3(theCameraEnd - theCameraStart).magnitude(); + QT3DSF32 theEndLineLen = theCameraEndLineLen; + // Draw lines in world space + SCamera &theCamera(*m_WidgetInfo.m_Camera); + QT3DSVec3 lineStart(ToFixedCameraPos(theStartPos, theCamera)); + QT3DSVec3 startLineEnd( + ToFixedCameraPos(theStartPos + theStartDirection * theStartLineLen, theCamera)); + QT3DSVec3 endLineEnd(ToFixedCameraPos(theCameraEnd, theCamera)); + DrawImmediateLine(lineStart, startLineEnd, 1.0f, lineColor); + DrawImmediateLine(lineStart, endLineEnd, 1.0f, lineColor); + DrawFilledArc(theStartPos, theStartDirection, theStartLineLen, theRotationAxis, + m_RotationWedge->m_Angle, fillColor); + // Now setup the model-view-projection. + QT3DSMat44 theProjection = m_WidgetInfo.m_LayerProjection; + EndImmediateDrawing(inWidgetContext, inRenderContext, theProjection); + + // Now we attempt to render some text. First we format it. + + char textBuffer[25] = { 0 }; + QT3DSF32 angleDeg(m_RotationWedge->m_Angle); + TODEG(angleDeg); + sprintf(textBuffer, "%.1f", angleDeg); + STextRenderInfo theInfo; + theInfo.m_Text = inRenderContext.GetStringTable().RegisterStr(textBuffer); + theInfo.m_HorizontalAlignment = TextHorizontalAlignment::Center; + theInfo.m_VerticalAlignment = TextVerticalAlignment::Bottom; + theInfo.m_FontSize = 12.0f * pixelRatio; + theInfo.m_Font = inRenderContext.GetStringTable().RegisterStr("TitilliumWeb-Regular"); + QT3DSMat44 theTransMatrix(QT3DSMat44::createIdentity()); + theTransMatrix.column3.x = endLineEnd.x; + theTransMatrix.column3.y = endLineEnd.y; + theTransMatrix.column3.z = endLineEnd.z; + // We want to scale the text *down* so that it looks better. + theTransMatrix.column0[0] = m_WidgetInfo.m_Scale * .8f; + theTransMatrix.column1[1] = m_WidgetInfo.m_Scale * .8f; + theTransMatrix.column2[2] = m_WidgetInfo.m_Scale * .8f; + QT3DSMat44 theTextMVP = theProjection * theTransMatrix; + inWidgetContext.RenderText(theInfo, QT3DSVec3(1, 1, 1), QT3DSVec3(.2, .2, .2), theTextMVP); + } + m_Highlight = StudioWidgetComponentIds::NoId; + } + + void RenderPick(const QT3DSMat44 &inProjPremult, NVRenderContext &inRenderContext, + uic::render::SWindowDimensions /*inWinDimensions*/) override + { + if (m_XAxis && m_PickShader) { + QT3DSMat44 theCameraMVP = + inProjPremult * m_WidgetInfo.m_PureProjection * m_CameraTranslationScale; + QT3DSMat44 theMVP = inProjPremult * m_WidgetInfo.m_PureProjection * m_TranslationScale; + + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.Clear(qt3ds::render::NVRenderClearValues::Depth); + inRenderContext.SetDepthTestEnabled(true); + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.SetBlendingEnabled(true); + inRenderContext.SetCullingEnabled(false); + inRenderContext.SetActiveShader(m_ZClearShader); + m_ZClearShader->SetPropertyValue("model_view_projection", theCameraMVP); + inRenderContext.SetInputAssembler(m_CameraRect); + inRenderContext.Draw(NVRenderDrawMode::Triangles, m_CameraRect->GetVertexCount(), 0); + + inRenderContext.SetActiveShader(m_PickShader); + m_PickShader->SetPropertyValue("model_view_projection", theCameraMVP); + RenderPickBuffer(StudioWidgetComponentIds::CameraPlane, m_CameraAxis, inRenderContext); + + m_PickShader->SetPropertyValue("model_view_projection", theMVP); + + RenderPickBuffer(StudioWidgetComponentIds::XAxis, m_XAxis, inRenderContext); + RenderPickBuffer(StudioWidgetComponentIds::YAxis, m_YAxis, inRenderContext); + RenderPickBuffer(StudioWidgetComponentIds::ZAxis, m_ZAxis, inRenderContext); + } + } +}; +} + +IStudioWidget &IStudioWidget::CreateRotationWidget(NVAllocatorCallback &inAlloc) +{ + return *QT3DS_NEW(inAlloc, SRotationWidget)(inAlloc); +} diff --git a/src/Authoring/Studio/Render/StudioScaleWidget.cpp b/src/Authoring/Studio/Render/StudioScaleWidget.cpp new file mode 100644 index 00000000..56b8bb33 --- /dev/null +++ b/src/Authoring/Studio/Render/StudioScaleWidget.cpp @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "StudioWidgetImpl.h" +#include "foundation/Qt3DSAtomic.h" +#include "render/Qt3DSRenderContext.h" +#include "render/Qt3DSRenderVertexBuffer.h" +#include "UICRenderNode.h" +#include "foundation/Qt3DSContainers.h" +#include "UICRenderShaderCodeGenerator.h" +#include "render/Qt3DSRenderShaderProgram.h" +#include "StudioUtils.h" + +using namespace uic::widgets; + +namespace { + +struct SScaleWidget : public SStudioWidgetImpl +{ + typedef SStudioWidgetImpl TBase; + + NVRenderInputAssembler *m_XAxis; + NVRenderInputAssembler *m_YAxis; + NVRenderInputAssembler *m_ZAxis; + + NVRenderInputAssembler *m_XPlane; + NVRenderInputAssembler *m_YPlane; + NVRenderInputAssembler *m_ZPlane; + + volatile QT3DSI32 mRefCount; + + SScaleWidget(NVAllocatorCallback &inAlloc) + : TBase(inAlloc) + , m_XAxis(nullptr) + , m_YAxis(nullptr) + , m_ZAxis(nullptr) + , m_XPlane(nullptr) + , m_YPlane(nullptr) + , m_ZPlane(nullptr) + , mRefCount(0) + { + } + + QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Allocator) + + NVRenderInputAssembler *CreateScaleAxis(IRenderWidgetContext &inWidgetContext, + NVRenderContext &inRenderContext, + const QT3DSVec3 &inDirection, QT3DSF32 inStartOffset, + QT3DSF32 inLength, QT3DSF32 inWidth, QT3DSF32 inBoxSideLength, + const char *inAxisName) + { + + CRegisteredString theItemName = inRenderContext.GetStringTable().RegisterStr(inAxisName); + NVRenderInputAssembler *retval = inWidgetContext.GetInputAssembler(theItemName); + if (retval) { + return retval; + } + + QT3DSVec3 tempCross = inDirection.cross(QT3DSVec3(0, 1, 0)); + if (tempCross.magnitudeSquared() < .05f) + tempCross = inDirection.cross(QT3DSVec3(1, 0, 0)); + + QT3DSVec3 upDir = inDirection.cross(tempCross); + QT3DSVec3 leftDir = upDir.cross(inDirection); + + TResultVecType theVertexData(m_Allocator, "SScaleWidget::theVertexData"); + + QT3DSVec3 rectStart = inDirection * inStartOffset; + // Rect end is also box start, obviously + QT3DSVec3 rectEnd = inDirection * (inStartOffset + inLength); + QT3DSVec3 boxEnd = inDirection * (inStartOffset + inLength + inBoxSideLength); + + QT3DSF32 axisHalfWidth = inWidth / 2.0f; + // Create the axis + CreateRect(rectStart, rectEnd, upDir, axisHalfWidth, 0.0f, theVertexData); + CreateRect(rectStart, rectEnd, leftDir, axisHalfWidth, 0.0f, theVertexData); + // Create box at the top. + QT3DSF32 boxSideHalfLength = inBoxSideLength / 2; + // Get the four sides + QT3DSVec3 boxRectStart = rectEnd + (leftDir * boxSideHalfLength); + QT3DSVec3 boxRectEnd = boxEnd + (leftDir * boxSideHalfLength); + CreateRect(boxRectStart, boxRectEnd, upDir, boxSideHalfLength, 0.0f, theVertexData); + + boxRectStart = rectEnd - leftDir * boxSideHalfLength; + boxRectEnd = boxEnd - leftDir * boxSideHalfLength; + CreateRect(boxRectStart, boxRectEnd, upDir, boxSideHalfLength, 0.0f, theVertexData); + + boxRectStart = rectEnd + upDir * boxSideHalfLength; + boxRectEnd = boxEnd + upDir * boxSideHalfLength; + CreateRect(boxRectStart, boxRectEnd, leftDir, boxSideHalfLength, 0.0f, theVertexData); + + boxRectStart = rectEnd - upDir * boxSideHalfLength; + boxRectEnd = boxEnd - upDir * boxSideHalfLength; + CreateRect(boxRectStart, boxRectEnd, leftDir, boxSideHalfLength, 0.0f, theVertexData); + + // now create the top and bottom + // bottom + boxRectStart = rectEnd + upDir * boxSideHalfLength; + boxRectEnd = rectEnd - upDir * boxSideHalfLength; + CreateRect(boxRectStart, boxRectEnd, leftDir, boxSideHalfLength, 0.0f, theVertexData); + + // top + boxRectStart = boxEnd + upDir * boxSideHalfLength; + boxRectEnd = boxEnd - upDir * boxSideHalfLength; + CreateRect(boxRectStart, boxRectEnd, leftDir, boxSideHalfLength, 0.0f, theVertexData); + + QT3DSU32 stride; + QT3DSU32 offset = 0; + NVRenderAttribLayout *theAttribLayout = &inWidgetContext.CreateAttributeLayout( + IStudioWidget::GetVertexBufferAttributesAndStride(stride)); + NVRenderVertexBuffer *theVertexBuffer = &inWidgetContext.GetOrCreateVertexBuffer( + theItemName, stride, toU8DataRef(theVertexData.begin(), theVertexData.size())); + retval = &inWidgetContext.GetOrCreateInputAssembler( + theItemName, theAttribLayout, toConstDataRef(&theVertexBuffer, 1), nullptr, + toConstDataRef(&stride, 1), toConstDataRef(&offset, 1)); + + return retval; + } + + void Render(IRenderWidgetContext &inWidgetContext, NVRenderContext &inRenderContext) override + { + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.SetDepthTestEnabled(true); + inRenderContext.Clear(qt3ds::render::NVRenderClearValues::Depth); + float pixelRatio = float(devicePixelRatio()); + QT3DSF32 axisStart = 20.0f * pixelRatio; + QT3DSF32 axisLength = 60.0f * pixelRatio; + QT3DSF32 axisTotalLength = axisStart + axisLength; + if (m_XAxis == nullptr) { + TBase::SetupRender(inWidgetContext, inRenderContext); + + QT3DSF32 axisWidth = 2.0f * pixelRatio; + QT3DSF32 triWidth = 7.0f * pixelRatio; + m_XAxis = CreateScaleAxis(inWidgetContext, inRenderContext, QT3DSVec3(1, 0, 0), axisStart, + axisLength, axisWidth, triWidth, "ScaleWidgetXAxis"); + m_YAxis = CreateScaleAxis(inWidgetContext, inRenderContext, QT3DSVec3(0, 1, 0), axisStart, + axisLength, axisWidth, triWidth, "ScaleWidgetYAxis"); + m_ZAxis = CreateScaleAxis(inWidgetContext, inRenderContext, QT3DSVec3(0, 0, -1), axisStart, + axisLength, axisWidth, triWidth, "ScaleWidgetZAxis"); + + QT3DSF32 axisPos = GetDiscPos() * pixelRatio; + QT3DSF32 axisDiscRadius = GetDiscRadius() * pixelRatio; + QT3DSF32 axisRingRadius = GetDiscRingRadius() * pixelRatio; + m_XPlane = + CreateRingedDisc(m_Allocator, inWidgetContext, inRenderContext, QT3DSVec3(1, 0, 0), + QT3DSVec3(0, axisPos, -axisPos), axisDiscRadius, axisRingRadius, 0.0f, + 1.0f, "ScaleWidgetXPlane"); + m_YPlane = + CreateRingedDisc(m_Allocator, inWidgetContext, inRenderContext, QT3DSVec3(0, 1, 0), + QT3DSVec3(axisPos, 0, -axisPos), axisDiscRadius, axisRingRadius, 0.0f, + 1.0f, "ScaleWidgetYPlane"); + m_ZPlane = + CreateRingedDisc(m_Allocator, inWidgetContext, inRenderContext, QT3DSVec3(0, 0, -1), + QT3DSVec3(axisPos, axisPos, 0), axisDiscRadius, axisRingRadius, 0.0f, + 1.0f, "ScaleWidgetZPlane"); + + inRenderContext.SetActiveShader(m_Shader); + m_Shader->SetPropertyValue("attr_pos_add_start", axisStart + 1); + } + + QT3DSMat44 theMVP = TBase::SetupMVP(inWidgetContext); + inRenderContext.SetBlendingEnabled(false); + inRenderContext.SetDepthTestEnabled(true); + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.SetCullingEnabled(false); + inRenderContext.SetActiveShader(m_Shader); + m_Shader->SetPropertyValue("model_view_projection", theMVP); + // temporary set color1 to white so we can hopefully see mistakes. + m_Shader->SetPropertyValue("color1", QT3DSVec3(1, 1, 1)); + + QT3DSVec3 theXColor(GetXAxisColor()); + QT3DSVec3 theYColor(GetYAxisColor()); + QT3DSVec3 theZColor(GetZAxisColor()); + QT3DSVec3 theRingColor(QT3DSVec3(.8, .8, .8)); + QT3DSVec3 theEndOffset = QT3DSVec3(axisTotalLength); + QT3DSVec3 theScaledEnd = QT3DSVec3(theEndOffset.x * m_AxisScale.x, theEndOffset.y * m_AxisScale.y, + theEndOffset.z * m_AxisScale.z); + QT3DSVec3 theEndAddition = theScaledEnd - theEndOffset; + + m_Shader->SetPropertyValue("attr_pos_add_amount", QT3DSVec3(theEndAddition.x, 0, 0)); + RenderSingleToneGeometry(StudioWidgetComponentIds::XAxis, theXColor, inRenderContext, + m_XAxis); + + m_Shader->SetPropertyValue("attr_pos_add_amount", QT3DSVec3(0, theEndAddition.y, 0)); + RenderSingleToneGeometry(StudioWidgetComponentIds::YAxis, theYColor, inRenderContext, + m_YAxis); + + m_Shader->SetPropertyValue("attr_pos_add_amount", QT3DSVec3(0, 0, -1.0f * theEndAddition.z)); + RenderSingleToneGeometry(StudioWidgetComponentIds::ZAxis, theZColor, inRenderContext, + m_ZAxis); + + m_Shader->SetPropertyValue("attr_pos_add_amount", QT3DSVec3(0, 0, 0)); + RenderTwoToneGeometry(StudioWidgetComponentIds::XPlane, theXColor, theRingColor, + inRenderContext, m_XPlane); + RenderTwoToneGeometry(StudioWidgetComponentIds::YPlane, theYColor, theRingColor, + inRenderContext, m_YPlane); + RenderTwoToneGeometry(StudioWidgetComponentIds::ZPlane, theZColor, theRingColor, + inRenderContext, m_ZPlane); + + m_Highlight = StudioWidgetComponentIds::NoId; + } + + void RenderPick(const QT3DSMat44 &inProjPremult, NVRenderContext &inRenderContext, + uic::render::SWindowDimensions /*inWinDimensions*/) override + { + if (m_XAxis && m_PickShader) { + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.Clear(qt3ds::render::NVRenderClearValues::Depth); + inRenderContext.SetDepthTestEnabled(true); + inRenderContext.SetBlendingEnabled(false); + inRenderContext.SetDepthTestEnabled(true); + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.SetCullingEnabled(false); + inRenderContext.SetActiveShader(m_PickShader); + // The projection premultiplication step moves the viewport around till + // it is centered over the mouse and scales everything *post* rendering (to keep + // appropriate aspect). + QT3DSMat44 theMVP = inProjPremult * m_PureProjection * m_TranslationScale; + m_PickShader->SetPropertyValue("model_view_projection", theMVP); + + RenderPickBuffer(StudioWidgetComponentIds::XAxis, m_XAxis, inRenderContext); + RenderPickBuffer(StudioWidgetComponentIds::YAxis, m_YAxis, inRenderContext); + RenderPickBuffer(StudioWidgetComponentIds::ZAxis, m_ZAxis, inRenderContext); + RenderPickBuffer(StudioWidgetComponentIds::XPlane, m_XPlane, inRenderContext); + RenderPickBuffer(StudioWidgetComponentIds::YPlane, m_YPlane, inRenderContext); + RenderPickBuffer(StudioWidgetComponentIds::ZPlane, m_ZPlane, inRenderContext); + } + } +}; +} + +IStudioWidget &IStudioWidget::CreateScaleWidget(NVAllocatorCallback &inAlloc) +{ + return *QT3DS_NEW(inAlloc, SScaleWidget)(inAlloc); +} diff --git a/src/Authoring/Studio/Render/StudioTranslationWidget.cpp b/src/Authoring/Studio/Render/StudioTranslationWidget.cpp new file mode 100644 index 00000000..d75e8567 --- /dev/null +++ b/src/Authoring/Studio/Render/StudioTranslationWidget.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "StudioWidgetImpl.h" +#include "foundation/Qt3DSAtomic.h" +#include "render/Qt3DSRenderContext.h" +#include "UICRenderShaderCodeGenerator.h" +#include "UICRenderNode.h" +#include "render/Qt3DSRenderShaderProgram.h" +#include "StudioUtils.h" + +using namespace uic::widgets; + +namespace { + +struct STranslationWidget : public SStudioWidgetImpl +{ + typedef SStudioWidgetImpl TBase; + NVRenderInputAssembler *m_XAxis; + NVRenderInputAssembler *m_YAxis; + NVRenderInputAssembler *m_ZAxis; + + NVRenderInputAssembler *m_XPlane; + NVRenderInputAssembler *m_YPlane; + NVRenderInputAssembler *m_ZPlane; + + volatile QT3DSI32 mRefCount; + + STranslationWidget(NVAllocatorCallback &inAlloc) + : TBase(inAlloc) + , m_XAxis(nullptr) + , m_YAxis(nullptr) + , m_ZAxis(nullptr) + , m_XPlane(nullptr) + , m_YPlane(nullptr) + , m_ZPlane(nullptr) + , mRefCount(0) + { + } + + QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Allocator); + + void Render(IRenderWidgetContext &inWidgetContext, NVRenderContext &inRenderContext) override + { + // Widgets have to clear the depth buffer; they shouldn't interact with other components + // but they should self-occlude. + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.Clear(qt3ds::render::NVRenderClearValues::Depth); + inRenderContext.SetDepthTestEnabled(true); + if (m_XAxis == nullptr) { + TBase::SetupRender(inWidgetContext, inRenderContext); + float pixelRatio = float(devicePixelRatio()); + QT3DSF32 axisStart = 20.0f * pixelRatio; + QT3DSF32 axisLength = 60.0f * pixelRatio; + QT3DSF32 triLength = 20.0f * pixelRatio; + QT3DSF32 axisWidth = 2.0f * pixelRatio; + QT3DSF32 triWidth = 7.0f * pixelRatio; + m_XAxis = CreateAxis(m_Allocator, inWidgetContext, inRenderContext, QT3DSVec3(1, 0, 0), + axisStart, axisLength, triLength, axisWidth, triWidth, + "TranslationWidgetXAxis"); + m_YAxis = CreateAxis(m_Allocator, inWidgetContext, inRenderContext, QT3DSVec3(0, 1, 0), + axisStart, axisLength, triLength, axisWidth, triWidth, + "TranslationWidgetYAxis"); + m_ZAxis = CreateAxis(m_Allocator, inWidgetContext, inRenderContext, QT3DSVec3(0, 0, -1), + axisStart, axisLength, triLength, axisWidth, triWidth, + "TranslationWidgetZAxis"); + + QT3DSF32 axisPos = GetDiscPos() * pixelRatio; + QT3DSF32 axisDiscRadius = GetDiscRadius() * pixelRatio; + QT3DSF32 axisRingRadius = GetDiscRingRadius() * pixelRatio; + m_XPlane = + CreateRingedDisc(m_Allocator, inWidgetContext, inRenderContext, QT3DSVec3(1, 0, 0), + QT3DSVec3(0, axisPos, -axisPos), axisDiscRadius, axisRingRadius, 0.0f, + 1.0f, "TranslationWidgetXPlane"); + m_YPlane = + CreateRingedDisc(m_Allocator, inWidgetContext, inRenderContext, QT3DSVec3(0, 1, 0), + QT3DSVec3(axisPos, 0, -axisPos), axisDiscRadius, axisRingRadius, 0.0f, + 1.0f, "TranslationWidgetYPlane"); + m_ZPlane = + CreateRingedDisc(m_Allocator, inWidgetContext, inRenderContext, QT3DSVec3(0, 0, -1), + QT3DSVec3(axisPos, axisPos, 0), axisDiscRadius, axisRingRadius, 0.0f, + 1.0f, "TranslationWidgetZPlane"); + } + QT3DSMat44 theMVP = TBase::SetupMVP(inWidgetContext); + inRenderContext.SetBlendingEnabled(false); + inRenderContext.SetDepthTestEnabled(true); + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.SetCullingEnabled(false); + inRenderContext.SetActiveShader(m_Shader); + m_Shader->SetPropertyValue("model_view_projection", theMVP); + // temporary set color1 to white so we can hopefully see mistakes. + m_Shader->SetPropertyValue("color1", QT3DSVec3(1, 1, 1)); + + QT3DSVec3 theXColor(GetXAxisColor()); + QT3DSVec3 theYColor(GetYAxisColor()); + QT3DSVec3 theZColor(GetZAxisColor()); + QT3DSVec3 theRingColor(QT3DSVec3(.8, .8, .8)); + + RenderSingleToneGeometry(StudioWidgetComponentIds::XAxis, theXColor, inRenderContext, + m_XAxis); + RenderSingleToneGeometry(StudioWidgetComponentIds::YAxis, theYColor, inRenderContext, + m_YAxis); + RenderSingleToneGeometry(StudioWidgetComponentIds::ZAxis, theZColor, inRenderContext, + m_ZAxis); + RenderTwoToneGeometry(StudioWidgetComponentIds::XPlane, theXColor, theRingColor, + inRenderContext, m_XPlane); + RenderTwoToneGeometry(StudioWidgetComponentIds::YPlane, theYColor, theRingColor, + inRenderContext, m_YPlane); + RenderTwoToneGeometry(StudioWidgetComponentIds::ZPlane, theZColor, theRingColor, + inRenderContext, m_ZPlane); + m_Highlight = StudioWidgetComponentIds::NoId; + } + + void RenderPick(const QT3DSMat44 &inProjPremult, NVRenderContext &inRenderContext, + uic::render::SWindowDimensions /*inWinDimensions*/) override + { + if (m_XAxis && m_PickShader) { + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.Clear(qt3ds::render::NVRenderClearValues::Depth); + inRenderContext.SetDepthTestEnabled(true); + inRenderContext.SetBlendingEnabled(false); + inRenderContext.SetDepthTestEnabled(true); + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.SetCullingEnabled(false); + inRenderContext.SetActiveShader(m_PickShader); + // The projection premultiplication step moves the viewport around till + // it is centered over the mouse and scales everything *post* rendering (to keep + // appropriate aspect). + QT3DSMat44 theMVP = inProjPremult * m_PureProjection * m_TranslationScale; + m_PickShader->SetPropertyValue("model_view_projection", theMVP); + + RenderPickBuffer(StudioWidgetComponentIds::XAxis, m_XAxis, inRenderContext); + RenderPickBuffer(StudioWidgetComponentIds::YAxis, m_YAxis, inRenderContext); + RenderPickBuffer(StudioWidgetComponentIds::ZAxis, m_ZAxis, inRenderContext); + RenderPickBuffer(StudioWidgetComponentIds::XPlane, m_XPlane, inRenderContext); + RenderPickBuffer(StudioWidgetComponentIds::YPlane, m_YPlane, inRenderContext); + RenderPickBuffer(StudioWidgetComponentIds::ZPlane, m_ZPlane, inRenderContext); + } + } +}; +} + +IStudioWidget &IStudioWidget::CreateTranslationWidget(NVAllocatorCallback &inAlloc) +{ + return *QT3DS_NEW(inAlloc, STranslationWidget)(inAlloc); +} diff --git a/src/Authoring/Studio/Render/StudioWidget.cpp b/src/Authoring/Studio/Render/StudioWidget.cpp new file mode 100644 index 00000000..4e8e4717 --- /dev/null +++ b/src/Authoring/Studio/Render/StudioWidget.cpp @@ -0,0 +1,315 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "StudioWidget.h" +#include "UICRenderWidgets.h" +#include "UICRenderContext.h" +#include "render/Qt3DSRenderContext.h" +#include "foundation/Qt3DSContainers.h" +#include "UICRenderShaderCodeGeneratorV2.h" + +using namespace uic::widgets; + +void IStudioWidget::CreateRect(QT3DSVec3 rectStart, QT3DSVec3 rectEnd, QT3DSVec3 orth1, QT3DSF32 axisHalfWidth, + QT3DSF32 inColorIndex, TResultVecType &outResult) +{ + outResult.push_back(QT3DSVec4(rectStart + orth1 * axisHalfWidth, inColorIndex)); + outResult.push_back(QT3DSVec4(rectEnd + orth1 * axisHalfWidth, inColorIndex)); + outResult.push_back(QT3DSVec4(rectEnd - orth1 * axisHalfWidth, inColorIndex)); + outResult.push_back(QT3DSVec4(rectEnd - orth1 * axisHalfWidth, inColorIndex)); + outResult.push_back(QT3DSVec4(rectStart - orth1 * axisHalfWidth, inColorIndex)); + outResult.push_back(QT3DSVec4(rectStart + orth1 * axisHalfWidth, inColorIndex)); +} + +void IStudioWidget::CreateTriangle(QT3DSVec3 triStart, QT3DSVec3 triEnd, QT3DSVec3 orth1, QT3DSF32 triHalfWidth, + QT3DSF32 inColorIndex, TResultVecType &outResult) +{ + outResult.push_back(QT3DSVec4(triStart + orth1 * triHalfWidth, inColorIndex)); + outResult.push_back(QT3DSVec4(triStart - orth1 * triHalfWidth, inColorIndex)); + outResult.push_back(QT3DSVec4(triEnd, inColorIndex)); +} + +NVRenderInputAssembler *IStudioWidget::CreateRingedDisc( + NVAllocatorCallback &inAllocator, IRenderWidgetContext &inWidgetContext, + NVRenderContext &inRenderContext, QT3DSVec3 inDirection, QT3DSVec3 inCenterPt, QT3DSF32 inInnerRadius, + QT3DSF32 inOuterRadius, QT3DSF32 inDiscColor, QT3DSF32 inRingColor, const char *inItemName) +{ + CRegisteredString theItemName = inRenderContext.GetStringTable().RegisterStr(inItemName); + NVRenderInputAssembler *retval = inWidgetContext.GetInputAssembler(theItemName); + if (retval) { + return retval; + } + TResultVecType theVertexData(inAllocator, "STranslationWidget::theVertexData"); + QT3DS_ASSERT(inInnerRadius < inOuterRadius); + QT3DSI32 numSubDivisions = 50; + QT3DSF32 arcRad = 360.0f / (QT3DSF32)numSubDivisions; + TORAD(arcRad); + QT3DSVec3 tempCross = inDirection.cross(QT3DSVec3(0, 1, 0)); + if (tempCross.magnitudeSquared() < .05f) + tempCross = inDirection.cross(QT3DSVec3(1, 0, 0)); + + QT3DSVec3 upDir = inDirection.cross(tempCross); + QT3DSVec3 leftDir = upDir.cross(inDirection); + upDir.normalize(); + leftDir.normalize(); + + for (QT3DSI32 idx = 0, numLooper = numSubDivisions; idx < numLooper; ++idx) { + QT3DSF32 startDeg = idx * 360.0f / numSubDivisions; + QT3DSF32 endDeg = (idx + 1) * 360.0f / numSubDivisions; + QT3DSF32 startRad(startDeg); + QT3DSF32 endRad(endDeg); + TORAD(startRad); + TORAD(endRad); + QT3DSF32 startSin = NVSin(startRad); + QT3DSF32 endSin = NVSin(endRad); + QT3DSF32 startCos = NVCos(startRad); + QT3DSF32 endCos = NVCos(endRad); + + QT3DSVec3 startDir = startSin * upDir + startCos * leftDir; + QT3DSVec3 endDir = endSin * upDir + endCos * leftDir; + + QT3DSVec3 discStart = inCenterPt + startDir * inInnerRadius; + QT3DSVec3 discEnd = inCenterPt + endDir * inInnerRadius; + QT3DSVec3 ringStart = inCenterPt + startDir * inOuterRadius; + QT3DSVec3 ringEnd = inCenterPt + endDir * inOuterRadius; + + // Create the Triangles + // disc first + theVertexData.push_back(QT3DSVec4(inCenterPt, inDiscColor)); + theVertexData.push_back(QT3DSVec4(discStart, inDiscColor)); + theVertexData.push_back(QT3DSVec4(discEnd, inDiscColor)); + + // Now two tris for the ring + theVertexData.push_back(QT3DSVec4(discStart, inRingColor)); + theVertexData.push_back(QT3DSVec4(ringStart, inRingColor)); + theVertexData.push_back(QT3DSVec4(ringEnd, inRingColor)); + theVertexData.push_back(QT3DSVec4(ringEnd, inRingColor)); + theVertexData.push_back(QT3DSVec4(discEnd, inRingColor)); + theVertexData.push_back(QT3DSVec4(discStart, inRingColor)); + } + + QT3DSU32 stride; + QT3DSU32 offset = 0; + NVRenderAttribLayout *theAttribLayout = &inWidgetContext.CreateAttributeLayout( + IStudioWidget::GetVertexBufferAttributesAndStride(stride)); + NVRenderVertexBuffer *theVertexBuffer = &inWidgetContext.GetOrCreateVertexBuffer( + theItemName, stride, toU8DataRef(theVertexData.begin(), theVertexData.size())); + + retval = &inWidgetContext.GetOrCreateInputAssembler( + theItemName, theAttribLayout, toConstDataRef(&theVertexBuffer, 1), nullptr, + toConstDataRef(&stride, 1), toConstDataRef(&offset, 1)); + + return retval; +} + +// Create an axis with a triangle at the top. Really we create two axis that are orthogonal to each +// other. +NVRenderInputAssembler * +IStudioWidget::CreateAxis(NVAllocatorCallback &inAllocator, IRenderWidgetContext &inWidgetContext, + NVRenderContext &inRenderContext, const QT3DSVec3 &inAxisDirection, + QT3DSF32 inAxisStartOffset, QT3DSF32 inAxisLength, QT3DSF32 inTriLength, + QT3DSF32 inAxisWidth, QT3DSF32 inTriWidth, const char *inAxisName) +{ + CRegisteredString theItemName = inRenderContext.GetStringTable().RegisterStr(inAxisName); + NVRenderInputAssembler *retval = inWidgetContext.GetInputAssembler(theItemName); + if (retval) { + return retval; + } + + TResultVecType theVertexData(inAllocator, "STranslationWidget::theVertexData"); + QT3DSVec3 orth1 = inAxisDirection.cross(QT3DSVec3(0, 0, 1)); + if (orth1.magnitudeSquared() < .05f) + orth1 = inAxisDirection.cross(QT3DSVec3(0, 1, 0)); + QT3DSVec3 orth2 = inAxisDirection.cross(orth1); + + // Draw a rect that starts at inAxisStartOffset + QT3DSVec3 rectStart = inAxisDirection * inAxisStartOffset; + // Rect end is also tri start, obviously + QT3DSVec3 rectEnd = inAxisDirection * (inAxisStartOffset + inAxisLength); + QT3DSVec3 triEnd = inAxisDirection * (inAxisStartOffset + inAxisLength + inTriLength); + + QT3DSF32 axisHalfWidth = inAxisWidth / 2.0f; + QT3DSF32 triHalfWidth = inTriWidth / 2.0f; + CreateRect(rectStart, rectEnd, orth1, axisHalfWidth, 0.0f, theVertexData); + CreateTriangle(rectEnd, triEnd, orth1, triHalfWidth, 0.0f, theVertexData); + CreateRect(rectStart, rectEnd, orth2, axisHalfWidth, 0.0f, theVertexData); + CreateTriangle(rectEnd, triEnd, orth2, triHalfWidth, 0.0f, theVertexData); + + QT3DSU32 stride; + QT3DSU32 offset = 0; + NVRenderAttribLayout *theAttribLayout = &inWidgetContext.CreateAttributeLayout( + IStudioWidget::GetVertexBufferAttributesAndStride(stride)); + NVRenderVertexBuffer *theVertexBuffer = &inWidgetContext.GetOrCreateVertexBuffer( + theItemName, stride, toU8DataRef(theVertexData.begin(), theVertexData.size())); + + retval = &inWidgetContext.GetOrCreateInputAssembler( + theItemName, theAttribLayout, toConstDataRef(&theVertexBuffer, 1), nullptr, + toConstDataRef(&stride, 1), toConstDataRef(&offset, 1)); + + return retval; +}; + +SWidgetRenderSetupResult::SWidgetRenderSetupResult(IRenderWidgetContext &inWidgetContext, + SNode &inNode, + RenderWidgetModes::Enum inWidgetMode) +{ + m_WidgetInfo = + inWidgetContext.GetWidgetRenderInformation(inNode, QT3DSVec3(0, 0, 0), inWidgetMode); + QT3DSMat44 theTranslationScale(QT3DSMat44::createIdentity()); + QT3DSMat33 theRotationMult(QT3DSMat33::createIdentity()); + bool includeNodeRotation = inWidgetMode == RenderWidgetModes::Local ? true : false; + if (includeNodeRotation) { + QT3DSMat44 theNodeRotation; + inNode.CalculateRotationMatrix(theNodeRotation); + if (inNode.m_Flags.IsLeftHanded()) { + SNode::FlipCoordinateSystem(theNodeRotation); + } + theRotationMult = + QT3DSMat33(theNodeRotation.column0.getXYZ(), theNodeRotation.column1.getXYZ(), + theNodeRotation.column2.getXYZ()); + } + + QT3DSMat33 theRotationMatrix = m_WidgetInfo.m_NormalMatrix * theRotationMult; + QT3DSMat33 theScaleMatrix(QT3DSMat33::createIdentity()); + theScaleMatrix.column0[0] = m_WidgetInfo.m_Scale; + theScaleMatrix.column1[1] = m_WidgetInfo.m_Scale; + theScaleMatrix.column2[2] = m_WidgetInfo.m_Scale; + QT3DSMat33 theCombined = theRotationMatrix * theScaleMatrix; + theTranslationScale.column0 = QT3DSVec4(theCombined.column0, 0.0f); + theTranslationScale.column1 = QT3DSVec4(theCombined.column1, 0.0f); + theTranslationScale.column2 = QT3DSVec4(theCombined.column2, 0.0f); + theTranslationScale.column3.x = m_WidgetInfo.m_Position.x; + theTranslationScale.column3.y = m_WidgetInfo.m_Position.y; + theTranslationScale.column3.z = m_WidgetInfo.m_Position.z; + m_TranslationScale = theTranslationScale; + m_PureProjection = m_WidgetInfo.m_PureProjection; + + QT3DSMat44 theCameraTransScale(QT3DSMat44::createIdentity()); + theCameraTransScale.column0 = QT3DSVec4(m_WidgetInfo.m_LookAtMatrix.column0, 0.0f); + theCameraTransScale.column1 = QT3DSVec4(m_WidgetInfo.m_LookAtMatrix.column1, 0.0f); + theCameraTransScale.column2 = QT3DSVec4(m_WidgetInfo.m_LookAtMatrix.column2, 0.0f); + theCameraTransScale.column3.x = m_WidgetInfo.m_Position.x; + theCameraTransScale.column3.y = m_WidgetInfo.m_Position.y; + theCameraTransScale.column3.z = m_WidgetInfo.m_Position.z; + theCameraTransScale.column0[0] = m_WidgetInfo.m_Scale; + theCameraTransScale.column1[1] = m_WidgetInfo.m_Scale; + theCameraTransScale.column2[2] = m_WidgetInfo.m_Scale; + m_CameraTranslationScale = theCameraTransScale; + m_SetupResult = m_WidgetInfo.m_LayerProjection * theTranslationScale; +} + +CRegisteredString IStudioWidget::GetSharedShaderName(IStringTable &inStrTable) +{ + return inStrTable.RegisterStr("IStudioWidget Shader"); +} + +CRegisteredString IStudioWidget::GetSharedPickShaderName(IStringTable &inStrTable) +{ + return inStrTable.RegisterStr("IStudioWidget Pick Shader"); +} + +NVRenderShaderProgram *IStudioWidget::CreateWidgetShader(IRenderWidgetContext &inWidgetContext, + NVRenderContext &inRenderContext) +{ + CRegisteredString theSharedName(GetSharedShaderName(inRenderContext.GetStringTable())); + NVRenderShaderProgram *retval = inWidgetContext.GetShader(theSharedName); + if (retval) + return retval; + uic::render::IShaderProgramGenerator &theGenerator(inWidgetContext.GetProgramGenerator()); + theGenerator.BeginProgram(); + uic::render::IShaderStageGenerator &theVertexGenerator( + *theGenerator.GetStage(uic::render::ShaderGeneratorStages::Vertex)); + uic::render::IShaderStageGenerator &theFragmentGenerator( + *theGenerator.GetStage(uic::render::ShaderGeneratorStages::Fragment)); + theVertexGenerator.AddIncoming("attr_pos", "vec3"); + theVertexGenerator.AddIncoming("attr_color_index", "float"); + theVertexGenerator.AddOutgoing("output_color_index", "float"); + theVertexGenerator.AddUniform("model_view_projection", "mat4"); + // These are required in order to scale the scale widget the way we want to scale it. + theVertexGenerator.AddUniform("attr_pos_add_start", "float"); + theVertexGenerator.AddUniform("attr_pos_add_amount", "vec3"); + theVertexGenerator.Append("void main() {"); + theVertexGenerator + << "\tvec3 thePos = attr_pos;" << Endl + << "\tif ( length(thePos) > attr_pos_add_start ) thePos = thePos + attr_pos_add_amount;" + << Endl; + theVertexGenerator.Append("\tgl_Position = model_view_projection * vec4(thePos, 1.0);"); + theVertexGenerator.Append("\toutput_color_index = attr_color_index;"); + theVertexGenerator.Append("}"); + theFragmentGenerator.AddUniform("color0", "vec3"); + theFragmentGenerator.AddUniform("color1", "vec3"); + theFragmentGenerator.Append("void main() {"); + theFragmentGenerator.Append("\tgl_FragColor.rgb = output_color_index > 0.0 ? color1 : color0;"); + theFragmentGenerator.Append("\tgl_FragColor.a = 1.0;"); + theFragmentGenerator.Append("}"); + return inWidgetContext.CompileAndStoreShader(theSharedName); +} + +NVRenderShaderProgram *IStudioWidget::CreateWidgetPickShader(IRenderWidgetContext &inWidgetContext, + NVRenderContext &inRenderContext) +{ + CRegisteredString theSharedName(GetSharedPickShaderName(inRenderContext.GetStringTable())); + NVRenderShaderProgram *retval = inWidgetContext.GetShader(theSharedName); + if (retval) + return retval; + uic::render::IShaderProgramGenerator &theGenerator(inWidgetContext.GetProgramGenerator()); + theGenerator.BeginProgram(); + uic::render::IShaderStageGenerator &theVertexGenerator( + *theGenerator.GetStage(uic::render::ShaderGeneratorStages::Vertex)); + uic::render::IShaderStageGenerator &theFragmentGenerator( + *theGenerator.GetStage(uic::render::ShaderGeneratorStages::Fragment)); + theVertexGenerator.AddIncoming("attr_pos", "vec3"); + theVertexGenerator.AddUniform("model_view_projection", "mat4"); + theVertexGenerator.Append("void main() {"); + theVertexGenerator.Append("\tgl_Position = model_view_projection * vec4(attr_pos, 1.0);"); + theVertexGenerator.Append("}"); + theFragmentGenerator.AddUniform("object_id", "int"); + theFragmentGenerator.Append("void main() {"); + theFragmentGenerator.Append("\tgl_FragColor.r = float(object_id % 256)/255.0;"); + theFragmentGenerator.Append("\tgl_FragColor.g = float(object_id / 256)/255.0;"); + theFragmentGenerator.Append("\tgl_FragColor.b = 0;"); + theFragmentGenerator.Append("\tgl_FragColor.a = 1.0;"); + theFragmentGenerator.Append("}"); + return inWidgetContext.CompileAndStoreShader(theSharedName); +} + +NVConstDataRef +IStudioWidget::GetVertexBufferAttributesAndStride(QT3DSU32 &stride) +{ + static qt3ds::render::NVRenderVertexBufferEntry theEntries[] = { + qt3ds::render::NVRenderVertexBufferEntry("attr_pos", qt3ds::render::NVRenderComponentTypes::QT3DSF32, + 3), + qt3ds::render::NVRenderVertexBufferEntry("attr_color_index", + qt3ds::render::NVRenderComponentTypes::QT3DSF32, 1, 12), + }; + + stride = 3 * sizeof(QT3DSF32) + 1 * sizeof(QT3DSF32); + + return toConstDataRef(theEntries, 2); +} \ No newline at end of file diff --git a/src/Authoring/Studio/Render/StudioWidget.h b/src/Authoring/Studio/Render/StudioWidget.h new file mode 100644 index 00000000..030e6836 --- /dev/null +++ b/src/Authoring/Studio/Render/StudioWidget.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 UIC_STUDIO_RENDERER_WIDGET_H +#define UIC_STUDIO_RENDERER_WIDGET_H +#pragma once +#include "UICRenderWindowDimensions.h" +#include "UICRenderWidgets.h" +#include "foundation/Qt3DSRefCounted.h" +#include "StudioPickValues.h" + +namespace uic { +namespace widgets { + using namespace uic::render; + + struct StudioWidgetTypes + { + enum Enum { + Unknown, + Translation, + Scale, + Rotation, + }; + }; + + // These are also the ids used as colors in the pick image. + struct StudioWidgetComponentIds + { + enum Enum { + NoId = 0, + XAxis, + YAxis, + ZAxis, + XPlane, + YPlane, + ZPlane, + CameraPlane, + LastId, + }; + }; + + // Functionality shared between the path widget and the various manipulation gadgets + class IStudioWidgetBase : public IRenderWidget, public NVRefCounted + { + public: + virtual void SetNode(SNode &inNode) = 0; + virtual void RenderPick(const QT3DSMat44 &inProjPreMult, NVRenderContext &inRenderContext, + uic::render::SWindowDimensions inWinDimensions) = 0; + virtual uic::studio::SStudioPickValue PickIndexToPickValue(QT3DSU32 inPickIndex) = 0; + }; + + typedef nvvector TResultVecType; + + struct SWidgetRenderSetupResult + { + QT3DSMat44 m_TranslationScale; + QT3DSMat44 m_CameraTranslationScale; + QT3DSMat44 m_PureProjection; + SWidgetRenderInformation m_WidgetInfo; + QT3DSMat44 m_SetupResult; + + SWidgetRenderSetupResult() {} + SWidgetRenderSetupResult(IRenderWidgetContext &inWidgetContext, SNode &inNode, + RenderWidgetModes::Enum inWidgetMode); + }; + + class IStudioWidget : public IStudioWidgetBase + { + public: + static CRegisteredString GetSharedShaderName(IStringTable &inStrTable); + static CRegisteredString GetSharedPickShaderName(IStringTable &inStrTable); + static NVRenderShaderProgram *CreateWidgetShader(IRenderWidgetContext &inWidgetContext, + NVRenderContext &inRenderContext); + static NVRenderShaderProgram *CreateWidgetPickShader(IRenderWidgetContext &inWidgetContext, + NVRenderContext &inRenderContext); + static NVConstDataRef + GetVertexBufferAttributesAndStride(QT3DSU32 &stride); + static NVRenderInputAssembler * + CreateRingedDisc(NVAllocatorCallback &inAllocator, IRenderWidgetContext &inWidgetContext, + NVRenderContext &inRenderContext, QT3DSVec3 inDirection, QT3DSVec3 inCenterPt, + QT3DSF32 inInnerRadius, QT3DSF32 inOuterRadius, QT3DSF32 inDiscColor, + QT3DSF32 inRingColor, const char *inItemName); + static NVRenderInputAssembler * + CreateAxis(NVAllocatorCallback &inAllocator, IRenderWidgetContext &inWidgetContext, + NVRenderContext &inRenderContext, const QT3DSVec3 &inAxisDirection, + QT3DSF32 inAxisStartOffset, QT3DSF32 inAxisLength, QT3DSF32 inTriLength, + QT3DSF32 inAxisWidth, QT3DSF32 inTriWidth, const char *inAxisName); + static void CreateRect(QT3DSVec3 rectStart, QT3DSVec3 rectEnd, QT3DSVec3 orth1, QT3DSF32 axisHalfWidth, + QT3DSF32 inColorIndex, TResultVecType &outResult); + static void CreateTriangle(QT3DSVec3 triStart, QT3DSVec3 triEnd, QT3DSVec3 orth1, QT3DSF32 triHalfWidth, + QT3DSF32 inColorIndex, TResultVecType &outResult); + + void SetNode(SNode &inNode) override = 0; + virtual StudioWidgetTypes::Enum GetWidgetType() const = 0; + virtual void SetSubComponentId(int inSubComponentId) = 0; + virtual void SetRenderWidgetMode(RenderWidgetModes::Enum inSpace) = 0; + virtual RenderWidgetModes::Enum GetRenderWidgetMode() const = 0; + // When we render the axis, we can scale the axis item itself + virtual void SetAxisScale(const QT3DSVec3 &inNewScale) = 0; + // Set the start/end positions of the rotation arc so the rotation gadget can show + // the angle and optionally display an angle readout. The start direction should + // be a normalized direction in world space, and the angle should be in radians + // inRotationAxis is expected to be a normalized direction in world space. + virtual void SetRotationEdges(const QT3DSVec3 &inStartDirection, const QT3DSVec3 &inRotationAxis, + QT3DSF32 inAngleRad, QT3DSF32 inEndLineLen) = 0; + virtual void ClearRotationEdges() = 0; + + static IStudioWidget &CreateTranslationWidget(NVAllocatorCallback &inAlloc); + static IStudioWidget &CreateRotationWidget(NVAllocatorCallback &inAlloc); + static IStudioWidget &CreateScaleWidget(NVAllocatorCallback &inAlloc); + }; +} +} + +#endif diff --git a/src/Authoring/Studio/Render/StudioWidgetImpl.h b/src/Authoring/Studio/Render/StudioWidgetImpl.h new file mode 100644 index 00000000..a00f4fcd --- /dev/null +++ b/src/Authoring/Studio/Render/StudioWidgetImpl.h @@ -0,0 +1,346 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 UIC_STUDIO_RENDERER_WIDGET_IMPL_H +#define UIC_STUDIO_RENDERER_WIDGET_IMPL_H +#pragma once + +#include "StudioWidget.h" +#include "foundation/Qt3DSContainers.h" +#include "render/Qt3DSRenderShaderProgram.h" + +#include "UICRenderNode.h" +#include "UICRenderShaderCodeGeneratorV2.h" + +namespace uic { +namespace widgets { + + typedef nvvector TResultVecType; + + struct SRotationWedge + { + QT3DSVec3 m_StartDirection; // world space position + QT3DSVec3 m_RotationAxis; + QT3DSF32 m_Angle; // angle in radians. + QT3DSF32 m_EndLineLen; + SRotationWedge() {} + SRotationWedge(const QT3DSVec3 &inStartDirection, const QT3DSVec3 &inRotationAxis, QT3DSF32 inAngle, + QT3DSF32 inEndLineLen) + : m_StartDirection(inStartDirection) + , m_RotationAxis(inRotationAxis) + , m_Angle(inAngle) + , m_EndLineLen(inEndLineLen) + { + } + }; + + struct SImmediateVertex + { + QT3DSVec3 m_Position; + QT3DSVec4 m_Color; + SImmediateVertex(const QT3DSVec3 &inPosition, const QT3DSVec4 &inColor) + : m_Position(inPosition) + , m_Color(inColor) + { + } + SImmediateVertex() {} + }; + + template + struct SStudioWidgetImpl : public IStudioWidget + { + NVAllocatorCallback &m_Allocator; + NVRenderShaderProgram *m_Shader; + NVRenderShaderProgram *m_PickShader; + QT3DSMat44 m_TranslationScale; + QT3DSMat44 m_CameraTranslationScale; + QT3DSMat44 m_PureProjection; + SWidgetRenderInformation m_WidgetInfo; + StudioWidgetComponentIds::Enum m_Highlight; + RenderWidgetModes::Enum m_WidgetMode; + + QT3DSVec3 m_AxisScale; + Option m_RotationWedge; + nvvector m_ImmediateBuffer; + NVRenderVertexBuffer *m_ImmediateVertexBuffer; + NVRenderInputAssembler *m_ImmediateInputAssembler; + NVRenderShaderProgram *m_ImmediateShader; + + SStudioWidgetImpl(NVAllocatorCallback &inAlloc) + : m_Allocator(inAlloc) + , m_Shader(NULL) + , m_PickShader(NULL) + , m_Highlight(StudioWidgetComponentIds::NoId) + , m_WidgetMode(RenderWidgetModes::Local) + , m_AxisScale(QT3DSVec3(1, 1, 1)) + , m_ImmediateBuffer(m_Allocator, "STranslationWidget::theVertexData") + , m_ImmediateVertexBuffer(NULL) + , m_ImmediateInputAssembler(NULL) + , m_ImmediateShader(NULL) + { + } + + void SetNode(SNode &inNode) override { m_Node = &inNode; } + + void SetSubComponentId(int inId) override + { + if (inId > 0 && inId < (int)StudioWidgetComponentIds::LastId) + m_Highlight = static_cast(inId); + else + m_Highlight = StudioWidgetComponentIds::NoId; + } + + StudioWidgetTypes::Enum GetWidgetType() const override { return TWidgetType; } + uic::studio::SStudioPickValue PickIndexToPickValue(QT3DSU32 inPickIndex) override + { + return uic::studio::SWidgetPick((QT3DSI32)inPickIndex); + } + + void SetupRender(IRenderWidgetContext &inWidgetContext, NVRenderContext &inRenderContext) + { + m_Shader = IStudioWidget::CreateWidgetShader(inWidgetContext, inRenderContext); + m_PickShader = IStudioWidget::CreateWidgetPickShader(inWidgetContext, inRenderContext); + } + + QT3DSMat44 SetupMVP(IRenderWidgetContext &inWidgetContext) + { + SWidgetRenderSetupResult theSetup(inWidgetContext, *m_Node, m_WidgetMode); + m_TranslationScale = theSetup.m_TranslationScale; + m_CameraTranslationScale = theSetup.m_CameraTranslationScale; + m_PureProjection = theSetup.m_PureProjection; + m_WidgetInfo = theSetup.m_WidgetInfo; + return theSetup.m_SetupResult; + } + + void RenderSingleToneGeometry(StudioWidgetComponentIds::Enum inId, + const QT3DSVec3 &inOriginalColor, + NVRenderContext &inRenderContext, + NVRenderInputAssembler *inGeometryAssembly) + { + bool isHighlighted = inId == m_Highlight; + QT3DSVec3 theColor = isHighlighted ? QT3DSVec3(1, 1, 0) : inOriginalColor; + + m_Shader->SetPropertyValue("color0", theColor); + inRenderContext.SetInputAssembler(inGeometryAssembly); + inRenderContext.Draw(qt3ds::render::NVRenderDrawMode::Triangles, + inGeometryAssembly->GetVertexCount(), 0); + }; + + void RenderTwoToneGeometry(StudioWidgetComponentIds::Enum inId, QT3DSVec3 inColor0, + QT3DSVec3 inColor1, NVRenderContext &inRenderContext, + NVRenderInputAssembler *inGeometryAssembly) + { + bool isHighlighted = inId == m_Highlight; + if (isHighlighted) { + inColor0 = inColor1 = QT3DSVec3(1, 1, 0); + } + + m_Shader->SetPropertyValue("color0", inColor0); + m_Shader->SetPropertyValue("color1", inColor1); + inRenderContext.SetInputAssembler(inGeometryAssembly); + inRenderContext.Draw(qt3ds::render::NVRenderDrawMode::Triangles, + inGeometryAssembly->GetVertexCount(), 0); + }; + + void SetRenderWidgetMode(RenderWidgetModes::Enum inSpace) override { m_WidgetMode = inSpace; } + + RenderWidgetModes::Enum GetRenderWidgetMode() const override { return m_WidgetMode; } + + void RenderPickBuffer(StudioWidgetComponentIds::Enum inId, + NVRenderInputAssembler *inGeometryAssembly, + NVRenderContext &inRenderContext) + { + QT3DSI32 theObjectId = inId; + m_PickShader->SetPropertyValue("object_id", theObjectId); + inRenderContext.SetInputAssembler(inGeometryAssembly); + inRenderContext.Draw(qt3ds::render::NVRenderDrawMode::Triangles, + inGeometryAssembly->GetVertexCount(), 0); + } + + void BeginImmediateDrawing(IRenderWidgetContext &, NVRenderContext &) + { + m_ImmediateBuffer.clear(); + } + + void DrawImmediateRect(const QT3DSVec3 &rectStart, const QT3DSVec3 &rectEnd, const QT3DSVec3 &orth1, + QT3DSF32 axisHalfWidth, const QT3DSVec4 &inColor) + { + StaticAssert::valid_expression(); + m_ImmediateBuffer.push_back( + SImmediateVertex(rectStart + orth1 * axisHalfWidth, inColor)); + m_ImmediateBuffer.push_back(SImmediateVertex(rectEnd + orth1 * axisHalfWidth, inColor)); + m_ImmediateBuffer.push_back(SImmediateVertex(rectEnd - orth1 * axisHalfWidth, inColor)); + m_ImmediateBuffer.push_back(SImmediateVertex(rectEnd - orth1 * axisHalfWidth, inColor)); + m_ImmediateBuffer.push_back( + SImmediateVertex(rectStart - orth1 * axisHalfWidth, inColor)); + m_ImmediateBuffer.push_back( + SImmediateVertex(rectStart + orth1 * axisHalfWidth, inColor)); + } + + void DrawImmediateLine(const QT3DSVec3 &inStart, const QT3DSVec3 &inEnd, QT3DSF32 inWidth, + const QT3DSVec4 &inColor) + { + QT3DSVec3 theDir = inEnd - inStart; + theDir.normalize(); + QT3DSVec3 theTemp = theDir.cross(QT3DSVec3(0, 0, 1)); + QT3DSF32 theTempLen = theTemp.normalize(); + if (theTempLen < .01f) { + theTemp = theDir.cross(QT3DSVec3(0, 1, 0)); + theTemp.normalize(); + } + QT3DSVec3 rectStart(inStart); + QT3DSVec3 rectEnd(inEnd); + QT3DSVec3 orth1 = theDir.cross(theTemp); + QT3DSVec3 orth2 = orth1.cross(theDir); + orth1.normalize(); + orth2.normalize(); + QT3DSF32 axisHalfWidth = inWidth / 2.0f; + DrawImmediateRect(rectStart, rectEnd, orth1, axisHalfWidth, inColor); + DrawImmediateRect(rectStart, rectEnd, orth2, axisHalfWidth, inColor); + } + + void DrawFilledArc(const QT3DSVec3 &inStartPos, const QT3DSVec3 &inStartDirection, QT3DSF32 inArcLen, + const QT3DSVec3 &inRotationAxis, QT3DSF32 inAngle, const QT3DSVec4 &inFillColor) + { + // 25 small triangles per 180 degrees + QT3DSF32 arcLen = (QT3DSF32)(M_PI / 25.0f); + QT3DSU32 increments = NVMax((QT3DSU32)1, (QT3DSU32)((fabs(inArcLen) / arcLen) + .5f)); + QT3DSF32 angleMultiplier = inAngle / (QT3DSF32)increments; + for (QT3DSU32 idx = 0; idx < increments; ++idx) { + QT3DSF32 localAngle = angleMultiplier * idx; + QT3DSF32 nextAngle = angleMultiplier * (idx + 1); + QT3DSQuat theQuat(localAngle, inRotationAxis); + QT3DSQuat nextQuat(nextAngle, inRotationAxis); + QT3DSVec3 startDir = theQuat.rotate(inStartDirection); + QT3DSVec3 endDir = nextQuat.rotate(inStartDirection); + QT3DSVec3 arcStart = inStartPos + (startDir * inArcLen); + QT3DSVec3 arcEnd = inStartPos + (endDir * inArcLen); + m_ImmediateBuffer.push_back(SImmediateVertex(inStartPos, inFillColor)); + m_ImmediateBuffer.push_back(SImmediateVertex(arcStart, inFillColor)); + m_ImmediateBuffer.push_back(SImmediateVertex(arcEnd, inFillColor)); + } + } + + void EndImmediateDrawing(IRenderWidgetContext &inWidgetContext, + NVRenderContext &inRenderContext, const QT3DSMat44 &inProjection) + { + static qt3ds::render::NVRenderVertexBufferEntry theEntries[] = { + qt3ds::render::NVRenderVertexBufferEntry("attr_pos", + qt3ds::render::NVRenderComponentTypes::QT3DSF32, 3), + qt3ds::render::NVRenderVertexBufferEntry( + "attr_color", qt3ds::render::NVRenderComponentTypes::QT3DSF32, 4, 12), + }; + + if (m_ImmediateBuffer.empty()) + return; + + CRegisteredString theShaderName( + inRenderContext.GetStringTable().RegisterStr("StudioWidgetImmedateShader")); + m_ImmediateShader = inWidgetContext.GetShader(theShaderName); + + if (m_ImmediateShader == nullptr) { + uic::render::IShaderProgramGenerator &theGenerator( + inWidgetContext.GetProgramGenerator()); + theGenerator.BeginProgram(); + uic::render::IShaderStageGenerator &theVertexGenerator( + *theGenerator.GetStage(uic::render::ShaderGeneratorStages::Vertex)); + uic::render::IShaderStageGenerator &theFragmentGenerator( + *theGenerator.GetStage(uic::render::ShaderGeneratorStages::Fragment)); + theVertexGenerator.AddIncoming("attr_pos", "vec3"); + theVertexGenerator.AddIncoming("attr_color", "vec4"); + theVertexGenerator.AddUniform("model_view_projection", "mat4"); + theVertexGenerator.AddOutgoing("vertex_color", "vec4"); + theVertexGenerator.Append("void main() {"); + theVertexGenerator.Append( + "\tgl_Position = model_view_projection * vec4(attr_pos, 1.0);"); + theVertexGenerator.Append("\tvertex_color = attr_color;"); + theVertexGenerator.Append("}"); + theFragmentGenerator.Append("void main() {"); + theFragmentGenerator.Append("\tgl_FragColor = vertex_color;"); + theFragmentGenerator.Append("}"); + + m_ImmediateShader = inWidgetContext.CompileAndStoreShader(theShaderName); + } + + CRegisteredString theBufferName = + inRenderContext.GetStringTable().RegisterStr("StudioWidgetImmediateBuffer"); + m_ImmediateVertexBuffer = &inWidgetContext.GetOrCreateVertexBuffer( + theBufferName, 3 * sizeof(QT3DSF32) + 4 * sizeof(QT3DSF32), + toU8DataRef(m_ImmediateBuffer.begin(), m_ImmediateBuffer.size())); + + if (!m_ImmediateInputAssembler) { + QT3DSU32 stride = m_ImmediateVertexBuffer->GetStride(); + QT3DSU32 offset = 0; + NVRenderAttribLayout *theAttribLayout = + &inWidgetContext.CreateAttributeLayout(toConstDataRef(theEntries, 2)); + + CRegisteredString theString = + inRenderContext.GetStringTable().RegisterStr("StudioWidgetImmediateBuffer"); + m_ImmediateInputAssembler = &inWidgetContext.GetOrCreateInputAssembler( + theString, theAttribLayout, toConstDataRef(&m_ImmediateVertexBuffer, 1), nullptr, + toConstDataRef(&stride, 1), toConstDataRef(&offset, 1)); + } + + if (m_ImmediateShader && m_ImmediateInputAssembler) { + inRenderContext.SetActiveShader(m_ImmediateShader); + m_ImmediateShader->SetPropertyValue("model_view_projection", inProjection); + inRenderContext.SetInputAssembler(m_ImmediateInputAssembler); + inRenderContext.Draw(NVRenderDrawMode::Triangles, + m_ImmediateInputAssembler->GetVertexCount(), 0); + } + } + + void SetAxisScale(const QT3DSVec3 &inAxisScale) override { m_AxisScale = inAxisScale; } + + void SetRotationEdges(const QT3DSVec3 &inStartDirection, const QT3DSVec3 &inRotationAxis, + QT3DSF32 inAngleRad, QT3DSF32 inEndLineLen) override + { + m_RotationWedge = + SRotationWedge(inStartDirection, inRotationAxis, inAngleRad, inEndLineLen); + } + + void ClearRotationEdges() override { m_RotationWedge = Empty(); } + + static inline QT3DSF32 ToGLSLColor(QT3DSU32 inItem) { return (QT3DSF32)inItem * 1.0f / 255.0f; } + static inline QT3DSVec3 ToGLSLColor(QT3DSU32 R, QT3DSU32 G, QT3DSU32 B) + { + return QT3DSVec3(ToGLSLColor(R), ToGLSLColor(G), ToGLSLColor(B)); + } + + static QT3DSVec3 GetXAxisColor() { return ToGLSLColor(202, 47, 46); } + static QT3DSVec3 GetYAxisColor() { return ToGLSLColor(100, 205, 53); } + static QT3DSVec3 GetZAxisColor() { return ToGLSLColor(30, 159, 205); } + + static inline QT3DSF32 GetDiscPos() { return 65.0f; } + static inline QT3DSF32 GetDiscRadius() { return 7.0f; } + static inline QT3DSF32 GetDiscRingRadius() { return GetDiscRadius() + 2.0f; } + }; +} +} + +#endif diff --git a/src/Authoring/Studio/Render/WGLRenderContext.cpp b/src/Authoring/Studio/Render/WGLRenderContext.cpp new file mode 100644 index 00000000..36130d0d --- /dev/null +++ b/src/Authoring/Studio/Render/WGLRenderContext.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2001 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "WGLRenderContext.h" +#include "foundation/TrackingAllocator.h" +#include "foundation/Qt3DSFoundation.h" +#include "render/Qt3DSRenderContext.h" +#include "EASTL/string.h" +#include "foundation/Qt3DSLogging.h" + +#include +#include +#include + +//UIC_DEFINE_THISFILE; + +//============================================================================= +/** + * Constructor: Creates the object + */ +CWGLRenderContext::CWGLRenderContext(UICWindow inWindow) + : m_qtContext(0) + , m_Foundation(Q3DStudio::Foundation::SStudioFoundation::Create()) +{ + Open(inWindow); +} + +//============================================================================= +/** + * Destructor: Destroys the object. + */ +CWGLRenderContext::~CWGLRenderContext() +{ + Close(); +} + +//============================================================================= +/** + * Open the render context. + * @param inRenderWindow window handle + * @param inWindowSize window size + */ +void CWGLRenderContext::Open(UICWindow inRenderWindow) +{ + // needed because NVidia cards will fail all the system functions below if there is no window. + // note: the only time inRenderWindow is nullptr is when CThumbnailGenerator is used. Bug3075. + if (!inRenderWindow) + return; + + QObject* qObject = static_cast(inRenderWindow); + QOpenGLWidget* qRenderWidget = qobject_cast(qObject); + Q_ASSERT(qRenderWidget); + + OpenNormalContext(qRenderWidget); +} + +QSurfaceFormat CWGLRenderContext::selectSurfaceFormat(QOpenGLWidget* window) +{ + struct ContextVersion { + int major; + int minor; + qt3ds::render::NVRenderContextType contextType; + }; + + ContextVersion versions[] = { + {4, 1, qt3ds::render::NVRenderContextValues::GL4}, + {3, 3, qt3ds::render::NVRenderContextValues::GL3}, + {2, 1, qt3ds::render::NVRenderContextValues::GL2}, + {0, 0, qt3ds::render::NVRenderContextValues::NullContext} + }; + + QSurfaceFormat result = window->format(); + bool valid = false; + + for (const auto& ver : versions) { + if (ver.contextType == qt3ds::render::NVRenderContextValues::NullContext) + break; + + // make an offscreen surface + context to query version + QScopedPointer offscreenSurface(new QOffscreenSurface); + + QSurfaceFormat format = window->format(); + format.setRenderableType(QSurfaceFormat::OpenGL); + if (ver.major >= 2) + format.setProfile(QSurfaceFormat::CoreProfile); + format.setMajorVersion(ver.major); + format.setMinorVersion(ver.minor); + format.setDepthBufferSize(24); + format.setStencilBufferSize(8); + + offscreenSurface->setFormat(format); + offscreenSurface->create(); + Q_ASSERT(offscreenSurface->isValid()); + + QScopedPointer queryContext(new QOpenGLContext); + queryContext->setFormat(format); + if (queryContext->create()) { + valid = true; + result = format; + break; + } + } // of version test iteration + + if (!valid) { + qFatal("Unable to select suitable OpenGL context"); + } + + qDebug() << Q_FUNC_INFO << "selected surface format:" << result; + return result; +} + +//============================================================================= +/** + * Open a non-multisample render context. + * @param inRenderWindow window handle + * @param inWindowSize window size + * @param inPixelDesc the pixel descriptor struct + */ +void CWGLRenderContext::OpenNormalContext(QOpenGLWidget* inRenderWindow) +{ + // Close before trying to open + Close(); + + // Save off the window + m_Window = inRenderWindow; + m_qtContext = m_Window->context(); + Q_ASSERT(m_qtContext); + + qt3ds::foundation::NVScopedRefCounted theStringTable = + qt3ds::foundation::IStringTable::CreateStringTable(*m_Foundation.m_AllocatorCallback); + QSurfaceFormat contextFormat = m_qtContext->format(); + m_RenderContext = NVScopedRefCounted( + NVRenderContext::CreateGL(*m_Foundation.m_Foundation, *theStringTable, + contextFormat)); + if (m_RenderContext) { + m_RenderContext->SetDefaultDepthBufferBitCount(contextFormat.depthBufferSize()); + m_RenderContext->SetDefaultRenderTarget(inRenderWindow->defaultFramebufferObject()); + } +} + +//============================================================================= +/** + * Close the render context. + */ +void CWGLRenderContext::Close() +{ + m_qtContext = 0; +} + +//============================================================================= +/** + * Prepare the render context to begin rendering. + */ +void CWGLRenderContext::BeginRender() +{ + m_Window->makeCurrent(); + if (m_lastWidgetFBO != m_Window->defaultFramebufferObject()) { + m_lastWidgetFBO = m_Window->defaultFramebufferObject(); + m_RenderContext->SetDefaultRenderTarget(m_lastWidgetFBO); + } +} + +//============================================================================= +/** + * Finalize the rendering of this frame, and present the result. + */ +void CWGLRenderContext::EndRender() +{ + m_Window->doneCurrent(); +} + +void CWGLRenderContext::resized() +{ + if (m_RenderContext) { + m_RenderContext->SetDefaultRenderTarget(m_Window->defaultFramebufferObject()); + } +} + +void CWGLRenderContext::requestRender() +{ + m_Window->update(); +} diff --git a/src/Authoring/Studio/Render/WGLRenderContext.h b/src/Authoring/Studio/Render/WGLRenderContext.h new file mode 100644 index 00000000..a6e5bf79 --- /dev/null +++ b/src/Authoring/Studio/Render/WGLRenderContext.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 __WGLRENDERCONTEXT_H_ +#define __WGLRENDERCONTEXT_H_ +#include "PlatformTypes.h" +#include "Q3DStudioNVFoundation.h" +#include "render/Qt3DSRenderBaseTypes.h" + +#include + +QT_BEGIN_NAMESPACE +class QOpenGLContext; +class QOpenGLWidget; +QT_END_NAMESPACE + +namespace qt3ds { +class NVFoundation; +} + +namespace qt3ds { +namespace render { + class NVRenderContext; + class CAllocator; +} +} + +using qt3ds::NVFoundation; +using qt3ds::render::NVRenderContext; +using qt3ds::render::CAllocator; +using qt3ds::foundation::NVScopedRefCounted; + +class GLogErrorString; + +//============================================================================== +/** + * @class CWGLRenderContext: The OpenGL subclass of the CRenderContext class. + */ +class CWGLRenderContext +{ + // Field Members +protected: + QOpenGLContext *m_qtContext; + + Q3DStudio::Foundation::SStudioFoundation m_Foundation; + NVScopedRefCounted m_RenderContext; + QOpenGLWidget* m_Window; + qt3ds::render::NVRenderContextType m_ContextType; + + quint32 m_lastWidgetFBO = 0; + + // Construction +public: + CWGLRenderContext(UICWindow inRenderWindow); + ~CWGLRenderContext(); + + // Access +public: + void BeginRender(); + void EndRender(); + + // Only available after open. + NVRenderContext &GetRenderContext() { return *m_RenderContext; } + + static QSurfaceFormat selectSurfaceFormat(QOpenGLWidget* window); + + void resized(); + + void requestRender(); + + // Implementation +protected: + void Open(UICWindow inRenderWindow); + + void OpenNormalContext(QOpenGLWidget* inRenderWindow); + void Close(); +}; + +#endif // __WGLRENDERCONTEXT_H_ diff --git a/src/Authoring/Studio/UI/ContextMenu.h b/src/Authoring/Studio/UI/ContextMenu.h new file mode 100644 index 00000000..d6b42bbb --- /dev/null +++ b/src/Authoring/Studio/UI/ContextMenu.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2001 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_CONTEXT_MENU_H +#define INCLUDED_CONTEXT_MENU_H 1 + +#pragma once + +#ifdef WIN32 +#define MENUHANDLE HMENU +#endif + +//============================================================================== +// Includes +//============================================================================== +#include "GenericFunctor.h" +#include + +class CContextMenu; + +//============================================================================= +/** + * Class declaration for Context Menu performers. + */ +class CContextMenuPerformer +{ +public: + CContextMenuPerformer() + : m_SubMenu(nullptr) + { + } + + virtual void OnOptionSelected() = 0; + + void SetSubMenu(CContextMenu *inSubMenu) { m_SubMenu = inSubMenu; } + CContextMenu *GetSubMenu() const { return m_SubMenu; } + +protected: + CContextMenu *m_SubMenu; +}; + +//============================================================================= +/** + * Template declaration for Context Menu performers. + */ +template +class CSpecificCContextMenuPerformer : public CContextMenuPerformer +{ +public: + typedef void (TClass::*TFunction)(); + CSpecificCContextMenuPerformer(TClass *inObject, TFunction inFunction) + { + m_Object = inObject; + m_Function = inFunction; + } + + virtual void OnOptionSelected() { (m_Object->*m_Function)(); } + + TClass *m_Object; + void (TClass::*m_Function)(); +}; + +//============================================================================= +/** + * Cross-platform class for creating context menus. + */ +class CContextMenu +{ + typedef std::vector TPerformerList; + typedef std::vector TOptionList; + +public: + enum ESelection { NO_SELECTION = -1 }; + + CContextMenu(); + virtual ~CContextMenu(); + + long DoPopup(CPt inLocation, HWND inParentWindow); + void AddSeparator(); + void AddOption(int inOptionNameStringID, CContextMenuPerformer *inPerformer, + bool inIsEnabled = true); + void AddOption(const Q3DStudio::CString &inOptionName, CContextMenuPerformer *inPerformer, + bool inIsEnabled = true); + + void Clear(); + void SetCheck(long inIndex, bool inChecked); + void ClearChecked(); + Q3DStudio::CString GetStringAt(long inIndex); + long GetItemCount(); + long GetSelectedOption() { return m_SelectedOption; } + /* + template< class TBase > + void AddOption( const Q3DStudio::CString& inOptionName, TBase* inClass, + CSpecificCContextMenuPerformer::TFunction inFunction, bool inIsEnabled ) + { + AddOption( inOptionName, new CSpecificCContextMenuPerformer( inClass, + inFunction, inIsEnabled ) ); + } + */ + + virtual void Update(); + + MENUHANDLE GetMenuHandle() const { return m_Menu; } + CContextMenuPerformer *GetSelectedMenuPerformer(long inIndex); + + void EnableOptionByIndex(long inIndex, bool inEnabledState = true); + void EnableOption(const Q3DStudio::CString &inOptionName, bool inEnabledState = true); + void EnableOption(unsigned int inOptionNameStringID, bool inEnabledState = true); + +protected: + void ProcessSelection(long inIndex); + void DeletePerformers(); + + TPerformerList m_Performers; + TOptionList m_Options; + long m_SelectedOption; + MENUHANDLE m_Menu; + long m_IndexBase; ///< Base index for command ids associated with this context menu +}; + +#endif // INCLUDED_CONTEXT_MENU_H \ No newline at end of file diff --git a/src/Authoring/Studio/UI/CustomReBar.cpp b/src/Authoring/Studio/UI/CustomReBar.cpp new file mode 100644 index 00000000..31813c3b --- /dev/null +++ b/src/Authoring/Studio/UI/CustomReBar.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** 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 "CustomReBar.h" +#include "StudioPreferences.h" + +BEGIN_MESSAGE_MAP(CCustomReBar, CReBar) +//}}AFX_MSG_MAP +ON_WM_ERASEBKGND() +END_MESSAGE_MAP() + +BOOL CCustomReBar::OnEraseBkgnd(CDC *pDC) +{ + CRect theRect; + GetClientRect(&theRect); + CColor theBaseColor(CStudioPreferences::GetToolBarBaseColor()); + CBrush theBaseColorBrush( + RGB(theBaseColor.GetRed(), theBaseColor.GetGreen(), theBaseColor.GetBlue())); + CBrush *pOld = pDC->SelectObject(&theBaseColorBrush); + BOOL bRes = pDC->PatBlt(0, 0, theRect.Width(), theRect.Height(), PATCOPY); + pDC->SelectObject(pOld); // restore old brush + return bRes; +} \ No newline at end of file diff --git a/src/Authoring/Studio/UI/CustomReBar.h b/src/Authoring/Studio/UI/CustomReBar.h new file mode 100644 index 00000000..66cbf5a4 --- /dev/null +++ b/src/Authoring/Studio/UI/CustomReBar.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** 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_CUSTOMTOOLBAR_H +#define INCLUDED_CUSTOMTOOLBAR_H 1 + +#pragma once + +//============================================================================== +/** + * @class CCustomReBar overrides the Win32 CReBar simply to change the background color + */ +class CCustomReBar : public CReBar +{ +public: + CCustomReBar() {} + ~CCustomReBar() {} + + // Implementation +protected: + // Generated message map functions + //{{AFX_MSG(CCustomToolBar) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +public: + afx_msg BOOL OnEraseBkgnd(CDC *pDC); +}; + +#endif \ No newline at end of file diff --git a/src/Authoring/Studio/UI/PaletteState.cpp b/src/Authoring/Studio/UI/PaletteState.cpp new file mode 100644 index 00000000..52750593 --- /dev/null +++ b/src/Authoring/Studio/UI/PaletteState.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "PaletteState.h" +#include "Preferences.h" + +CPaletteState::CPaletteState(Q3DStudio::CString inWindowName) + : m_WindowName(inWindowName) + , m_Maximized(false) + , m_IsVisible(false) +{ +} + +CPaletteState::~CPaletteState() +{ +} + +CPt CPaletteState::GetPosition() const +{ + return m_Position; +} + +void CPaletteState::SetPosition(CPt inPosition) +{ + m_Position = inPosition; +} + +CPt CPaletteState::GetSize() const +{ + return m_Size; +} + +void CPaletteState::SetSize(CPt inSize) +{ + m_Size = inSize; +} + +bool CPaletteState::IsVisible() const +{ + return m_IsVisible; +} + +void CPaletteState::SetVisible(bool inIsVisible) +{ + m_IsVisible = inIsVisible; +} + +void CPaletteState::LoadState() +{ + RestoreDefaults(); + + CPreferences thePrefs = CPreferences::GetUserPreferences(m_WindowName); + + m_Maximized = static_cast(thePrefs.GetValue("maximized", m_Maximized)); + m_Position.x = thePrefs.GetLongValue("positionX", m_Position.x); + m_Position.y = thePrefs.GetLongValue("positionY", m_Position.y); + m_Size.x = thePrefs.GetLongValue("sizeX", m_Size.x); + m_Size.y = thePrefs.GetLongValue("sizeY", m_Size.y); + m_IsVisible = static_cast(thePrefs.GetValue("visible", m_IsVisible)); +} + +void CPaletteState::SaveState() const +{ + CPreferences thePrefs = CPreferences::GetUserPreferences(m_WindowName); + + thePrefs.SetValue("maximized", m_Maximized); + if (!m_Maximized) { + thePrefs.SetLongValue("positionX", m_Position.x); + thePrefs.SetLongValue("positionY", m_Position.y); + thePrefs.SetLongValue("sizeX", m_Size.x); + thePrefs.SetLongValue("sizeY", m_Size.y); + } + thePrefs.SetValue("visible", m_IsVisible); +} + +void CPaletteState::RestoreDefaults() +{ + CPt theDisplaySize = ::GetAvailableDisplaySize(); + CPt theInitialPos = GetDisplaySize(); + + if (m_WindowName == "Library") { + m_Position.x = theInitialPos.x; + m_Position.y = theInitialPos.y; + m_Size.x = ::dtol(theDisplaySize.x * .25); + m_Size.y = ::dtol(theDisplaySize.y * .60); + m_IsVisible = true; + } else if (m_WindowName == "Timeline") { + m_Position.x = ::dtol(theDisplaySize.x * .25) + theInitialPos.x; + m_Position.y = ::dtol(theDisplaySize.y * .60) + theInitialPos.y; + m_Size.x = ::dtol(theDisplaySize.x * .50); + m_Size.y = ::dtol(theDisplaySize.y * .40); + m_IsVisible = true; + } else if (m_WindowName == "Storage") { + m_Position.x = ::dtol(theDisplaySize.x * .75) + theInitialPos.x; + m_Position.y = ::dtol(theDisplaySize.y * .60) + theInitialPos.y; + m_Size.x = ::dtol(theDisplaySize.x * .25); + m_Size.y = ::dtol(theDisplaySize.y * .40); + m_IsVisible = true; + } else if (m_WindowName == "MainWindow") { + // m_Position.x = ::dtol( theDisplaySize.x * .25 ) + theInitialPos.x; + m_Position.x = theInitialPos.x; + m_Position.y = theInitialPos.y; + // m_Size.x = ::dtol( theDisplaySize.x * .50 ); + // m_Size.y = ::dtol( theDisplaySize.y * .60 ); + m_Size.x = ::dtol(theDisplaySize.x * 1.0); + m_Size.y = ::dtol(theDisplaySize.y * 1.0); + m_IsVisible = true; + } else if (m_WindowName == "Inspector") { + m_Position.x = theInitialPos.x; + m_Position.y = ::dtol(theDisplaySize.y * .60) + theInitialPos.y; + m_Size.x = ::dtol(theDisplaySize.x * .25); + m_Size.y = ::dtol(theDisplaySize.y * .40); + m_IsVisible = true; + } else { + m_Position.x = theInitialPos.x; + m_Position.y = ::dtol(theDisplaySize.y * .50); + m_Size.x = ::dtol(theDisplaySize.x * .25); + m_Size.y = ::dtol(theDisplaySize.y * .50); + m_IsVisible = true; + } +} + +//============================================================================= +/** +* @return Returns the resolution in pixels of the current primary display. + */ +CPt CPaletteState::GetDisplaySize() const +{ + // return CPt( 0, 0 ); + CRect theWorkArea; + SystemParametersInfo(SPI_GETWORKAREA, 0, &theWorkArea, FALSE); + return CPt(theWorkArea.left, theWorkArea.top); +} diff --git a/src/Authoring/Studio/UI/PaletteState.h b/src/Authoring/Studio/UI/PaletteState.h new file mode 100644 index 00000000..c56b48e6 --- /dev/null +++ b/src/Authoring/Studio/UI/PaletteState.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_PALETTE_STATE_H +#define INCLUDED_PALETTE_STATE_H 1 + +#pragma once + +#include "Pt.h" + +class CPaletteState +{ +public: + CPaletteState(Q3DStudio::CString inWindowName); + virtual ~CPaletteState(); + + bool IsMaximized() const { return m_Maximized; } + void SetMaximized(bool inMaximized) { m_Maximized = inMaximized; } + + CPt GetPosition() const; + void SetPosition(CPt inPosition); + + CPt GetSize() const; + void SetSize(CPt inSize); + + bool IsVisible() const; + void SetVisible(bool inIsVisible); + + void SaveState() const; + void LoadState(); + + void RestoreDefaults(); + +protected: + CPt GetDisplaySize() const; + + Q3DStudio::CString m_WindowName; + bool m_Maximized; + CPt m_Position; + CPt m_Size; + bool m_IsVisible; +}; + +#endif // INCLUDED_PALETTE_STATE_H diff --git a/src/Authoring/Studio/Utils/CmdLineParser.cpp b/src/Authoring/Studio/Utils/CmdLineParser.cpp new file mode 100644 index 00000000..2c63c16f --- /dev/null +++ b/src/Authoring/Studio/Utils/CmdLineParser.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** 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 "CmdLineParser.h" +#include "StudioObjectTypes.h" +#include "UICFile.h" +#include "UICString.h" + +// using namespace Q3DStudio; <-- Do not do this here because it will conflict with CList and make +// the template generator go blah + +//============================================================================= +/** + * Create a new Command Line Parser object. + */ +CCmdLineParser::CCmdLineParser() + : m_Silent(false) + , m_RunUnitTests(false) +{ +} + +CCmdLineParser::~CCmdLineParser() +{ +} + +//============================================================================= +/** + * If the execution mode is to open a file or execute XML tests strings then + * this will return the filename used for them. + * @return filename for file open or XML tests + */ +Q3DStudio::CString CCmdLineParser::GetFilename() const +{ + return m_Filename; +} + +//============================================================================= +/** + * Call to parse the specified parameter from the command line format into + * a format useful by the app. + * @param inParameter the name of the parameter to be parsed. + * @param inIsFlag true if the param is a flag, false if it is an argument. + */ +void CCmdLineParser::ParseParam(const Q3DStudio::CString &inParameter, bool inIsFlag) +{ + if (inIsFlag) { + if (inParameter == "t" || inParameter == "test") { + m_ExecutionQueue.push_back(TEST_CMD_LINE); + m_RunUnitTests = true; + } else if (inParameter == "silent") { + m_Silent = true; + } + } else { + m_Params.push_back(inParameter); + } +} + +//============================================================================= +/** + * Call this to parse all the command line arguments into useful info. + * This is most often called with the args from main( ). + * @param inArgc the number of argments being given. + * @param inArgv the arguments. + */ +void CCmdLineParser::ParseArguments(int inArgc, wchar_t **inArgv) +{ + m_Filename.Clear(); + m_Params.clear(); + + for (int i = 0; i < inArgc; ++i) { + bool isFlag = false; + Q3DStudio::CString theArg(inArgv[i]); + if (theArg[(long)0] == '-') { + isFlag = true; + // take off the dash + theArg = theArg.Extract(1); + } + ParseParam(theArg, isFlag); + } + + // m_Params[1]is m_Filename + // m_Params[0] is the path to the executable + if (m_Params.size() > 1) { + ConvertToLongFilename(m_Params[1], m_Filename); + } + + // Post-processing + // If there were no switches modifying m_ExecutionMode, default execution mode + // according to the file extension found on m_Filename. + if (0 == m_ExecutionQueue.size()) { + CUICFile theFile(m_Filename); + Q3DStudio::CString theExtension = "." + theFile.GetExtension(); + if (theExtension.CompareNoCase(::LoadResourceString(IDS_FILE_EXT_UIP))) + m_ExecutionQueue.push_back(OPEN_FILE); + } +} + +//============================================================================= +/** + * Get the next main mode of execution that the application should be in. + * @return EExecutionMode execution mode; END_OF_CMDS if end of queue. + */ +CCmdLineParser::EExecutionMode CCmdLineParser::PopExecutionMode() +{ + EExecutionMode theMode = END_OF_CMDS; + if (m_ExecutionQueue.size() > 0) { + theMode = m_ExecutionQueue.front(); + m_ExecutionQueue.pop_front(); + } + return theMode; +} + +//============================================================================= +/** + * Return true if the silent flag is specified. + * @return true if running in muted mode. ie. no dialogs. + */ +bool CCmdLineParser::IsSilent() const +{ + return m_Silent; +} + +//============================================================================= +/** + * Return true if running unit tests. + * @return true if running unit tests. + */ +bool CCmdLineParser::IsRunUnitTests() const +{ + return m_RunUnitTests; +} + +//============================================================================= +/** + * Converts the specified path to its long form. If no long path is found, + * this function simply returns the specified name. + * @param inSource Source filename + * @param outLongFilename Output filename + */ +void CCmdLineParser::ConvertToLongFilename(const Q3DStudio::CString &inSource, + Q3DStudio::CString &outLongFilename) const +{ +#ifdef _WIN32 + TCHAR thePathBuffer[_MAX_PATH * 2 + 1] = { + 0 + }; // make sure this char buffer is big enough for 2-byte chars + long theRet = GetLongPathName(inSource, thePathBuffer, _MAX_PATH * 2); + if (theRet != 0 && theRet <= _MAX_PATH * 2) + outLongFilename = Q3DStudio::CString(thePathBuffer); + else + outLongFilename = inSource; // No conversion +#else + outLongFilename = inSource; +#endif +} diff --git a/src/Authoring/Studio/Utils/CmdLineParser.h b/src/Authoring/Studio/Utils/CmdLineParser.h new file mode 100644 index 00000000..427930a1 --- /dev/null +++ b/src/Authoring/Studio/Utils/CmdLineParser.h @@ -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$ +** +****************************************************************************/ + +#ifndef INCLUDED_CMD_LINE_PARSER_H +#define INCLUDED_CMD_LINE_PARSER_H 1 + +#include + +#include + +class CCmdLineParser +{ +public: + enum EExecutionMode { NORMAL, OPEN_FILE, TEST_CMD_LINE, END_OF_CMDS }; + + CCmdLineParser(); + virtual ~CCmdLineParser(); + + void ParseArguments(int inArgc, wchar_t **); + + EExecutionMode PopExecutionMode(); + bool IsSilent() const; + bool IsRunUnitTests() const; + + Q3DStudio::CString GetFilename() const; + +protected: + virtual void ParseParam(const Q3DStudio::CString &inParameter, bool inIsFlag); + void ConvertToLongFilename(const Q3DStudio::CString &inSource, + Q3DStudio::CString &outLongFilename) const; + + Q3DStudio::CString m_Filename; ///< input filename for file open + bool m_Silent; ///< true if non-dialog alternative output + std::vector m_Params; ///< filenames or optional parameters + std::deque m_ExecutionQueue; ///< queue holding execution mode commands + bool m_RunUnitTests; ///< true if running unit tests +}; +#endif // INCLUDED_CMD_LINE_PARSER_H diff --git a/src/Authoring/Studio/Utils/ITickTock.h b/src/Authoring/Studio/Utils/ITickTock.h new file mode 100644 index 00000000..2a3155bc --- /dev/null +++ b/src/Authoring/Studio/Utils/ITickTock.h @@ -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$ +** +****************************************************************************/ +#pragma once +#ifndef ITICKTOCKH +#define ITICKTOCKH + +namespace Q3DStudio { +class CString; +} + +namespace UICDM { +class ISignalConnection; +} + +QT_BEGIN_NAMESPACE +class QWidget; +QT_END_NAMESPACE + +typedef std::function TTickTockProc; + +namespace Q3DStudio { +/** + * ITickTock is meant for a relatively small number of scheduled + * events that need to happen on the UI thread. Clients can cancel + * any event simply by releasing the returned shared pointer. + * Interface is completely threadsafe and the returned signal connection + * may safely outlive the interface. + */ +class ITickTock +{ +protected: + virtual ~ITickTock() {} + static ITickTock *m_Instance; + +public: + // The timer is canceled if the shared ptr deletes the signal connection. Save to call from any + // thread. + // The callback, however, (inTickTockProc) will be activated solely from the UI thread. + virtual std::shared_ptr + AddTimer(unsigned long inTime, bool inIsPeriodic, TTickTockProc inTickTockProc, + const Q3DStudio::CString &inName) = 0; + + // Called from UI thread to process all of the messages + // that have happened in the timer thread. + // Clients should not generally call this, it will be take care of for them. + // In the current implementation, MainFrm.h processes the tick tock message + // in order to call this function. + virtual void ProcessMessages() = 0; + + friend class std::shared_ptr; + + // m_Instance is set to the first tick tock created, and unset when that tick tock + // goes away. + static std::shared_ptr CreateTickTock(long inMessageID, QWidget* inTarget); + + static ITickTock &GetInstance(); +}; +} + +#endif diff --git a/src/Authoring/Studio/Utils/ImportUtils.cpp b/src/Authoring/Studio/Utils/ImportUtils.cpp new file mode 100644 index 00000000..0b3ba6a6 --- /dev/null +++ b/src/Authoring/Studio/Utils/ImportUtils.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 "ImportUtils.h" +#include "Dialogs.h" +#include "UICFileTools.h" + +namespace Q3DStudio { + +SObjectFileType ImportUtils::GetObjectFileTypeForFile(const CFilePath &inFile, + bool inCheckFileExists /*= true*/) +{ + if (inCheckFileExists && inFile.IsFile() == false) + return SObjectFileType(OBJTYPE_UNKNOWN, DocumentEditorFileType::Unknown); + + Q3DStudio::CString theExtension(inFile.GetExtension()); + theExtension.ToLower(); + + if (theExtension.Compare(CDialogs::GetImportFileExtension(), Q3DStudio::CString::ENDOFSTRING, + false)) + return SObjectFileType(OBJTYPE_GROUP, DocumentEditorFileType::Import); + else if (theExtension.Compare(CDialogs::GetMeshFileExtension(), Q3DStudio::CString::ENDOFSTRING, + false)) + return SObjectFileType(OBJTYPE_MODEL, DocumentEditorFileType::Mesh); + else if (CDialogs::IsImageFileExtension(theExtension)) + return SObjectFileType( + OBJTYPE_MODEL, OBJTYPE_IMAGE, + DocumentEditorFileType::Image); // Drag-drop image to scene will auto-map to Rectangle. + else if (theExtension.Compare(CDialogs::GetLUAFileExtension(), + Q3DStudio::CString::ENDOFSTRING, false) + || theExtension.Compare(CDialogs::GetQmlFileExtension(), + Q3DStudio::CString::ENDOFSTRING, false)) + return SObjectFileType(OBJTYPE_BEHAVIOR, DocumentEditorFileType::Behavior); + else if (CDialogs::IsFontFileExtension(theExtension)) + return SObjectFileType(OBJTYPE_TEXT, DocumentEditorFileType::Font); + else if (CDialogs::IsEffectFileExtension(theExtension)) + return SObjectFileType(OBJTYPE_EFFECT, DocumentEditorFileType::Effect); + else if (CDialogs::IsMaterialFileExtension(theExtension)) + return SObjectFileType(OBJTYPE_CUSTOMMATERIAL, DocumentEditorFileType::Material); + else if (CDialogs::IsPathFileExtension(theExtension)) + return SObjectFileType(OBJTYPE_PATH, DocumentEditorFileType::Path); + else if (CDialogs::IsPathBufferExtension(theExtension)) + return SObjectFileType(OBJTYPE_PATH, DocumentEditorFileType::Path); + else if (CDialogs::IsSoundFileExtension(theExtension)) + return SObjectFileType(OBJTYPE_SOUND, DocumentEditorFileType::Sound); + + return SObjectFileType(OBJTYPE_UNKNOWN, DocumentEditorFileType::Unknown); +} + +DocumentEditorInsertType::Enum ImportUtils::GetInsertTypeForDropType(EDROPDESTINATION inDestination) +{ + switch (inDestination) { + case EDROPDESTINATION_ON: + return DocumentEditorInsertType::LastChild; + case EDROPDESTINATION_ABOVE: + return DocumentEditorInsertType::PreviousSibling; + case EDROPDESTINATION_BELOW: + return DocumentEditorInsertType::NextSibling; + } + assert(0); + return DocumentEditorInsertType::LastChild; +} +} diff --git a/src/Authoring/Studio/Utils/ImportUtils.h b/src/Authoring/Studio/Utils/ImportUtils.h new file mode 100644 index 00000000..0a41dd9c --- /dev/null +++ b/src/Authoring/Studio/Utils/ImportUtils.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$ +** +****************************************************************************/ +#pragma once +#ifndef IMPORTUTILSH +#define IMPORTUTILSH +#include "DocumentEditorEnumerations.h" +#include "StudioObjectTypes.h" +#include "DropSource.h" + +namespace Q3DStudio { +class CFilePath; + +struct SObjectFileType +{ + EStudioObjectType m_ObjectType; // The Object Type of the File. Used to specify the result + // ObjectType when drag-drop file to Scene. + EStudioObjectType m_IconType; // The Icon Type of the File. Used for User Interface (what Icon + // to display) such as Project Palette. + DocumentEditorFileType::Enum m_FileType; // The File Type of the File. + + SObjectFileType(EStudioObjectType inObjectType, EStudioObjectType inIconType, + DocumentEditorFileType::Enum inFileType) + : m_ObjectType(inObjectType) + , m_IconType(inIconType) + , m_FileType(inFileType) + { + } + + SObjectFileType(EStudioObjectType inObjectType, DocumentEditorFileType::Enum inFileType) + : m_ObjectType(inObjectType) + , m_IconType(inObjectType) // Icon type is same as object type + , m_FileType(inFileType) + { + } +}; + +class ImportUtils +{ +public: + static SObjectFileType GetObjectFileTypeForFile(const CFilePath &inPath, + bool inCheckFileExists = true); + + static DocumentEditorInsertType::Enum GetInsertTypeForDropType(EDROPDESTINATION inDestination); +}; +} +#endif \ No newline at end of file diff --git a/src/Authoring/Studio/Utils/MouseCursor.h b/src/Authoring/Studio/Utils/MouseCursor.h new file mode 100644 index 00000000..a346d597 --- /dev/null +++ b/src/Authoring/Studio/Utils/MouseCursor.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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_MOUSE_CURSOR_H +#define INCLUDED_MOUSE_CURSOR_H 1 + +#pragma once + +#include + + +//============================================================================= +// Includes +//============================================================================= + +//============================================================================= +/** + * Cross-platform cursor class. + */ +class CMouseCursor +{ +public: + typedef long TUICMouseCursor; + + static const TUICMouseCursor CURSOR_ARROW; + static const TUICMouseCursor CURSOR_WAIT; + static const TUICMouseCursor CURSOR_RESIZE_LEFTRIGHT; + static const TUICMouseCursor CURSOR_RESIZE_UPDOWN; + static const TUICMouseCursor CURSOR_GROUP_MOVE; + static const TUICMouseCursor CURSOR_GROUP_ROTATE; + static const TUICMouseCursor CURSOR_GROUP_SCALE; + static const TUICMouseCursor CURSOR_ITEM_MOVE; + static const TUICMouseCursor CURSOR_ITEM_ROTATE; + static const TUICMouseCursor CURSOR_ITEM_SCALE; + static const TUICMouseCursor CURSOR_EDIT_CAMERA_PAN; + static const TUICMouseCursor CURSOR_EDIT_CAMERA_ROTATE; + static const TUICMouseCursor CURSOR_EDIT_CAMERA_ZOOM; + static const TUICMouseCursor CURSOR_BLANK; + static const TUICMouseCursor CURSOR_DROP_INVALID; + static const TUICMouseCursor CURSOR_DROP_MOVE; + static const TUICMouseCursor CURSOR_DROP_COPY; + static const TUICMouseCursor CURSOR_IBEAM; + + CMouseCursor(); + virtual ~CMouseCursor(); + QCursor GetHandle(); + void Show(); + void Hide(); + void SetCursorPos(long inXPos, long inYPos); + bool Load(TUICMouseCursor inCursor); + +protected: + void Destroy(); + + QCursor m_Handle; + +private: + bool m_IsThemeCursor; + short m_ThemeCursor; +}; + +#endif // INCLUDED_MOUSE_CURSOR_H diff --git a/src/Authoring/Studio/Utils/ResourceCache.cpp b/src/Authoring/Studio/Utils/ResourceCache.cpp new file mode 100644 index 00000000..5a32ec18 --- /dev/null +++ b/src/Authoring/Studio/Utils/ResourceCache.cpp @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** 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 "ResourceCache.h" +#include "MouseCursor.h" +#include "StudioUtils.h" + +#include + +//============================================================================= +/** + * Constructor + */ +CResourceCache::CResourceCache() +{ +} + +//============================================================================= +/** + * Destructor: releases all loaded resources. + */ +CResourceCache::~CResourceCache() +{ + Clear(); +} + +//============================================================================= +/** + * Returns a default instance of the resource cache so that the whole application + * can use the same cache if desired. + * @return Handle to the default instance of the cache + */ +CResourceCache *CResourceCache::GetInstance() +{ + static CResourceCache theCache; + return &theCache; +} + +//============================================================================= +/** + * Retrieves a bitmap image of the specified name. Currently only accepts .png + * files. + * @param inName Name of the bitmap file to be fetched + * @return Pointer to a bitmap object or NULL if the image could not be loaded + */ +QPixmap CResourceCache::GetBitmap(const QString &inName) +{ + QPixmap theImage; + + // If our image name is not empty, then lets get it... + if (!inName.isEmpty()) { + TImageMap::iterator thePos = m_Images.find(inName); + if (thePos != m_Images.end()) { + theImage = thePos->second; + } else { + const QString resPath = QString("%1%2").arg(resourceImagePath(), inName); + if (theImage.load(resPath)) { + m_Images[inName] = theImage; + } else { + qWarning() << Q_FUNC_INFO << "missing image at path:" << resPath; + } + } + } + return theImage; +} + +//============================================================================= +/** + * Retrieves the specified cursor resource. The cursor is loaded if necessary + * otherwise a previously loaded cursor of the same ID is returned. + * @param inResourceID ID of the cursor to be loaded (see SCursor.h) + * @return Pointer to the cursor, or NULL if the cursor could not be loaded + */ +QCursor CResourceCache::GetCursor(CMouseCursor::TUICMouseCursor inResourceID) +{ + CMouseCursor *theCursor = NULL; + CMouseCursor::TUICMouseCursor theKey = inResourceID; + + TCursorMap::iterator thePos = m_Cursors.find(theKey); + if (thePos != m_Cursors.end()) { + theCursor = thePos->second; + } else { + theCursor = new CMouseCursor(); + if (theCursor->Load(inResourceID)) + m_Cursors[theKey] = theCursor; + else { + delete theCursor; + theCursor = nullptr; + } + } + + return theCursor ? theCursor->GetHandle() : QCursor(); +} + +//============================================================================= +/** + * Clears all the maps of resources and deletes any associated resources. + * Called by the destructor. + */ +void CResourceCache::Clear() +{ + m_Images.clear(); + + TCursorMap::iterator theCursorPos = m_Cursors.begin(); + for (; theCursorPos != m_Cursors.end(); ++theCursorPos) { + CMouseCursor *theCursor = theCursorPos->second; + delete theCursor; + } + m_Cursors.clear(); +} diff --git a/src/Authoring/Studio/Utils/ResourceCache.h b/src/Authoring/Studio/Utils/ResourceCache.h new file mode 100644 index 00000000..4b2f0c39 --- /dev/null +++ b/src/Authoring/Studio/Utils/ResourceCache.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** 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_RESOURCE_CACHE_H +#define INCLUDED_RESOURCE_CACHE_H 1 + +#pragma once + +#include "MouseCursor.h" +#include "UICString.h" +#include + +#include +#include + +class CResImage; + +class CResourceCache +{ + typedef std::map TImageMap; + typedef std::map TCursorMap; + +public: + CResourceCache(); + virtual ~CResourceCache(); + + static CResourceCache *GetInstance(); + + QPixmap GetBitmap(const QString &inName); + QCursor GetCursor(CMouseCursor::TUICMouseCursor inResourceID); + + void Clear(); + +protected: + TImageMap m_Images; + TCursorMap m_Cursors; +}; +#endif // INCLUDED_RESOURCE_CACHE_H diff --git a/src/Authoring/Studio/Utils/StringLoader.cpp b/src/Authoring/Studio/Utils/StringLoader.cpp new file mode 100644 index 00000000..73a5324f --- /dev/null +++ b/src/Authoring/Studio/Utils/StringLoader.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** 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 "Strings.h" +#include "StringLoader.h" +#include +#include + +CStringLoader CStringLoader::s_GlobalInstance; + +CStringLoader::CStringLoader() + : m_Strings(nullptr) + , m_StringCount(0) +{ +} + +CStringLoader::~CStringLoader() +{ + UnloadResourceStrings(); +} + +//============================================================================= +/** + * Static function to load the string resource specified by inStringID. + * inStringID should have been specified in the Resource.h header file. + * This will load the string from the global string resource object. + */ +Q3DStudio::CString CStringLoader::LoadString(long inStringID) +{ + return s_GlobalInstance.LoadResourceString(inStringID); +} + +//============================================================================= +/** + * Load the string resource specified by inStringID. + * inStringID should have been specified in the Resource.h header file. + * @param inID the ID of the string to be loaded. + * @return theString specified by inStringID. + */ +Q3DStudio::CString CStringLoader::LoadResourceString(long inStringID) +{ + Q3DStudio::CString theName; + // Make sure we aren't going off into la-la land. + if (inStringID > 0 && inStringID < m_StringCount) { + theName = m_Strings[inStringID]; + } + return theName; +} + +//============================================================================= +/** + * Load the string resources from the specified directory into the global table. + * All .stro files in the directory will be processed for strings. + * @param inDirectory the directory that should be read for strings. + */ +void CStringLoader::LoadStrings(const CUICFile &inDirectory) +{ + s_GlobalInstance.LoadResourceStrings(inDirectory); +} + +//============================================================================= +/** + * Load the string resources from the specified directory into this string table. + * All .stro files in the directory will be processed for strings. + * @param inDirectory the directory that should be read for strings. + */ +void CStringLoader::LoadResourceStrings(const CUICFile &inDirectory) +{ + UnloadResourceStrings(); + + // Sure hope we don't get an absolute ton of strings here... + m_Strings = new Q3DStudio::CString[STRING_RESOURCE_COUNT + 1]; + m_StringCount = STRING_RESOURCE_COUNT; + + Q3DStudio::CString theExtension = ".stro"; + + // Go through all the files in the directory and process them. + CFileIterator theFiles = inDirectory.GetSubItems(); + for (; !theFiles.IsDone(); ++theFiles) { + CUICFile theFile = theFiles.GetCurrent(); + Q3DStudio::CString theFilename = theFile.GetAbsolutePath(); + // Only process .stro files. + if (theFilename.Find(theExtension) == theFilename.Length() - theExtension.Length()) { + QFile file(theFilename.toQString()); + file.open(QFile::ReadOnly); + QXmlStreamReader reader(&file); + while (!reader.atEnd()) { + reader.readNextStartElement(); + if (reader.name() == "string") { + Q3DStudio::CString theValue; + long theIndex = -1; + for (auto attrib : reader.attributes()) { + if (attrib.name() == "value") + theValue = attrib.value().toUtf8().constData(); + else if (attrib.name() == "ID") + theIndex = attrib.value().toInt(); + } + if (theIndex > 0 && theIndex < STRING_RESOURCE_COUNT) { + theValue.Replace("\\n", "\n"); + theValue.Replace("\\t", "\t"); + m_Strings[theIndex] = theValue; + } + } + } + } + } +} + +void CStringLoader::UnloadStrings() +{ + s_GlobalInstance.UnloadResourceStrings(); +} + +void CStringLoader::UnloadResourceStrings() +{ + delete[] m_Strings; + m_Strings = nullptr; + m_StringCount = 0; +} + +Q3DStudio::CString LoadResourceString(long inID) +{ + return CStringLoader::LoadString(inID); +} diff --git a/src/Authoring/Studio/Utils/StringLoader.h b/src/Authoring/Studio/Utils/StringLoader.h new file mode 100644 index 00000000..69595566 --- /dev/null +++ b/src/Authoring/Studio/Utils/StringLoader.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** 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_STRING_LOADER_H +#define INCLUDED_STRING_LOADER_H 1 +#pragma once + +#include "UICFile.h" + +class CStringLoader +{ +public: + CStringLoader(); + virtual ~CStringLoader(); + + static Q3DStudio::CString LoadString(long inStringID); + static void LoadStrings(const CUICFile &inDirectory); + static void UnloadStrings(); + + Q3DStudio::CString LoadResourceString(long inStringID); + void LoadResourceStrings(const CUICFile &inDirectory); + void UnloadResourceStrings(); + +protected: + Q3DStudio::CString *m_Strings; + long m_StringCount; + + static CStringLoader s_GlobalInstance; +}; + +Q3DStudio::CString LoadResourceString(long inID); + +#endif // INCLUDED_STRING_LOADER_H diff --git a/src/Authoring/Studio/Utils/StudioUtils.cpp b/src/Authoring/Studio/Utils/StudioUtils.cpp new file mode 100644 index 00000000..34522198 --- /dev/null +++ b/src/Authoring/Studio/Utils/StudioUtils.cpp @@ -0,0 +1,229 @@ +/**************************************************************************** +** +** 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 "CoreUtils.h" +#include "StudioPreferences.h" +#include "StudioClipboard.h" +#include "Pt.h" + +#include +#include +#include +#include +#include +#include + +//============================================================================== +/** + * FormatTimeString: Format a time string. + * @param inTimeMS Time in milliseconds. + * @return The formatted time string in MM:SS:MS format. + */ +Q3DStudio::CString FormatTimeString(long inTimeMS) +{ + BOOL theNegativeFlag = (inTimeMS < 0); + long theTimeMS = abs(inTimeMS); + Q3DStudio::CString theTimeString; + long theMM, theSS; + + // Format the time in MM:SS:MS format + + // Get the MM value + theMM = theTimeMS / 60000; + theTimeMS -= (theMM * 60000); + + // Get the SS value + theSS = theTimeMS / 1000; + theTimeMS -= (theSS * 1000); + + // Remainder is MS value + + // Format the string + theTimeString.Format(_UIC("%d:%0.2d.%0.2d"), theMM, theSS, theTimeMS / 10); + + // If the original time was negative, append the "-" to the front of the time string. + if (theNegativeFlag) { + theTimeString.Insert(0, "-"); + } + + return theTimeString; +} + +//============================================================================== +/** + * Checks a string to determine if it is numeric. + * @param inString String to check for all numeric characters. + * @return TRUE if the string is numeric. + */ +bool IsNumericString(const Q3DStudio::CString &inString) +{ + Q3DStudio::CString theNumbers = "0123456789"; + long theLoop; + bool theNumericFlag = true; + + // Iterate through the entire string + for (theLoop = 0; theLoop < inString.Length() && theNumericFlag; theLoop++) { + // Check each character for being numeric + if (theNumbers.Find(inString.Extract(theLoop, 1)) == Q3DStudio::CString::ENDOFSTRING) + theNumericFlag = false; + } + + return theNumericFlag; +} + +//============================================================================= +/** + * @return The available resolution in pixels of the display index "screen" + * (minus the Dock/Taskbar, etc.). Default is current primary display. + */ +QSize GetAvailableDisplaySize(int screen) +{ + return QApplication::desktop()->availableGeometry(screen).size(); +} + +//============================================================================= +/** +* @return The total resolution in pixels of the display index "screen". +* Default is the current primary display. + */ +QSize GetDisplaySize(int screen) +{ + return QApplication::desktop()->screenGeometry(screen).size(); + +} + +//============================================================================= +/** +* @return The index of the screen containing "widget". + */ +int getWidgetScreen(QWidget *widget) +{ + return QApplication::desktop()->screenNumber(widget); +} + +//============================================================================= +/** + * Helper function to adjust the point for the color popup dialog so that it + * ends up in the right place. Adjust the given point if it is near the left + * or bottom part of the screen. + * @param ioPoint upper-left corner of the color popup dialog; will be adjust if necessary on return + */ +void TranslatePoint(QPoint &ioPoint, const QPoint &inSize) +{ + long theBuffer = 10; // Just because the taskbar seems to overlap the dialog by a little bit + QPoint theDlgSize(150, 260); // Size of color popup dialog - note that it's hard-coded + QSize theScreenSize = GetAvailableDisplaySize(-1); + long theVertOffset = theDlgSize.y() - inSize.y(); + long theHorizOffset = theDlgSize.x(); + + // If the point is too close to both the left side and the bottom of the screen, adjust both the + // x and y values + if ((ioPoint.y() > theScreenSize.height() - theVertOffset - theBuffer) + && (ioPoint.x() >= theScreenSize.width() - theHorizOffset)) { + + ioPoint.setX(ioPoint.x() - (theHorizOffset + inSize.x())); + ioPoint.setY(ioPoint.y() - theVertOffset); + } + // If the point is just too close to the bottom of the screen, adjust the y value + else if (ioPoint.y() > theScreenSize.height() - theVertOffset - theBuffer) + ioPoint.setY(ioPoint.y() - theVertOffset); + // If the point is just too close to the left side of the screen, adjust the x value + else if (ioPoint.x() >= theScreenSize.width() - theHorizOffset) + ioPoint.setX(ioPoint.x() - (theHorizOffset + inSize.x())); +} + +long TimeToPos(long inTime, double inTimeRatio) +{ + return ::dtol(inTime * inTimeRatio) + CStudioPreferences::GUTTER_SIZE; +} + +long TimeToPos(double inTime, double inTimeRatio) +{ + return ::dtol(inTime * inTimeRatio) + CStudioPreferences::GUTTER_SIZE; +} + +long PosToTime(long inPos, double inTimeRatio) +{ + return ::dtol((inPos - CStudioPreferences::GUTTER_SIZE) / inTimeRatio); +} + +//============================================================================= +/** + * opens the url in the web browser + * + * @param inURL + * the URL to open + * + * @return void + */ +void ShowURLInBrowser(const Q3DStudio::CString &inURL) +{ + QDesktopServices::openUrl(QUrl(inURL.toQString())); +} + +QString resourcePath() +{ + return QStringLiteral(":/res"); +} + +QString resourceImagePath() +{ + return QStringLiteral(":/images/"); +} + +QString resourceImageUrl() +{ + return QStringLiteral("qrc:/images/"); +} + +// Returns the qml import path required for binary installations +QString qmlImportPath() +{ + QString extraImportPath(QStringLiteral("%1/qml")); + return extraImportPath.arg(QApplication::applicationDirPath()); +} + +qreal devicePixelRatio() +{ + static qreal pixelRatio = 0.0; + if (Q_UNLIKELY(pixelRatio == 0.0)) { + const QWindowList list = QGuiApplication::topLevelWindows(); + if (list.size() > 0) + pixelRatio = list[0]->devicePixelRatio(); + } + return pixelRatio; +} diff --git a/src/Authoring/Studio/Utils/StudioUtils.h b/src/Authoring/Studio/Utils/StudioUtils.h new file mode 100644 index 00000000..4e248bb3 --- /dev/null +++ b/src/Authoring/Studio/Utils/StudioUtils.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** 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_STUDIO_UTILS_H +#define INCLUDED_STUDIO_UTILS_H 1 + +#pragma once + +#include "UICString.h" +#include +#include + +//============================================================================== +// Functions +//============================================================================== +Q3DStudio::CString FormatTimeString(long inTimeMS); +bool IsNumericString(Q3DStudio::CString inString); + +QSize GetAvailableDisplaySize(int screen = -1); +QSize GetDisplaySize(int screen = -1); +void TranslatePoint(QPoint &ioPoint, const QPoint &inSize); + +long TimeToPos(long inTime, double inTimeRatio); +long TimeToPos(double inTime, double inTimeRatio); +long PosToTime(long inPos, double inTimeRatio); + +void ShowURLInBrowser(Q3DStudio::CString inURL); + +QString resourceImagePath(); +QString resourceImageUrl(); + +QString resourcePath(); + +QString qmlImportPath(); + +qreal devicePixelRatio(); + +int getWidgetScreen(QWidget *widget); + +#endif // INCLUDED_STUDIO_UTILS_H diff --git a/src/Authoring/Studio/Utils/SystemPreferences.cpp b/src/Authoring/Studio/Utils/SystemPreferences.cpp new file mode 100644 index 00000000..85e5a58b --- /dev/null +++ b/src/Authoring/Studio/Utils/SystemPreferences.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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 "CColor.h" +#include "SystemPreferences.h" + +#include +#include + +//============================================================================= +/** + * Destructor + */ +CSystemPreferences::~CSystemPreferences() +{ +} + +//============================================================================= +/** + * Retrieves the system preferred background color. Example use would be for + * the fill color of a button. + */ +QColor CSystemPreferences::GetSystemBackgroundColor() +{ + const auto palette = QApplication::palette(); + return palette.color(QPalette::Active, QPalette::Button); +} + +//============================================================================= +/** + * Returns the color used by the system to indicate that an item is selected. + */ +QColor CSystemPreferences::GetSelectedItemColor() +{ + const auto palette = QApplication::palette(); + return palette.color(QPalette::Active, QPalette::Highlight); +} + +//============================================================================= +/** + * Returns the color of selected text to be displayed on top of GetSelectedItemColor(). + */ +QColor CSystemPreferences::GetSelectedTextColor() +{ + const auto palette = QApplication::palette(); + return palette.color(QPalette::Active, QPalette::HighlightedText); +} + +//============================================================================= +/** + * Supposed to get whether or not anti aliasing should be enabled for a specified + * font size, but the Theme does not seem to include any data on it. If the + * theme starts working in a later release of the OS then this should work. + */ +bool CSystemPreferences::IsFontAntiAliasing(float inFontSize) +{ + Q_UNUSED(inFontSize); + return false; +} + +//============================================================================= +/** + * Scroll bars contain two arrows (up/down or left/right). These can be located + * on either end of the scroll bar, or located next to each other at one end. On + * Mac OS X, this is a system preference. + * @return true if the scroll bar arrows should be next to each other, at one end of the scroll bar + */ +bool CSystemPreferences::AreScrollArrowsAdjacent() +{ + return false; +} diff --git a/src/Authoring/Studio/Utils/SystemPreferences.h b/src/Authoring/Studio/Utils/SystemPreferences.h new file mode 100644 index 00000000..2d72780e --- /dev/null +++ b/src/Authoring/Studio/Utils/SystemPreferences.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** 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_SYSTEM_PREFERENCES_H +#define INCLUDED_SYSTEM_PREFERENCES_H 1 + +#pragma once + +class CColor; + +class CSystemPreferences +{ +public: + CSystemPreferences(); + virtual ~CSystemPreferences(); + static QColor GetSystemBackgroundColor(); + static QColor GetSelectedItemColor(); + static QColor GetSelectedTextColor(); + static bool IsFontAntiAliasing(float inFontSize); + static bool AreScrollArrowsAdjacent(); +}; + +#endif // INCLUDED_SYSTEM_PREFERENCES_H diff --git a/src/Authoring/Studio/Utils/TickTock.cpp b/src/Authoring/Studio/Utils/TickTock.cpp new file mode 100644 index 00000000..dcf6eb8a --- /dev/null +++ b/src/Authoring/Studio/Utils/TickTock.cpp @@ -0,0 +1,312 @@ +/**************************************************************************** +** +** 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 "ITickTock.h" +#include "UICDMSignals.h" +#include "Thread.h" +#include "Mutex.h" +#include "Conditional.h" +#include "StandardExtensions.h" +#include + +#include +#include +#include + +using namespace Q3DStudio; +using Q3DStudio::CString; +using namespace UICDM; +using namespace std; + +namespace { + +struct TickTockImpl; + +struct TickTockItem : public ISignalConnection +{ + TTickTockProc m_Callback; + bool m_IsPeriodic; + unsigned long m_Time; + quint64 m_NextTime; + CString m_Name; + TickTockImpl *m_Impl; + + TickTockItem(TTickTockProc inCallback, bool inPeriodic, unsigned long inTime, + quint64 inNextTime, const CString &inName, TickTockImpl &inImpl) + : m_Callback(inCallback) + , m_IsPeriodic(inPeriodic) + , m_Time(inTime) + , m_NextTime(inNextTime) + , m_Name(inName) + , m_Impl(&inImpl) + { + } + // Implemented below to access TickTockImpl API + virtual ~TickTockItem(); + + // Called when our tick tock impl is through with us. + // We cannot access the tick tock impl after this as + // it could cause a crash + void Release() { m_Impl = nullptr; } + + void Signal() + { + if (m_Impl) + m_Callback(); + } + bool operator<(const TickTockItem &inOther) const { return m_NextTime < inOther.m_NextTime; } +}; + +struct TickTockDerefCompare +{ + bool operator()(const TickTockItem *lhs, const TickTockItem *rhs) { return *lhs < *rhs; } +}; + +typedef vector TTockList; + +/** + * Struct that implements the ITickTock interface via a thread that runs + * and schedules information and a message that is sent back in order to + * process that schedule information and send out signals on the UI thread. + */ +struct TickTockImpl : public ITickTock, public CRunnable +{ + // Mutex to protect our internal datastructures + // Mainly m_Tockers and m_SignalledTockers + CMutex m_Mutex; + // Our thread + CThread m_Thread; + // Event to wake up schedule thread; used to keep thread from + // spinning till next event. + CConditional m_Event; + + // The sorted list (by m_NextTime) of tick tock signals + TTockList m_Tockers; + // The list of signals that are past their time and need to be sent. + TTockList m_SignalledTockers; + // True if the thread is running and we want it to continue. + volatile bool m_IsRunning; + // Message to fire into the window in order to get our notifications + // processed on the UI thread + long m_MessageID; + // Target window that we use in order to fire events and get processing + // done back on the UI thread from the schedule thread. + QWidget *m_Target; + + TickTockImpl(long inMessageID, QWidget *inTarget) + : m_Thread(this, "ITickTock", NULL, false) + , m_IsRunning(false) + , m_MessageID(inMessageID) + , m_Target(inTarget) + { + } + + virtual void Initialize() + { + m_IsRunning = true; + m_Thread.Start(); + } + + virtual ~TickTockImpl() + { + if (m_Instance == this) + m_Instance = nullptr; + { + CMutex::Scope __mutexScope(&m_Mutex); + UnsafeReleaseTockers(m_Tockers); + UnsafeReleaseTockers(m_SignalledTockers); + } + + if (m_IsRunning) { + m_IsRunning = false; + // Wake up the thread to notify it to exit + m_Event.Notify(); + // Wait for the thread to exit. + m_Thread.Join(); + } + } + + TSignalConnectionPtr AddTimer(unsigned long inTime, bool inIsPeriodic, + TTickTockProc inTickTockProc, + const Q3DStudio::CString &inName) override + { + // Lock down so we don't conflict with the timer thread. + CMutex::Scope __mutexScope(&m_Mutex); + + std::shared_ptr retval = + std::make_shared(inTickTockProc, inIsPeriodic, inTime, + QDateTime::currentMSecsSinceEpoch() + inTime, inName, std::ref(*this)); + if (inTime > 0) { + UnsafeInsertTimer(*retval); + } else { + assert(inIsPeriodic == false); + m_SignalledTockers.push_back(retval.get()); + } + m_Event.Notify(); + + return retval; + } + + void RemoveTimer(TickTockItem &inItem) + { + CMutex::Scope __mutexScope(&m_Mutex); + UnsafeRemoveTimer(inItem, m_Tockers); + UnsafeRemoveTimer(inItem, m_SignalledTockers); + } + + //============================================================================= + /** + * Call from the main processing thread to process any existing messages. + * This should be called when a message of the type specified in the constructor + * is recieved. This will call all the functors on the timers that have + * triggered. + */ + void ProcessMessages() override + { + quint64 theCurrentTime = QDateTime::currentMSecsSinceEpoch(); + + CMutex::Scope __mutexScope(&m_Mutex); + // Go through all the timers looking for expired ones + for (TTockList::iterator theTocks = m_SignalledTockers.begin(), + end = m_SignalledTockers.end(); + theTocks != end; ++theTocks) { + TickTockItem *theTock = (*theTocks); + // If this item hasn't been released in another thread. + if (theTock->m_Impl) { + theTock->Signal(); + + // If it is periodic, re-add it. + if (theTock->m_IsPeriodic == true) { + theTock->m_NextTime = theCurrentTime + theTock->m_Time; + UnsafeInsertTimer(*theTock); + } + // If it isn't, then we forget about it. The client's have a shared-ptr + // to the object so it will get deleted eventually, it just isn't any of + // our business any more + else + theTock->Release(); + } + } + + m_SignalledTockers.clear(); + m_Event.Notify(); + } + + void Run(void *) override + { + unsigned long theNextTime = (unsigned long)-1; + // Stay in this loop until the running flag is turned off on the constructor. + while (m_IsRunning) { + // Wait for either the next time or the change notification + m_Event.Wait(theNextTime); + + CMutex::Scope __mutexScope(&m_Mutex); + + // Get the amount of time this should sleep for. + theNextTime = (unsigned long)-1; + quint64 theCurrentTime = QDateTime::currentMSecsSinceEpoch(); + // We know that m_Tocks is sorted by m_NextTime. + // So we run through it linearly, transferring singalled items + // into the signalled vector. + size_t idx = 0, end = m_Tockers.size(); + for (; idx < end; ++idx) { + TickTockItem *item(m_Tockers[idx]); + if (item->m_NextTime <= theCurrentTime && item->m_Impl != nullptr) { + m_SignalledTockers.push_back(item); + } else + break; + } + // We then remove all signalled items. + if (m_Tockers.empty() == false) + m_Tockers.erase(m_Tockers.begin(), m_Tockers.begin() + idx); + + // And we reset next time to the difference between the current time + // and the first tock's next time. + if (m_Tockers.empty() == false) { + assert(m_Tockers.front()->m_NextTime > theCurrentTime); + theNextTime = m_Tockers.front()->m_NextTime - theCurrentTime; + } + + if (m_SignalledTockers.empty() == false) { + // Send the async notification that timers have expired. + qApp->postEvent(m_Target, new QTimerEvent(m_MessageID)); + } + } + } + +private: + //////////////////////////////////////////////////////////////// + // Unsafe functions are functions that require the mutex locked + // in order to function correctly + //////////////////////////////////////////////////////////////// + void UnsafeInsertTimer(TickTockItem &inItem) + { + binary_sort_insert_unique(m_Tockers, &inItem, TickTockDerefCompare()); + } + + void UnsafeReleaseTockers(TTockList &inTockers) + { + for (size_t idx = 0, end = inTockers.size(); idx < end; ++idx) + inTockers[idx]->Release(); + inTockers.clear(); + } + + // Unsafe means we don't have the mutex + void UnsafeRemoveTimer(TickTockItem &inItem, TTockList &ioList) + { + TTockList::iterator theTimer = std::find(ioList.begin(), ioList.end(), &inItem); + if (theTimer != ioList.end()) + ioList.erase(theTimer); + } +}; + +TickTockItem::~TickTockItem() +{ + if (m_Impl != NULL) + m_Impl->RemoveTimer(*this); + m_Impl = NULL; +} +} + +ITickTock *ITickTock::m_Instance(NULL); + +std::shared_ptr ITickTock::CreateTickTock(long inMessageID, QWidget *inWnd) +{ + std::shared_ptr theTickTock( + std::make_shared(inMessageID, std::ref(inWnd))); + theTickTock->Initialize(); + if (m_Instance == NULL) + m_Instance = theTickTock.get(); + return theTickTock; +} + +ITickTock &ITickTock::GetInstance() +{ + return *m_Instance; +} diff --git a/src/Authoring/Studio/Workspace/Dialogs.h b/src/Authoring/Studio/Workspace/Dialogs.h new file mode 100644 index 00000000..012ce98f --- /dev/null +++ b/src/Authoring/Studio/Workspace/Dialogs.h @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2001 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_DIALOGS_H +#define INCLUDED_DIALOGS_H 1 + +#pragma once + +//============================================================================= +// Includes +//============================================================================= +#include "UICFile.h" +#include "StudioObjectTypes.h" +#include "UICMessageBox.h" +//#include "MultilineEditDlg.h" +#include "UICFileTools.h" +#include "CColor.h" +#include + +//============================================================================= +// Forwards +//============================================================================= +class IDoc; +class CStudioApp; +class CControl; +class CDialogControl; +class IProgressCallback; + +class CProgressPalette; + +class CDialogs +{ +public: + enum ESavePromptResult { + CANCEL_OPERATION, + CONTINUE_NO_SAVE, + SAVE_FIRST, + }; + + CDialogs(bool inShowGUI = true); + virtual ~CDialogs(); + + void DisplayAssetDeleteFailed(); + void DisplayRefreshResourceFailed(const Q3DStudio::CString &inResourceName, + const Q3DStudio::CString &inDescription); + QString ConfirmRefreshModelFile(const QString &inOriginalPath); + + // This is not an appropriate place for these, but better + // in an inappropriate place than duplicated + static const char *GetDAEFileExtension(); + static const char *GetFbxFileExtension(); + // Null terminated list + static const char **GetImgFileExtensions(); + static const char *GetImportFileExtension(); + static const char *GetMeshFileExtension(); + static const char *GetLUAFileExtension(); + static const char *GetQmlFileExtension(); + static const char **GetFontFileExtensions(); + static const char **GetEffectFileExtensions(); + static const char **GetMaterialFileExtensions(); + static const char **GetSoundFileExtensions(); + static bool IsImageFileExtension(const char *inExt); + static bool IsFontFileExtension(const char *inExt); + static bool IsEffectFileExtension(const char *inExt); + static bool IsMaterialFileExtension(const char *inExt); + static bool IsSoundFileExtension(const char *inExt); + + static const wchar_t *GetWideDAEFileExtension(); + static const wchar_t *GetWideFbxFileExtension(); + static const wchar_t *GetWideImportFileExtension(); + static const wchar_t *GetWideMeshFileExtension(); + static const wchar_t *GetWideLUAFileExtension(); + static const wchar_t **GetWideFontFileExtensions(); + static const wchar_t **GetWideImgFileExtensions(); + static const wchar_t **GetWideEffectFileExtensions(); + static const wchar_t **GetWideMaterialFileExtensions(); + static const wchar_t **GetWideSoundFileExtensions(); + static bool IsImageFileExtension(const wchar_t *inExt); + static bool IsFontFileExtension(const wchar_t *inExt); + static bool IsEffectFileExtension(const wchar_t *inExt); + static bool IsMaterialFileExtension(const wchar_t *inExt); + static bool IsPathFileExtension(const wchar_t *inExt); + static bool IsPathBufferExtension(const wchar_t *inExt); + static bool IsSoundFileExtension(const wchar_t *inExt); + + CUICFile GetExportChoice(const Q3DStudio::CString &inExtension, + const Q3DStudio::CString &inDefaultName); + + std::pair GetSaveAsChoice(const Q3DStudio::CString &inDialogTitle = "", + bool inFilenameUntitled = false); + // Returns pair of file along with a boolean indicating the state of the create + // new directory checkbox. + std::pair + GetNewDocumentChoice(const Q3DStudio::CString &inInitialDirectory = Q3DStudio::CString()); + CUICFile GetFileOpenChoice(const Q3DStudio::CString &inInitialDirectory = Q3DStudio::CString()); + + void DisplayImportFailed(const QUrl &inURL, const QString &inDescription, + bool inWarningsOnly); + void DisplayLoadingPresentationFailed(const CUICFile &inPresentation, long inErrorIDS = -1); + void DisplaySavingPresentationFailed(); + void DisplaySaveReadOnlyFailed(const CUICFile &inSavedLocation); + CUICMessageBox::EMessageBoxReturn DisplayMessageBox(const Q3DStudio::CString &inTitle, + const Q3DStudio::CString &inText, + CUICMessageBox::EMessageBoxIcon inIcon, + bool inShowCancel); + int DisplayChoiceBox(const Q3DStudio::CString &inTitle, const Q3DStudio::CString &inText, + int inIcon); + void DisplayKnownErrorDialog(const Q3DStudio::CString &inErrorText); + + bool LocateFileReference(CUICFile &outFile, long inFileType); + bool LocateFolderReference(CUICFile &outFile); + bool BrowseForFolderDialog(CUICFile &outFile, Q3DStudio::CString inDefaultDir, + Q3DStudio::CString inDialogTitle); + + ESavePromptResult PromptForSave(); + bool PromptForKeyframeInterpolation(float &ioEaseIn, float &ioEaseOut); + + bool ConfirmRevert(); + + void DisplayProgressScreen(const Q3DStudio::CString &inActionText, + const Q3DStudio::CString &inFileName, + const Q3DStudio::CString &inWindowTitle); + void DestroyProgressScreen(); + + bool PromptObjectTimebarColor(CColor &ioColor); + void DisplayProfilingStatistics(); + /*void DisplayMultilineTextEdit(Q3DStudio::CString &ioText, + CMultilineEditDlg::INotification *inNotifiction = NULL);*/ + IProgressCallback *GetProgressScreen() const; + + void DisplayEnvironmentVariablesError(const Q3DStudio::CString &inErrorMessage); + + Q3DStudio::CString GetFilePathChoice(const Q3DStudio::CString &inFileExtensionFilter, + const Q3DStudio::CString &inDefault, + const Q3DStudio::CString *inDialogTitle = NULL); + void ResetSettings(const Q3DStudio::CString &inCurrentDocPath = ""); + + bool DisplayResetKeyframeValuesDlg(); + void DisplayPasteFailed(); + + static void DisplayGLVersionError(const Q3DStudio::CString &inGLVersion, + const Q3DStudio::CString &inMinVersion); + static void DisplayGLVersionWarning(const Q3DStudio::CString &inGLVersion, + const Q3DStudio::CString &inRecommendedVersion); + +protected: + QString CreateAllowedTypesString(long inFileTypeFilter, bool inForImport); + static void DisplayGLVersionDialog(const Q3DStudio::CString &inGLVersion, + const Q3DStudio::CString &inRecommendedVersion, + bool inError); + +#ifdef WIN32 + CProgressPalette *m_ProgressPalette; +#endif + bool m_ShowGUI; + + Q3DStudio::CString m_LastSaveFile; ///< Path to the file was previously saved +}; +#endif // INCLUDED_DIALOGS_H diff --git a/src/Authoring/Studio/Workspace/Views/Views.h b/src/Authoring/Studio/Workspace/Views/Views.h new file mode 100644 index 00000000..52b075e0 --- /dev/null +++ b/src/Authoring/Studio/Workspace/Views/Views.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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_VIEWS_H +#define INCLUDED_VIEWS_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +//============================================================================== +// Forwards +//============================================================================== +class CMainFrame; +class CStudioApp; +class CHotKeys; +class CStudioPaletteBar; +class CStudioDialog; +#ifdef WIN32 +class CRuntimeClass; +class CFrameWnd; +#endif + +#include + +//============================================================================== +// Class +//============================================================================== + +class CViews +{ +public: + CViews(CStudioApp *inStudioApp); + virtual ~CViews(); + + // Implementation + void CreateViews(); + void DestroyViews(); + + // Keyboard + void RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler); + + // Main Frame + CMainFrame *GetMainFrame(); // ONLY THE APP SHOULD USE THIS FUNCTION- ABSOLUTELY NO ONE ELSE!!!! + + void RecheckMainframeSizingMode(); + +#ifdef WIN32 + static void CreatePaletteAndView(CRuntimeClass *inClass, CStudioPaletteBar *inPalette, + CFrameWnd *inParent, Q3DStudio::CString inWindowTitle); + static void CreateDialogAndView(CRuntimeClass *inClass, CStudioDialog *inDialog, + CFrameWnd *inParent, Q3DStudio::CString inWindowTitle); +#endif + +protected: + CMainFrame *m_MainFrame; ///< + Q3DStudio::CString m_HelpURL; ///< +}; + +#endif // INCLUDED_VIEWS_H diff --git a/src/Authoring/Studio/_Win/Application/AboutDlg.cpp b/src/Authoring/Studio/_Win/Application/AboutDlg.cpp new file mode 100644 index 00000000..533a5601 --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/AboutDlg.cpp @@ -0,0 +1,314 @@ +/**************************************************************************** +** +** 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 "qtAuthoring-config.h" +#include "StudioDefs.h" +#include "Strings.h" +#include "StringLoader.h" + +//============================================================================== +// Includes +//============================================================================== +#include "AboutDlg.h" +#include "ui_AboutDlg.h" +#include "ProductInfo.h" +#include "HotKeys.h" +#include "Preferences.h" +#include "StudioPreferences.h" + +#include +#include +#include + +//============================================================================== +// Constants +//============================================================================== +const int TIMER_RESIZEABOUT = 6; +const int TIMER_FADEOUT = 7; + +//============================================================================== +/** + * Constructor: Initializes the object. + */ +CAboutDlg::CAboutDlg(QWidget* parent) + : QDialog(parent, Qt::MSWindowsFixedSizeDialogHint) + , m_ScrollingCreditsFlag(false) + , m_ui(new Ui::AboutDlg) +{ + m_ui->setupUi(this); + m_IconRect = m_ui->icon->pixmap()->rect(); + setFixedSize(size()); + + m_Font = QFont(CStudioPreferences::GetFontFaceName()); + m_Font.setPointSizeF(7.8); + m_Font = QFont(CStudioPreferences::GetFontFaceName()); + m_Font.setPointSizeF(8.8); + + m_Color_Background = CStudioPreferences::GetDarkBaseColor(); + m_Color_Text = CStudioPreferences::GetNormalColor(); + + OnInitDialog(); +} + +//============================================================================== +/** + * Destructor: Releases the object. + */ +CAboutDlg::~CAboutDlg() +{ +} + +//============================================================================== +/** + * Handles the painting of the icon in the About Box. + * All additional painting (text, etc) occurs by default by MFC. + */ +//============================================================================== +void CAboutDlg::paintEvent(QPaintEvent* event) +{ + Q_UNUSED(event); + if (!m_ScrollingCreditsFlag) { + DrawFadeRect(); + } +} + +//============================================================================== +/** + * Completes the construction of the About Box. + * Stores the product version in the member variable associated with the static + * text box in the dialog template. This version information comes from the + * VersionNumber.h file in $/Studio/Build. + * @return Returns TRUE always. + */ +void CAboutDlg::OnInitDialog() +{ + // Set the Studio version + m_ProductVersionStr.Format( + ::LoadResourceString(IDS_UIC_STUDIO_VERSION), + static_cast(CStudioPreferences::GetVersionString())); + + // Set the copyright string + m_CopyrightStr.Format(::LoadResourceString(IDS_ABOUT_COPYRIGHT), + static_cast(Q3DStudio::CString(STUDIO_COPYRIGHT_YEAR))); + + // Set the credit strings + m_Credit1Str.Format(::LoadResourceString(IDS_ABOUT_PAINTLIB_CREDIT)); +#ifdef QT_3DSTUDIO_FBX + m_Credit2Str.Format(::LoadResourceString(IDS_ABOUT_FBX_CREDIT)); +#endif + +#ifdef STUDIOSTORYNUM + m_ProductVersionStr += " (Story #"; + m_ProductVersionStr += STUDIOSTORYNUM; + m_ProductVersionStr += ")"; +#endif + +#ifdef BETA + // Add "beta" to the Studio version if necessary + m_ProductVersionStr += " BETA"; +#endif + + // Add link to Web site + Q3DStudio::CString theURL(::LoadResourceString(IDS_HELP_VISIT_QT)); + + m_ui->m_WebSite->setText(QString("%2").arg(theURL.toQString(), theURL.toQString())); + m_ui->m_WebSite->setToolTip(::LoadResourceString(IDS_WEBSITELINK).toQString()); + m_ui->m_WebSite->setOpenExternalLinks(true); + + // Add link to support email address + Q3DStudio::CString theEmail; + Q3DStudio::CString theEmailSansProtocol; + + theEmail = ::LoadResourceString(IDS_SUPPORTEMAIL); + theEmailSansProtocol = "support@qt.io"; + + m_ui->m_Email->setText(QString("%2").arg(theEmail.toQString(), theEmailSansProtocol.toQString())); + m_ui->m_Email->setToolTip(::LoadResourceString(IDS_SUPPORTEMAIL_TEXT).toQString()); + m_ui->m_Email->setOpenExternalLinks(true); + + // Set the fonts + m_ui->m_Copyright->setFont(m_Font); + m_ui->m_Credit1->setFont(m_Font); + m_ui->m_Credit2->setFont(m_Font); + m_ui->m_WebSiteLabel->setFont(m_Font); + m_ui->m_WebSite->setFont(m_Font); + m_ui->m_EmailLabel->setFont(m_Font); + m_ui->m_Email->setFont(m_Font); + + // Make the font bold for version numbers + m_ui->m_ProductVersion->setFont(m_BoldFont); + + // Create brush for background color + m_Brush = QBrush(m_Color_Background); + + m_ui->m_ProductVersion->setText(m_ProductVersionStr.toQString()); + m_ui->m_Copyright->setText(m_CopyrightStr.toQString()); + m_ui->m_Credit1->setText(m_Credit1Str.toQString()); + m_ui->m_Credit2->setText(m_Credit2Str.toQString()); + + // Hide the email link until we have a valid one. + m_ui->m_EmailLabel->setVisible(false); + m_ui->m_Email->setVisible(false); +} + +//============================================================================== +/** + * Handles the WM_LBUTTONDBLCLK message + * Check to see if the mouse is within the Qt logo and the control key is pressed. + * If so, begin the transition to show the detailed credits. + */ +void CAboutDlg::mouseDoubleClickEvent(QMouseEvent* event) +{ + // If the mouse's left button is double-clicked in the Qt logo while the control key is + // pressed... + if (m_IconRect.contains(event->pos())) { + // if ( CHotKeys::IsKeyDown( VK_CONTROL ) ) + //{ + // Start the transition to display the scrolling credits + // Crashing... this->BeginCreditsTransition(); + //} + } + + QDialog::mouseDoubleClickEvent(event); +} + +//============================================================================== +/** + * BeginCreditsTransition: Begin the transition from the About box to the scrolling credits. + */ +void CAboutDlg::BeginCreditsTransition() +{ + m_ScrollingCreditsFlag = TRUE; + + // Hide all controls + for (QWidget* w : findChildren()) + w->setVisible(false); + + // Invalidate the window + update(); + + // Set the resizing timer + QTimer::singleShot(50, this, &CAboutDlg::ResizeAbout); +} + +//============================================================================== +/** + * Resize the about box height until the Client area is square. + */ +void CAboutDlg::ResizeAbout() +{ + bool retriggerResizeAbout = true; + + QRect theClientRect = rect(); + bool theRightSize = false; + + // this is just a sizing stuff to show some transition on size + if (theClientRect.height() < theClientRect.width()) { + theClientRect.setBottom(theClientRect.bottom() + 5); + if (theClientRect.bottom() >= theClientRect.width()) { + theRightSize = true; + theClientRect.setBottom(theClientRect.width()); + retriggerResizeAbout = false; + } + } else { + theClientRect.setRight(theClientRect.right() + 5); + if (theClientRect.right() >= theClientRect.height()) { + theRightSize = true; + theClientRect.setRight(theClientRect.height()); + retriggerResizeAbout = false; + } + } + + if (parentWidget()) + theClientRect.moveCenter(parentWidget()->geometry().center()); + else + theClientRect.moveTopLeft(geometry().topLeft()); + + setGeometry(theClientRect); + + if (theRightSize) { + QColor the3DColor; + short theColorValue; + + m_CreditsRect = rect().adjusted(3, 3, -3, -3); + + the3DColor = palette().color(QPalette::Base); + theColorValue = + (short)((the3DColor.red() + the3DColor.green() + the3DColor.blue()) / 3); + + m_ColorFade = RGB(theColorValue, theColorValue, theColorValue); + + QTimer::singleShot(50, this, &CAboutDlg::FadeOut); + } + + if (retriggerResizeAbout) { + QTimer::singleShot(50, this, &CAboutDlg::ResizeAbout); + } +} + +//============================================================================== +/** + * Fade out a rectangle in the client area, from the background 3D color to black. + */ +void CAboutDlg::FadeOut() +{ + update(); + + // Continue fading to black + if (m_ColorFade != Qt::black) { + short theColorValue; + + theColorValue = (short)(m_ColorFade.red() - 10); + + if (theColorValue < 0) + theColorValue = 0; + + m_ColorFade = qRgb(theColorValue, theColorValue, theColorValue); + QTimer::singleShot(50, this, &CAboutDlg::FadeOut); + } +} + +//============================================================================== +/** + * DrawFadeRect: Draw the faded rectangle as we transition to the scrolling credits. + */ +void CAboutDlg::DrawFadeRect() +{ + QPainter painter(this); + painter.fillRect(m_CreditsRect, m_ColorFade); +} + +void CAboutDlg::OnStnClickedAboutboxProdver() +{ + // TODO: Add your control notification handler code here +} diff --git a/src/Authoring/Studio/_Win/Application/AboutDlg.h b/src/Authoring/Studio/_Win/Application/AboutDlg.h new file mode 100644 index 00000000..244e7192 --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/AboutDlg.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_ABOUT_DLG_H +#define INCLUDED_ABOUT_DLG_H 1 + +#pragma once + +#include + +#include "UICString.h" + +#ifdef QT_NAMESPACE +using namespace QT_NAMESPACE; +#endif + +QT_BEGIN_NAMESPACE +namespace Ui { + class AboutDlg; +} +QT_END_NAMESPACE + +class CAboutDlg : public QDialog +{ + Q_OBJECT +public: + CAboutDlg(QWidget* parent = nullptr); + ~CAboutDlg(); + + // Implementation +protected: + bool m_ScrollingCreditsFlag = false; // TRUE if credits are being scrolled + QRect m_IconRect; // bounding rectangle to display the about image + QRect m_CreditsRect; // bounding rectangle for the scrolling credits + QColor m_ColorFade; // fade-out color to fade to the credits window + QFont m_Font; // Font for text + QFont m_BoldFont; // Font for Studio/Client version number + + QColor m_Color_Background; + QColor m_Color_Text; + QBrush m_Brush; + + void BeginCreditsTransition(); + + void DrawFadeRect(); + + void FadeOut(); + + void ResizeAbout(); + + //{{AFX_MSG(CAboutDlg) + void paintEvent(QPaintEvent* event) override; + void OnInitDialog(); + + void mouseDoubleClickEvent(QMouseEvent* event) override; + + Q3DStudio::CString m_ProductVersionStr; + Q3DStudio::CString m_CopyrightStr; + Q3DStudio::CString m_Credit1Str; + Q3DStudio::CString m_Credit2Str; + +public: + void OnStnClickedAboutboxProdver(); + +private: + QScopedPointer m_ui; +}; + +#endif // INCLUDED_ABOUT_DLG_H diff --git a/src/Authoring/Studio/_Win/Application/AboutDlg.ui b/src/Authoring/Studio/_Win/Application/AboutDlg.ui new file mode 100644 index 00000000..a5fe3433 --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/AboutDlg.ui @@ -0,0 +1,180 @@ + + + AboutDlg + + + + 0 + 0 + 502 + 483 + + + + About Qt 3D Studio + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + :/res/About Icon.bmp + + + + + + + + + + Qt::Horizontal + + + + + + + <studio version goes here> + + + + + + + <Copyright goes here> + + + + + + + <Credit 1 goes here> + + + true + + + + + + + <Credit 2 goes here> + + + true + + + + + + + Qt::Horizontal + + + + + + + Web site: + + + + + + + <Link to support site here> + + + + + + + Support email: + + + + + + + <Link to support email here> + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + + + + + + buttonBox + accepted() + AboutDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AboutDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/Authoring/Studio/_Win/Application/BaseLink.cpp b/src/Authoring/Studio/_Win/Application/BaseLink.cpp new file mode 100644 index 00000000..5e7b4775 --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/BaseLink.cpp @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** 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" + +#ifdef _DEBUG +//#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +//============================================================================== +// Includes +//============================================================================== + +#include "BaseLink.h" +#include "Resource.h" +#include "StudioColors.h" + +// The IDC_HAND should be defined in WinUser.h if the WINVER is 0x5000 or greater +#ifndef IDC_HAND +#define IDC_HAND MAKEINTRESOURCE(32649) +#endif + +///////////////////////////////////////////////////////////////////////////// +// CBaseLink class + +//============================================================================== +/** + * Constructor: Initializes the object. + */ +//============================================================================== +CBaseLink::CBaseLink() +{ + m_bCapture = FALSE; +} + +//============================================================================== +/** + * Destructor: Releases the object. + */ +//============================================================================== +CBaseLink::~CBaseLink() +{ +} + +//============================================================================== +// Message Map +//============================================================================== + +BEGIN_MESSAGE_MAP(CBaseLink, CWnd) +//{{AFX_MSG_MAP(CBaseLink) +ON_WM_PAINT() +ON_WM_SETCURSOR() +ON_WM_MOUSEMOVE() +//}}AFX_MSG_MAP +END_MESSAGE_MAP() + +//============================================================================== +/** + * ShowTextLink: Shows the text link. + * + * @param None + */ +//============================================================================== +void CBaseLink::ShowTextLink(COLORREF inTextColor, COLORREF inBackColor, UINT inTextFormat, + bool inUnderlineText) +{ + if (IsWindow(m_hWnd)) { + CRect theRect; + CFont *theFont; + CFont *theOldFont = nullptr; + CDC *theDC; + CDC theMemDC; + CString theTextBuffer; + + // Set up the link font. + theFont = GetFont(); + if (theFont != nullptr) { + LOGFONT theLogFont; + + theFont->GetLogFont(&theLogFont); + + // Turn on the underline style... + if (inUnderlineText) + theLogFont.lfUnderline = TRUE; + else + theLogFont.lfUnderline = FALSE; + + theFont = new CFont(); + + if (theFont != nullptr) { + theFont->CreateFontIndirect(&theLogFont); + } + } + + GetClientRect(&theRect); + GetWindowText(theTextBuffer); + + theDC = GetDC(); + + theDC->SetTextColor(inTextColor); + theDC->SetBkColor(inBackColor); + + // Fill the background. + theDC->FillSolidRect(&theRect, inBackColor); + + // Set the font and draw the text. + if (theFont != nullptr) { + theOldFont = (CFont *)theDC->SelectObject(theFont); + } + theDC->DrawText(theTextBuffer, &theRect, inTextFormat); + + if (theOldFont != nullptr) { + theDC->SelectObject(theOldFont); + } + ReleaseDC(theDC); + + if (theFont != nullptr) { + theFont->DeleteObject(); + delete theFont; + } + } +} + +///////////////////////////////////////////////////////////////////////////// +// CBaseLink message handlers + +//============================================================================== +/** + * OnPaint - Handler for the WM_PAINT message + * + * Draw the control. + * + * @param None + */ +//============================================================================== +void CBaseLink::OnPaint() +{ + CPaintDC dc(this); // device context for painting + + if (IsWindowEnabled()) + this->ShowLink(); +} + +//============================================================================== +/** + * OnSetCursor + * + * Handle the WM_SETCURSOR message. + * + * @param inWnd Pointer to the parent CWnd object. + * @param inHitTest Specifies the hit-test area code. The hit test determines the + *cursor�s location. + * @param inMessage Specifies the mouse message number. + */ +//============================================================================== +BOOL CBaseLink::OnSetCursor(CWnd *inWnd, UINT inHitTest, UINT inMessage) +{ + UNREFERENCED_PARAMETER(inWnd); + UNREFERENCED_PARAMETER(inHitTest); + UNREFERENCED_PARAMETER(inMessage); + + SetCursor(LoadCursor(nullptr, IDC_HAND)); + + return TRUE; +} + +//============================================================================== +/** + * OnMouseMove + * + * Windows callback handler for the WM_MOUSEMOVE message + * + * @param inFlags Flags for the left button up message + * @param inPoint Point where the left button was last moved (client coordinates) + */ +//============================================================================== +void CBaseLink::OnMouseMove(UINT inFlags, CPoint inPoint) +{ + UNREFERENCED_PARAMETER(inFlags); + UNREFERENCED_PARAMETER(inPoint); + + if (IsWindowEnabled()) { + + if (!m_bCapture) { + SetCursor(LoadCursor(nullptr, IDC_HAND)); + SetCapture(); + + m_bCapture = TRUE; + this->ShowLink(); + } else { + // Already captured... + if (!this->IsMouseOverLink()) { + m_bCapture = FALSE; + ReleaseCapture(); + + this->ShowLink(); + } + } + } +} + +//============================================================================== +/** + * IsMouseOverLink: Determine if the mouse is over the control. + * + * @param None + * + * @return true if the mouse is over the control. + */ +//============================================================================== +bool CBaseLink::IsMouseOverLink() +{ + POINT theMousePos; + RECT theWndRect; + + ::GetCursorPos(&theMousePos); + GetWindowRect(&theWndRect); + + return PtInRect(&theWndRect, theMousePos) ? true : false; +} diff --git a/src/Authoring/Studio/_Win/Application/BaseLink.h b/src/Authoring/Studio/_Win/Application/BaseLink.h new file mode 100644 index 00000000..4d89a155 --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/BaseLink.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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 _BASELINK_H_ +#define _BASELINK_H_ + +///////////////////////////////////////////////////////////////////////////// +// CBaseLink window + +class CBaseLink : public CWnd +{ + // Construction +public: + CBaseLink(); + + // Attributes +public: + // Operations +public: +protected: + bool m_bCapture; + + virtual bool IsMouseOverLink(); + virtual void ShowLink() = 0; + virtual void ShowTextLink(COLORREF inTextColor, COLORREF inBackColor, UINT inTextFormat, + bool inUnderlineText); + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CBaseLink) + //}}AFX_VIRTUAL + + // Implementation +public: + virtual ~CBaseLink(); + + // Generated message map functions +protected: + //{{AFX_MSG(CBaseLink) + virtual afx_msg void OnPaint(); + virtual afx_msg BOOL OnSetCursor(CWnd *pWnd, UINT nHitTest, UINT message); + virtual afx_msg void OnMouseMove(UINT nFlags, CPoint point); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/src/Authoring/Studio/_Win/Application/MsgRouter.cpp b/src/Authoring/Studio/_Win/Application/MsgRouter.cpp new file mode 100644 index 00000000..4ce57cc8 --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/MsgRouter.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** 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 "MsgRouter.h" +#include "StudioConst.h" +#include "Core.h" +#include "Doc.h" +#include "Views.h" + +#include + +static std::unique_ptr static_theInstance; + +//============================================================================== +/** + * Constructor + */ +CMsgRouter::CMsgRouter() +{ + qApp->installEventFilter(this); + m_eventType = QEvent::registerEventType(); +} + +//============================================================================== +/** + * Destructor + */ +CMsgRouter::~CMsgRouter() +{ +} + +CMsgRouter *CMsgRouter::GetInstance() +{ + if (!static_theInstance) { + static_theInstance.reset(new CMsgRouter); + } + + return static_theInstance.get(); +} + +//============================================================================== +/** + * Send a command to be executed asynchronously. + */ +void CMsgRouter::SendCommand(CCmd *inCommand, CCore *inCore) +{ + SMessageData *theMsgData = new SMessageData(m_eventType); + theMsgData->Method = &CMsgRouter::OnCommand; + theMsgData->Data = inCommand; + theMsgData->Data2 = inCore; + + qApp->postEvent(qApp, theMsgData); +} + +bool CMsgRouter::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == m_eventType) { + SMessageData *theMsgData = reinterpret_cast(event); + (this->*(theMsgData->Method))(theMsgData); + return true; + } + + return false; +} + +//============================================================================== +/** + * Windows entry point for processing generic messages. + */ +void CMsgRouter::OnAsyncNotification(SMessageData *inMessageData) +{ + try { + CRoutedMessageBase *theRoutedMsg = static_cast(inMessageData->Data); + if (theRoutedMsg) + theRoutedMsg->Notify(); + } catch (...) { + // Catch crashes in case the object is gone + } +} + +//============================================================================== +/** + * Main thread processing for processing command execution messages. + */ +void CMsgRouter::OnCommand(SMessageData *inMsgData) +{ + CCmd *theCommand = static_cast(inMsgData->Data); + CCore *theCore = static_cast(inMsgData->Data2); + theCore->ExecuteCommand(theCommand, true); +} + + + +CMsgRouter::SMessageData::SMessageData(int eventType) : + QEvent(static_cast(eventType)) +{ +} diff --git a/src/Authoring/Studio/_Win/Application/StudioApp.cpp b/src/Authoring/Studio/_Win/Application/StudioApp.cpp new file mode 100644 index 00000000..fa160431 --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/StudioApp.cpp @@ -0,0 +1,1835 @@ +/**************************************************************************** +** +** 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" + +#ifdef _WIN32 +#pragma warning(disable : 4100) // unreferenced formal parameter +#endif +#include "StudioApp.h" +#include "SubPresentationsDlg.h" +#include "UICStateApplication.h" + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + // to enable QOpenGLWidget to work on macOS, we must set the default + // QSurfaceFormat before QApplication is created. Otherwise context-sharing + // fails and QOpenGLWidget breaks. + + // fortunately, we know which OpenGL version we can use on macOS, so we + // can simply hard-code it here. +#if defined(Q_OS_MACOS) + QSurfaceFormat openGL33Format; + openGL33Format.setRenderableType(QSurfaceFormat::OpenGL); + openGL33Format.setProfile(QSurfaceFormat::CoreProfile); + openGL33Format.setMajorVersion(3); + openGL33Format.setMinorVersion(3); + openGL33Format.setStencilBufferSize(8); + QSurfaceFormat::setDefaultFormat(openGL33Format); +#endif + + // init runtime static resources + Q_INIT_RESOURCE(res); + + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication guiApp(argc, argv); + // Load and apply stylesheet for the application + QFile styleFile(":/style.qss"); + styleFile.open(QFile::ReadOnly); + guiApp.setStyleSheet(styleFile.readAll()); + g_StudioApp.InitInstance(argc, argv); + return g_StudioApp.Run(); +} + +//============================================================================== +// Includes +//============================================================================== +#include "Exceptions.h" +#include "IOLibraryException.h" +#include "Strings.h" +#include "MainFrm.h" +#include "AboutDlg.h" +#ifdef KDAB_TEMPORARILY_REMOVED +#include "StackOps.h" +#include "Views.h" +#endif +#include "StringLoader.h" +#include "Doc.h" +#include "Dialogs.h" +#include "Dispatch.h" +#include "StartupDlg.h" +#include "RecentItems.h" +#include "StudioPreferences.h" +#include "MsgRouter.h" +#include "SplashView.h" +#include "Views.h" +#include "UICLog.h" +#ifdef KDAB_TEMPORARILY_REMOVED +#include "WinUtils.h" +#include "CrashDlg.h" +#endif +#include "UICFile.h" +#include "UICFileTools.h" +#include "ITickTock.h" +#include "IStudioRenderer.h" +#include "IDocumentEditor.h" +#include "StudioUtils.h" + +#ifdef KDAB_TEMPORARILY_REMOVED +#include "IObjectReferenceHelper.h" +#endif +#include "ClientDataModelBridge.h" +#ifdef KDAB_TEMPORARILY_REMOVED +#include "CommonConstants.h" +#include "IOLibraryException.h" + +#ifdef _DEBUG +#include "UICMemoryLeak.h" +#endif +#include "UICDMErrors.h" + +#include +#include +#include +#include +#include +#endif +#include + +#include +#include + +#ifdef KDAB_TEMPORARILY_REMOVED +#include "..\Build\versionnumber.h" + +#include "UICDESKey.h" // g_DESKey +#endif + +#include "Core.h" +#include "HotKeys.h" +#include "StudioTutorialWidget.h" +#include "GuideInspectable.h" +#include "UICDMStudioSystem.h" +#include "UICDMInspectable.h" +#include "UICDMSlides.h" +#include "UICDMMaterialInspectable.h" +#include "UICDMSceneInspectable.h" +#ifdef KDAB_TEMPORARILY_REMOVED +#include "UICDMAnimation.h" +#include "UICDMDataCore.h" +#include "SlideControl.h" +#endif +#include "IDirectoryWatchingSystem.h" +#ifdef KDAB_TEMPORARILY_REMOVED +#include "ITickTock.h" +#include "UICFileTools.h" +#include "foundation/Qt3DSLogging.h" + +#endif +#ifdef USE_LICENSE_HANDLER +#include "licensehandler.h" +#endif + +CStudioApp g_StudioApp; +long g_UICErrorCode = 0; + +using namespace Q3DStudio; + +#ifndef MAX_PATH +#define MAX_PATH 260 +#endif + +char g_DumpPath[MAX_PATH] = { 0 }; + +#ifndef WIN32 +namespace qt3ds +{ +void NVAssert(const char *exp, const char *file, int line, bool *igonore) +{ + qFatal("NVAssertion thrown %s(%d): %s", file, line, exp); +} +} +#endif + +//============================================================================= +/** + * Constructor + */ +CStudioApp::CStudioApp() +#ifdef KDAB_TEMPORARILY_REMOVED + , m_SplashPalette(nullptr) + , m_OldHelpFilePath(nullptr) + , m_UnitTestResults(0) + , m_IsSilent(false) + , m_Core(NULL) + , m_Views(NULL) + , m_Dialogs(NULL) + , m_ManipulationMode(StudioManipulationModes::Local) + , m_PlaybackTime(0) + , m_pGdiToken(0) + , m_AuthorZoom(false) +#endif + : m_ToolMode(STUDIO_TOOLMODE_MOVE) + , m_SelectMode(STUDIO_SELECTMODE_GROUP) + , m_welcomeShownThisSession(false) + , m_goStraightToWelcomeFileDialog(false) + , m_tutorialPage(0) +{ +#ifdef KDAB_TEMPORARILY_REMOVED +#ifdef _DEBUG + AfxEnableMemoryTracking(TRUE); + CMemoryLeak::SetXMLFileName("StudioMemoryLeaks.xml"); + CMemoryLeak::SetShowDialogOnExit(false); +#endif // _DEBUG + g_DumpPath[0] = 0; +#endif +} + +//============================================================================= +/** + * Destructor + */ +CStudioApp::~CStudioApp() +{ + // Do not call PerformShutdown from here as the C has already been shutdown (!!) +} + +void CStudioApp::PerformShutdown() +{ + m_DirectoryWatcherTicker = std::shared_ptr(); + + // Dispatch un-registration + if (m_Core) { + m_Core->GetDispatch()->RemoveAppStatusListener(this); + m_Core->GetDispatch()->RemoveCoreAsynchronousEventListener(this); + qCInfo(qt3ds::TRACE_INFO) << "Studio exiting successfully"; + } + + if (m_Renderer) { + m_Renderer->Close(); + m_Renderer = std::shared_ptr(); + } + + // No need to delete m_SplashPalette. You should not call delete on CFrameWnds, + // you should call DestroyWindow( ) instead. See the MSDN. + // delete m_SplashPalette; +#ifdef KDAB_TEMPORARILY_REMOVED + delete m_Views; + m_Views = nullptr; + delete m_Dialogs; + m_Dialogs = nullptr; + delete m_Core; + m_Core = nullptr; +#endif + + CStringLoader::UnloadStrings(); + + // Get rid of the temp files + CUICFile::ClearCurrentTempCache(); + + qApp->exit(); +} + +//============================================================================= +/** + * Entry location for the creation of this application. + * This creates the all the views, then returns if everything + * was successful. + */ +BOOL CStudioApp::InitInstance(int argc, char* argv[]) +{ + QApplication::setOrganizationName("The Qt Company"); + QApplication::setOrganizationDomain("qt.io"); + QApplication::setApplicationName("Qt 3D Studio"); + QApplication::setApplicationVersion( + QString::fromWCharArray(CStudioPreferences::GetVersionString().c_str())); + + qCInfo(qt3ds::TRACE_INFO) << "Studio: " << QApplication::applicationFilePath(); + + // Load the strings used by the app gui + // This needs to occur prior to parsing command line arguments + // since access to the strings are required by some of the cases + CUICFile theResDir(CString::fromQString(resourcePath() + QStringLiteral("/strings"))); + CStringLoader::LoadStrings(theResDir); + qCInfo(qt3ds::TRACE_INFO) << "Version: " + << CStudioPreferences::GetVersionString().GetCharStar(); + + std::vector wargv; + wargv.resize(argc); + for (int i = 0; i < argc; ++i) { + QString arg = argv[i]; + wargv[i] = new wchar_t[arg.size() + 1]; + wargv[i][arg.size()] = L'\0'; + arg.toWCharArray(wargv[i]); + } + + // Parse the command line so we know what's up + m_CmdLineParser.ParseArguments(argc, &(wargv[0])); + + // Silent mode indicates that Studio will be operated in a muted "no-GUI" mode + m_IsSilent = m_CmdLineParser.IsSilent(); + + // If we're just running unit tests, return before creating windows/MFC controls + if (m_CmdLineParser.IsRunUnitTests()) { + { + RunCmdLineTests(m_CmdLineParser.GetFilename()); + return FALSE; // return false so we bail from loading the app + } + } + +#ifdef KDAB_TEMPORARILY_REMOVED + // Standard initialization + // If you are not using these features and wish to reduce the size + // of your final executable, you should remove from the following + // the specific initialization routines you do not need + // Change the registry key under which our settings are stored + Q3DStudio::CString theRegistryKey = + ::LoadResourceString(IDS_UICOMPOSER_PALETTE_SETTINGS_REGISTRY_KEY); + SetRegistryKey(theRegistryKey); +#endif + + CFilePath thePreferencesPath = CFilePath::GetUserApplicationDirectory(); + thePreferencesPath = CFilePath::CombineBaseAndRelative( + thePreferencesPath, CFilePath(L"UIComposer\\Preferences.setting")); + CPreferences::SetPreferencesFile(thePreferencesPath); + +#ifdef KDAB_TEMPORARILY_REMOVED + // Set up the path to the help file + InitHelpSystem(); +#endif + + CStudioPreferences::LoadPreferences(); + + m_Dialogs = new CDialogs(!m_IsSilent); + + if (!m_IsSilent) { + // Show the splash screen + m_SplashPalette = new CSplashView(); + m_SplashPalette->setWindowTitle(::LoadResourceString(IDS_PROJNAME).toQString()); + m_SplashPalette->show(); + + m_Views = new CViews(this); + } + + // All custom icons (PNGs) are drawn using Gdiplus so that transparency are handled. + // note that gdiplus.dll are included with WinXP ( previous OS versions require the gdi + // redistributables to be installed and unless + // support for those OS becomes a priority, we assume Studio is run minimally on a XP machine ) +#ifdef KDAB_TEMPORARILY_REMOVED + Gdiplus::GdiplusStartup(&m_pGdiToken, &m_gdiplusStartupInput, nullptr); // gdi+ init +#endif + + m_Core = new CCore(); + GetRenderer(); + m_Core->GetDoc()->SetSceneGraph(m_Renderer); + + // Dispatch registration + m_Core->GetDispatch()->AddAppStatusListener(this); + m_Core->GetDispatch()->AddCoreAsynchronousEventListener(this); + + return TRUE; +} + +//============================================================================= +/** + * Exit location for the destruction of this application. + * @return 0 on success; -1 on failure + */ +int CStudioApp::ExitInstance() +{ + int theResult = -1; + +#ifdef KDAB_TEMPORARILY_REMOVED + // CWinApp::InitInstance returns 1(TRUE) on success; 0(FALSE) on failure + if (CWinApp::InitInstance() == TRUE) + theResult = 0; + + if (m_CmdLineParser.IsRunUnitTests() && 0 == m_UnitTestResults) + theResult = m_UnitTestResults; // unit tests return 0 on success; 1 on failure + +#ifdef _DEBUG + // If appears that MFC takes over dumping memory leaks on exit + // this is the only way I've been able to turn it off. + + // Turn off dumping CRT memory leaks + ::_CrtSetReportMode(_CRT_WARN, 0); + ::_CrtSetReportMode(_CRT_ERROR, 0); + ::_CrtSetReportMode(_CRT_ASSERT, 0); +#endif + + // Make sure any GDI resources have been cleaned up + CResourceCache::GetInstance()->Clear(); + // Called in conjuction with Gdiplus::GdiplusStartup + Gdiplus::GdiplusShutdown(m_pGdiToken); +#endif + + return theResult; +} + +//============================================================================= +/** + * Command handler to display the about dialog. + */ +void CStudioApp::OnAppAbout() +{ + CAboutDlg aboutDlg; + aboutDlg.exec(); +} + +#ifdef KDAB_TEMPORARILY_REMOVED +//============================================================================= +/** + * Overrides registry access member functions, direct settings to a XML file + */ +UINT CStudioApp::GetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nDefault) +{ + QT3DS_ASSERT(lpszSection != nullptr); + QT3DS_ASSERT(lpszEntry != nullptr); + + Q3DStudio::CString theSubKeyName; + theSubKeyName.Format(L"%s\\%s\\%s", PALETTE_KEY, PALETTE_SUBKEY, lpszSection); + return CPreferences::GetUserPreferences(theSubKeyName).GetLongValue(lpszEntry, nDefault); +} +BOOL CStudioApp::WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue) +{ + QT3DS_ASSERT(lpszSection != nullptr); + QT3DS_ASSERT(lpszEntry != nullptr); + + Q3DStudio::CString theSubKeyName; + theSubKeyName.Format(L"%s\\%s\\%s", PALETTE_KEY, PALETTE_SUBKEY, lpszSection); + CPreferences::GetUserPreferences(theSubKeyName).SetLongValue(lpszEntry, nValue); + return TRUE; +} +::CString CStudioApp::GetProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, + LPCTSTR lpszDefault /* = nullptr */) +{ + QT3DS_ASSERT(lpszSection != nullptr); + QT3DS_ASSERT(lpszEntry != nullptr); + + Q3DStudio::CString theSubKeyName; + theSubKeyName.Format(L"%s\\%s\\%s", PALETTE_KEY, PALETTE_SUBKEY, lpszSection); + return CPreferences::GetUserPreferences(theSubKeyName).GetStringValue(lpszEntry, lpszDefault); +} +BOOL CStudioApp::WriteProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue) +{ + QT3DS_ASSERT(lpszSection != nullptr); + Q3DStudio::CString theSubKeyName; + theSubKeyName.Format(L"%s\\%s\\%s", PALETTE_KEY, PALETTE_SUBKEY, lpszSection); + + if (lpszEntry == nullptr) // delete whole section + { + CPreferences::GetUserPreferences(theSubKeyName).Clear(); + } else if (lpszValue == nullptr) { + CPreferences::GetUserPreferences(theSubKeyName).RemoveKey(lpszEntry); + } else { + CPreferences::GetUserPreferences(theSubKeyName).SetStringValue(lpszEntry, lpszValue); + } + return TRUE; +} +#endif + +//============================================================================= +/** + * Main application execution loop. + * The application's main thread stays in this until the app exits. + * @return 0 on success; -1 on failure + */ +int CStudioApp::Run() +{ + int theRetVal = -1; + +#ifdef USE_LICENSE_HANDLER + LicenseHandler lh; + if (!lh.handleLicense()) + return theRetVal; +#endif + + try { + UIC_LOGSTART; + +#ifdef KDAB_TEMPORARILY_REMOVED + // Set the crash handler for all unhandled exceptions. + CStackOps::SetCrashProc(&StudioUnhandledCrashHandler); + CStackOps::RegisterCrashHandler(); + CStackOps::EnableCrashingOnCrashes(); +#endif + + CCmdLineParser::EExecutionMode theMode = m_CmdLineParser.PopExecutionMode(); + if (CCmdLineParser::END_OF_CMDS == theMode) + theMode = CCmdLineParser::NORMAL; + + for (; CCmdLineParser::END_OF_CMDS != theMode; + theMode = m_CmdLineParser.PopExecutionMode()) { + // This just switches the execution mode of the app and starts it in the correct state. + switch (theMode) { + case CCmdLineParser::TEST_CMD_LINE: + theRetVal = RunSystemTests(m_CmdLineParser.GetFilename()); + break; + case CCmdLineParser::OPEN_FILE: + theRetVal = OpenAndRunApplication(m_CmdLineParser.GetFilename()); + break; + default: + theRetVal = BlankRunApplication(); + break; + } + + // if any operations returned a bad value, stop following operations + if (-1 == theRetVal) + break; + } + PerformShutdown(); + + UIC_LOGSTOP; + } catch (CUICExceptionClass &inException) { + g_UICErrorCode = inException.GetErrorCode(); + throw; + } catch (UICDM::UICDMError &uicdmError) { + Q_UNUSED(uicdmError); + +#ifdef KDAB_TEMPORARILY_REMOVED + EXCEPTION_POINTERS *pExPtrs; + CStackOps::GetExceptionPointers(1, &pExPtrs); + StudioUnhandledCrashHandler(pExPtrs); +#endif + exit(1); + } catch (...) { + throw; + } + + return theRetVal; +} + +bool CStudioApp::HandleWelcomeRes(int res, bool recursive) +{ + int theReturn = true; + switch (res) { + case StudioTutorialWidget::createNewResult: { + std::pair theFile = m_Dialogs-> + GetNewDocumentChoice(Q3DStudio::CString(".")); + if (theFile.first.GetPath() != "") { + m_Core->OnNewDocument(theFile.first, theFile.second); + theReturn = true; + m_welcomeShownThisSession = true; + } else { + // User Cancels the dialog. Show the welcome screen. + if (recursive) { + m_welcomeShownThisSession = false; + m_goStraightToWelcomeFileDialog = true; + theReturn = ShowStartupDialog(); + } else { + theReturn = false; + } + } + } break; + + case StudioTutorialWidget::openSampleResult: { + // Try three options: + // - open a specific example directory with .uip file in it + // - failing that, show the main example root dir + // - failing all previous, show Qt3DStudio dir + Q3DStudio::CFilePath filePath; + + filePath = CUICFile::GetApplicationDirectory().GetPath()+ + Q3DStudio::CString("../examples/qmldynamickeyframes/presentation"); + + if (!filePath.Exists()) { + filePath = CUICFile::GetApplicationDirectory().GetPath()+ + Q3DStudio::CString("../examples"); + } + if (!filePath.Exists()) { + filePath = CUICFile::GetApplicationDirectory().GetPath()+ + Q3DStudio::CString("."); + } + + CUICFile theFile = m_Dialogs->GetFileOpenChoice(filePath); + + if (theFile.GetPath() != "") { + OnLoadDocument(theFile); + theReturn = true; + m_welcomeShownThisSession = true; + } else { + // User Cancels the dialog. Show the welcome screen. + if (recursive) { + m_welcomeShownThisSession = false; + m_goStraightToWelcomeFileDialog = true; + theReturn = ShowStartupDialog(); + } else { + theReturn = false; + } + } + } break; + + default: + ASSERT(false); // Should not reach this block. + theReturn = false; + break; + } + return theReturn; +} + +//============================================================================= +/** + * Show startup dialog and perform necessary action such as create new doc or load doc. + * Return false if user requests to exit + */ +bool CStudioApp::ShowStartupDialog() +{ + int welcomeRes = QDialog::Rejected; + bool theReturn = true; + + if (!m_welcomeShownThisSession){ + m_welcomeShownThisSession = true; + + bool show = false; + QSettings settings; + + if (!settings.contains("showWelcomeScreen")) { + settings.setValue("showWelcomeScreen", 1); + show = true; + } else { + // if we are returning to welcome dialog page after canceling + // file dialog, do not care about settings but always show + // welcome + show = settings.value("showWelcomeScreen").toBool() + || m_goStraightToWelcomeFileDialog; + } + + if (show) { + StudioTutorialWidget tutorial(m_goStraightToWelcomeFileDialog); + welcomeRes = tutorial.exec(); + } + } + + // show the usual startup dialog only if user rejected tutorial + // ( = did not open samples or create new project) + if (welcomeRes == QDialog::Rejected) { + CStartupDlg theStartupDlg; + + // Populate recent items + Q3DStudio::CFilePath theMostRecentDirectory; + if (m_Views) { + CRecentItems *theRecentItems = m_Views->GetMainFrame()->GetRecentItems(); + for (long theIndex = 0; theIndex < theRecentItems->GetItemCount(); ++theIndex) { + if (theIndex == 0) { + theMostRecentDirectory = + Q3DStudio::CFilePath(theRecentItems->GetItem(0).GetAbsolutePath()) + .GetDirectory(); + } + theStartupDlg.AddRecentItem(theRecentItems->GetItem(theIndex)); + } + } + + theStartupDlg.exec(); + CStartupDlg::EStartupChoice theChoice = theStartupDlg.GetChoice(); + + switch (theChoice) { + case CStartupDlg::EStartupChoice_Exit: + theReturn = false; + break; + + case CStartupDlg::EStartupChoice_NewDoc: { + std::pair theFile = m_Dialogs-> + GetNewDocumentChoice(theMostRecentDirectory); + if (theFile.first.GetPath() != "") { + m_Core->OnNewDocument(theFile.first, theFile.second); + theReturn = true; + } else { + // User Cancels the dialog. Show startup dialog again. + theReturn = ShowStartupDialog(); + } + } break; + + case CStartupDlg::EStartupChoice_OpenDoc: { + CUICFile theFile = m_Dialogs->GetFileOpenChoice(theMostRecentDirectory); + if (theFile.GetPath() != "") { + OnLoadDocument(theFile); + theReturn = true; + } else { + // User Cancels the dialog. Show startup dialog again. + theReturn = ShowStartupDialog(); + } + } break; + + case CStartupDlg::EStartupChoice_OpenRecent: { + CUICFile theFile = theStartupDlg.GetRecentDoc(); + if (theFile.GetPath() != "") { + OnLoadDocument(theFile); + // throw SlideNotFound( L""); + theReturn = true; + } else { + // User Cancels the dialog. Show startup dialog again. + theReturn = ShowStartupDialog(); + } + } break; + + default: + ASSERT(false); // Should not reach this block. + theReturn = false; + break; + } + } else { // open sample or create new + theReturn = HandleWelcomeRes(welcomeRes, true); + } + return theReturn; +} + +//============================================================================= +/** + * Start the app. + */ +int CStudioApp::BlankRunApplication() +{ + InitCore(); + + if (ShowStartupDialog()) + return RunApplication(); + return -1; +} + +//============================================================================= +/** + * Run the unit tests specified on the command line then return. + * @param inTestPath input unit test path + * @return 0 on success; 1 on failure + */ +int CStudioApp::RunCmdLineTests(const Q3DStudio::CString &inTestPath) +{ + Q_UNUSED(inTestPath); + + return m_UnitTestResults; +} + +//============================================================================= +/** + * Run the system level tests specified on the command line then return. + * @param inTestPath + * @return 0 on success; -1 on failure + */ +int CStudioApp::RunSystemTests(const Q3DStudio::CString &inTestPath) +{ + int theSystemTestsResult = -1; + + Q_UNUSED(inTestPath); + + if (0 == m_UnitTestResults) + theSystemTestsResult = m_UnitTestResults; // unit tests return 0 on success; 1 on failure + + return theSystemTestsResult; +} + +//============================================================================= +/** + * Open the specified file and run the application. + * This will load the file then go into the standard app loop. + * On load with the -silent flag, this would force the application to exit on + * load failures. + * @return 0 on success; -1 on failure + */ +int CStudioApp::OpenAndRunApplication(const Q3DStudio::CString &inFilename) +{ + int theSuccess = -1; + InitCore(); + if (OnLoadDocument( + inFilename, + false)) // Load document. Upon failure, don't show startup dialog but exit immediately. + theSuccess = RunApplication(); + return theSuccess; +} + +//============================================================================= +/** + * This is the app execution loop, the main thread loops here until the app exits. + * @return 0 on success; -1 on failure + */ +int CStudioApp::RunApplication() +{ +#ifdef KDAB_TEMPORARILY_REMOVED + BOOL bIdle = TRUE; + LONG lIdleCount = 0; + MSG theMessage; + + // CStackOps::RegisterCrashHandler( ); + + // acquire and dispatch messages until a WM_QUIT message is received. + for (;;) { + // phase1: check to see if we can do idle work + while (bIdle && !::PeekMessage(&theMessage, nullptr, nullptr, nullptr, PM_NOREMOVE)) { + // call OnIdle while in bIdle state + if (!OnIdle(lIdleCount++)) + bIdle = FALSE; // assume "no idle" state + } + + // phase2: pump messages while available + do { + try { + // Pump message, but quit on WM_QUIT + if (!PumpMessage()) + return ExitInstance(); + } catch (...) { + // Throw here so that any crash goes through the crash reporter + throw; + } + + // Reset "no idle" state after pumping "normal" message + if (IsIdleMessage(&theMessage)) { + bIdle = TRUE; + lIdleCount = 0; + } + } while (::PeekMessage(&theMessage, nullptr, nullptr, nullptr, PM_NOREMOVE)); + } +#endif + return qApp->exec(); +} + +//============================================================================= +/** + * Initialize the core and all the views. + */ +void CStudioApp::InitCore() +{ + // Initialize and cache the RenderSelector values for the first time, + // this way, subsequent attempts to instantiate a RenderSelector would circumvent the need + // for any extra (unneccesary) creation of render contexts which inadvertently cause exceptions + // to be thrown. + + m_Core->Initialize(); + + if (m_Views) { + m_Views->CreateViews(); + m_pMainWnd = m_Views->GetMainFrame(); + } else { + ASSERT(0); // No views? wha? + } + +#ifdef KDAB_TEMPORARILY_REMOVED + CMsgRouter::GetInstance()->SetMainframe(m_pMainWnd); +#endif + + // At this point, get rid of the splash screen, otherwise any errors dialog would be hidden + // behind. + // Could happen when this is directly activated due to a uip file being dbl-clicked or dragged + // into the executable. + if (m_SplashPalette) { + m_SplashPalette->deleteLater(); + m_SplashPalette = nullptr; + } + + RegisterGlobalKeyboardShortcuts(m_Core->GetHotKeys()); + m_Core->GetDispatch()->AddPresentationChangeListener(this); +} + +struct SIImportFailedHandler : public Q3DStudio::IImportFailedHandler +{ + CDialogs &m_Dialogs; + SIImportFailedHandler(CDialogs &dialogs) + : m_Dialogs(dialogs) + { + } + void DisplayImportFailed(const QString &inDocumentPath, + const QString &inDescription, bool inWarningsOnly) override + { + m_Dialogs.DisplayImportFailed(QUrl(inDocumentPath), inDescription, inWarningsOnly); + } +}; + +struct SIDeletingReferencedObjectHandler : public Q3DStudio::IDeletingReferencedObjectHandler +{ + CDialogs &m_Dialogs; + + SIDeletingReferencedObjectHandler(CDialogs &dialogs) + : m_Dialogs(dialogs) + { + } + + void DisplayMessageBox(const Q3DStudio::CString &inDescription) override + { + Q3DStudio::CString theTitle(::LoadResourceString(IDS_DELETE_OBJ_CONFIRM_TITLE)); + Q3DStudio::CString theFormat(::LoadResourceString(IDS_DELETE_OBJ_CONFIRM_MSG)); + Q3DStudio::CString theMessage; + theMessage.Format(theFormat, static_cast(inDescription)); + + m_Dialogs.DisplayMessageBox(theTitle, theMessage, CUICMessageBox::ICON_WARNING, false); + } +}; + +void CStudioApp::SetupTimer(long inMessageId, QWidget *inWnd) +{ + m_TickTock = ITickTock::CreateTickTock(inMessageId, inWnd); + GetDirectoryWatchingSystem(); + m_Core->GetDoc()->SetDirectoryWatchingSystem(m_DirectoryWatchingSystem); + m_Core->GetDoc()->SetImportFailedHandler( + std::make_shared(std::ref(*GetDialogs()))); + m_Core->GetDoc()->SetDocMessageBoxHandler( + std::make_shared(std::ref(*GetDialogs()))); +} + +ITickTock &CStudioApp::GetTickTock() +{ + if (m_TickTock == nullptr) + throw std::runtime_error("Uninitialized TickTock"); + return *m_TickTock; +} + +Q3DStudio::IStudioRenderer &CStudioApp::GetRenderer() +{ + if (!m_Renderer) + m_Renderer = Q3DStudio::IStudioRenderer::CreateStudioRenderer(); + return *m_Renderer; +} + +void CStudioApp::ClearGuides() +{ + SCOPED_DOCUMENT_EDITOR(*m_Core->GetDoc(), QObject::tr("Clear Guides"))->ClearGuides(); +} + +void SendAsyncCommand(CDispatch &inDispatch, Q3DStudio::TCallbackFunc inFunc) +{ + inDispatch.FireOnAsynchronousCommand(inFunc); +} + +IDirectoryWatchingSystem &CStudioApp::GetDirectoryWatchingSystem() +{ + if (m_DirectoryWatchingSystem == nullptr) { + Q3DStudio::TCallbackCaller theCaller = + std::bind(SendAsyncCommand, std::ref(*m_Core->GetDispatch()), std::placeholders::_1); + m_DirectoryWatchingSystem = + IDirectoryWatchingSystem::CreateThreadedDirectoryWatchingSystem(theCaller); + } + return *m_DirectoryWatchingSystem; +} + +#ifdef KDAB_TEMPORARILY_REMOVED +bool s_testVar = true; +//============================================================================== +/** + * This gets called any time an unhandled exception is thrown anywhere in the + * application. + * + * @param pExPtrs a description of the exception. + * @return 0 if not handled, 1 if it was handled. + */ +void CStudioApp::StudioUnhandledCrashHandler(EXCEPTION_POINTERS *pExPtrs) +{ + TCHAR theTraceBuffer[4096]; + CCrashDlg theDlg; + Q3DStudio::CString errorMessage; + + CStackOps::GetExceptionStackTrace(theTraceBuffer, sizeof(theTraceBuffer), + pExPtrs->ContextRecord); + if (g_UICErrorCode != 0) { + // switch (g_UICErrorCode) + //{ + // default: + Q3DStudio::CString description; + description.Format(_UIC("Custom error 0x%X "), g_UICErrorCode); + errorMessage = CStackOps::GetExceptionDescription(description, pExPtrs); + // break; + //} + } else { + errorMessage = CStackOps::GetExceptionDescription(pExPtrs); + } + theDlg.SetStackTrace(theTraceBuffer); + qCCritical(qt3ds::INTERNAL_ERROR) << "Crash!" << theTraceBuffer; + // Attempt to save the current project (although this may crash). + CDoc &theDoc = *g_StudioApp.m_Core->GetDoc(); + CFilePath theFullPath = theDoc.GetDocumentPath().GetAbsolutePath(); + CFilePath theDir = theFullPath.GetDirectory(); + CFilePath theStem = theFullPath.GetFileStem(); + theStem.append(L"_Crash"); + // Attempt to open a dump file ideally next to the log file. + CFilePath theSaveFile; + { + TFilePtr theSaveFilePtr = + SFileTools::FindUniqueDestFile(theDir, theStem, CFilePath(L"uip")); + theSaveFile = theSaveFilePtr->m_Path; + } + theSaveFile.DeleteThisFile(); + theDoc.SaveDocument(CUICFile(theSaveFile)); + qCInfo(qt3ds::TRACE_INFO) << "Project successfully saved: " << theSaveFile.GetCharStar(); + + ::CString fileSaveLocationMessage; + fileSaveLocationMessage.Format(L"Project saved as %ls", + static_cast(theSaveFile)); + + theDlg.SetErrorMessage(errorMessage); + theDlg.SetFilename(fileSaveLocationMessage); + theDlg.DoModal(); +} + +void CStudioApp::InitHelpSystem() +{ + Q3DStudio::CString theHelpFile = ::LoadResourceString(IDS_HELP_FILE_NAME); + + ATL::CStringT> theOldHelpPath(m_pszHelpFilePath); + ATL::CStringT> theNewHelpPath; + + long theIndex = theOldHelpPath.ReverseFind('\\'); + theOldHelpPath.Delete(theIndex + 1, (theOldHelpPath.GetLength() - theIndex)); + theNewHelpPath = theOldHelpPath; + ::CString theMFCHelpFile(theHelpFile.GetMulti()); + theNewHelpPath += theMFCHelpFile; + + // Save the m_pszHelpFilePath variable so that CWinApp::SetCurrentHandles() + // in appinit.cpp can deallocate the memory it allocated, which causes a + // mmgr.h assert when we free it in here + m_OldHelpFilePath = const_cast(m_pszHelpFilePath); + + long theLength = theNewHelpPath.GetLength(); + m_pszHelpFilePath = new TCHAR[theLength + 1]; + ::lstrcpyn(const_cast(m_pszHelpFilePath), theNewHelpPath, theLength + 1); +} +#endif + +CCore *CStudioApp::GetCore() +{ + return m_Core; +} + +//============================================================================= +/** + * Get the view manager for this core to communicate to the views. + */ +CViews *CStudioApp::GetViews() +{ + return m_Views; +} + +//============================================================================= +/** + * Get the dialog manager for this core for displaying dialogs. + */ +CDialogs *CStudioApp::GetDialogs() +{ + return m_Dialogs; +} + +long CStudioApp::GetToolMode() +{ + return m_ToolMode; +} + +void CStudioApp::SetToolMode(long inToolMode) +{ + if (m_ToolMode != inToolMode) { + m_ToolMode = inToolMode; + m_Core->GetDispatch()->FireOnToolbarChange(); + } +} + +long CStudioApp::GetSelectMode() +{ + return m_SelectMode; +} + +void CStudioApp::SetSelectMode(long inSelectMode) +{ + if (m_SelectMode != inSelectMode) { + m_SelectMode = inSelectMode; + m_Core->GetDispatch()->FireOnToolbarChange(); + } +} + +StudioManipulationModes::Enum CStudioApp::GetMinpulationMode() const +{ + return m_ManipulationMode; +} +void CStudioApp::SetMinpulationMode(StudioManipulationModes::Enum inManipulationMode) +{ + if (m_ManipulationMode != inManipulationMode) { + m_ManipulationMode = inManipulationMode; + m_Core->GetDispatch()->FireOnToolbarChange(); + } +} + +//============================================================================= +/** + * return true if undo is possible + */ +bool CStudioApp::CanUndo() +{ + return m_Core->GetCmdStack()->CanUndo(); +} + +//============================================================================= +/** + * return true if redo is possible + */ +bool CStudioApp::CanRedo() +{ + return m_Core->GetCmdStack()->CanRedo(); +} + +void CStudioApp::OnCopy() +{ + m_Core->GetDoc()->HandleCopy(); +} + +bool CStudioApp::CanCopy() +{ + return m_Core->GetDoc()->CanCopy(); +} + +//============================================================================= +/** + * Get a string describing the type of the copy operation that can be done. + * Precedence of copying is 1) Actions; 2) Keyframes; 3) Objects + */ +Q3DStudio::CString CStudioApp::GetCopyType() +{ + Q3DStudio::CString theCopyType; + + CDoc *theDoc = m_Core->GetDoc(); + if (theDoc->CanCopyAction()) + theCopyType = ::LoadResourceString(IDS_MENU_COPYPASTE_TYPE_ACTION); + else if (theDoc->CanCopyKeyframe()) + theCopyType = ::LoadResourceString(IDS_MENU_COPYPASTE_TYPE_KEYFRAMES); + else + theCopyType = ::LoadResourceString(IDS_MENU_COPYPASTE_TYPE_OBJECT); + + return theCopyType; +} + +//============================================================================= +/** + * Cuts the selected object or keys + */ +void CStudioApp::OnCut() +{ + m_Core->GetDoc()->HandleCut(); +} + +bool CStudioApp::CanCut() +{ + return m_Core->GetDoc()->CanCut(); +} + +//============================================================================= +/** + * Paste keys from the copied list yo + */ +void CStudioApp::OnPaste() +{ + m_Core->GetDoc()->HandlePaste(); +} + +bool CStudioApp::CanPaste() +{ + return m_Core->GetDoc()->CanPaste(); +} + +//============================================================================= +/** + * Get a string describing the type of the paste operation that can be done. + * Precedence of paste is 1) Actions; 2) Object ; 3) Keyframes + */ +Q3DStudio::CString CStudioApp::GetPasteType() +{ + Q3DStudio::CString thePasteType; + + CDoc *theDoc = m_Core->GetDoc(); + if (theDoc->CanPasteAction()) + thePasteType = ::LoadResourceString(IDS_MENU_COPYPASTE_TYPE_ACTION); + else if (theDoc->CanPasteObject()) + thePasteType = ::LoadResourceString(IDS_MENU_COPYPASTE_TYPE_OBJECT); + else + thePasteType = ::LoadResourceString(IDS_MENU_COPYPASTE_TYPE_KEYFRAMES); + + return thePasteType; +} + +bool CStudioApp::CanChangeTimebarColor() +{ + bool theRetVal = true; + UICDM::CUICDMInstanceHandle theSelectedInstance = m_Core->GetDoc()->GetSelectedInstance(); + if (!theSelectedInstance.Valid() + || m_Core->GetDoc()->GetStudioSystem()->GetClientDataModelBridge()->IsSceneInstance( + theSelectedInstance)) + theRetVal = false; + + return theRetVal; +} + +//============================================================================= +/** + * Sets any changed keyframes on the selected object + */ +void CStudioApp::HandleSetChangedKeys() +{ + m_Core->GetDoc()->SetChangedKeyframes(); +} + +//============================================================================= +/** + * Deletes all selected keys + */ +void CStudioApp::DeleteSelectedKeys() +{ + m_Core->GetDoc()->DeleteSelectedKeys(); +} + +//============================================================================= +/** + * Handles the duplicate object command + */ +void CStudioApp::HandleDuplicateCommand() +{ + m_Core->GetDoc()->HandleDuplicateCommand(); +} + +//============================================================================= +/** + * return true if the selected object is duplicatable + */ +bool CStudioApp::CanDuplicateObject() +{ + // Get the currently selected object + UICDM::CUICDMInstanceHandle theSelectedInstance = m_Core->GetDoc()->GetSelectedInstance(); + +#ifdef KDAB_TEMPORARILY_REMOVED + // Check if the object can be duplicated + return m_Core->GetDoc()->GetStudioSystem()->GetClientDataModelBridge()->IsDuplicateable( + theSelectedInstance); +#endif + return false; +} + +//============================================================================== +/** + * Toggles the state of autoset keyframes. + */ +void CStudioApp::OnToggleAutosetKeyframes() +{ + SetAutosetKeyframes(!CStudioPreferences::IsAutosetKeyframesOn()); + + m_Core->GetDispatch()->FireOnToolbarChange(); +} + +//============================================================================== +/** + * Updates the preferences, and AnimationSystem. + */ +void CStudioApp::SetAutosetKeyframes(bool inFlag) +{ + CStudioPreferences::SetAutosetKeyframesOn(inFlag); + + m_Core->GetDoc()->GetStudioSystem()->GetAnimationSystem()->SetAutoKeyframe(inFlag); +} + +//============================================================================== +/** + * If the presentation is not currently playing, this function will make it + * start playing from the current position. The starting point of the playhead + * is saved so that it can be restored later. + */ +void CStudioApp::PlaybackPlay() +{ + CDoc *theDoc = m_Core->GetDoc(); + if (!theDoc->IsPlaying()) { + m_PlaybackTime = theDoc->GetCurrentViewTime(); + m_PlaybackOriginalSlide = theDoc->GetActiveSlide(); + theDoc->SetPlayMode(PLAYMODE_PLAY); + } +} + +//============================================================================== +/** + * If the presentation is currently playing, it is stopped. The playhead is + * left wherever it was stopped at (hence it's not restored). + */ +void CStudioApp::PlaybackStopNoRestore() +{ + m_Core->GetDoc()->SetPlayMode(PLAYMODE_STOP); +} + +//============================================================================== +/** + * Moves the playhead back to time zero. + */ +void CStudioApp::PlaybackRewind() +{ + CDoc *theDoc = m_Core->GetDoc(); + if (theDoc->IsPlaying()) { + theDoc->SetPlayMode(PLAYMODE_STOP, 0); + theDoc->SetPlayMode(PLAYMODE_PLAY); + } else { + m_Core->GetDoc()->NotifyTimeChanged(0); + } +} + +//============================================================================= +/** + * Performs a file revert. + * This will revert the doc to the last saved version. + */ +void CStudioApp::OnRevert() +{ + if (!m_Core->GetDoc()->IsModified() || m_Dialogs->ConfirmRevert()) { + CUICFile theCurrentDoc = m_Core->GetDoc()->GetDocumentPath(); + OnLoadDocument(theCurrentDoc); + } +} + +//============================================================================= +/** + * Check to see if it is possible to perform a revert. + */ +bool CStudioApp::CanRevert() +{ + return m_Core->GetDoc()->IsModified() && m_Core->GetDoc()->GetDocumentPath().GetPath() != ""; +} + +//============================================================================== +/** + * Handles the recent list. + */ +void CStudioApp::OnFileOpenRecent(const CUICFile &inDocument) +{ + if (PerformSavePrompt()) + OnLoadDocument(inDocument); +} + +//============================================================================== +/** + * Called when closing the current doc, this prompts the user to save the doc. + * This will only prompt if the doc is modified, and if the user selects save + * then this will perform the save operation. + * @return true if the operation should continue, false if not. + */ +bool CStudioApp::PerformSavePrompt() +{ + if (m_Core->GetDoc()->IsModified()) { + CDialogs::ESavePromptResult theResult = m_Dialogs->PromptForSave(); + if (theResult == CDialogs::SAVE_FIRST) { + bool onSaveResult = OnSave(); + if (onSaveResult) + return true; + } else if (theResult == CDialogs::CONTINUE_NO_SAVE) + return true; + + return false; + } + return true; +} + +//============================================================================== +/** + * If the presentation is currently playing, it is stopped. The playhead is + * restored to the position found in m_PlaybackTime. + */ +void CStudioApp::PlaybackStop() +{ + CDoc *theDoc = m_Core->GetDoc(); + // change it back to the original slide first before restoring the original time + if (m_PlaybackOriginalSlide.Valid()) { + if (m_PlaybackOriginalSlide != theDoc->GetActiveSlide()) + theDoc->NotifyActiveSlideChanged(m_PlaybackOriginalSlide); + theDoc->SetPlayMode(PLAYMODE_STOP, m_PlaybackTime); + } + // Invalidate the playback original slide so we don't inadvertently trigger this code later. + m_PlaybackOriginalSlide = 0; +} + +//============================================================================= +/** + * Used for track wheel to do smooth tracking on mac, just scrolls the playhead. + */ +void CStudioApp::AdvanceTime() +{ + long theDeltaTime = CStudioPreferences::GetTimeAdvanceAmount(); + long theTime = + (m_Core->GetDoc()->GetCurrentViewTime() + theDeltaTime) / theDeltaTime * theDeltaTime; + m_Core->GetDoc()->NotifyTimeChanged(theTime); +} + +//============================================================================= +/** + * Used for track wheel to do smooth tracking on mac, just scrolls the playhead. + */ +void CStudioApp::ReduceTime() +{ + long theDeltaTime = CStudioPreferences::GetTimeAdvanceAmount(); + long theTime = (m_Core->GetDoc()->GetCurrentViewTime() - 1) / theDeltaTime * theDeltaTime; + m_Core->GetDoc()->NotifyTimeChanged(theTime); +} + +//============================================================================= +/** + * Used for track wheel to do smooth tracking on mac, just scrolls the playhead. + */ +void CStudioApp::AdvanceUltraBigTime() +{ + long theDeltaTime = CStudioPreferences::GetBigTimeAdvanceAmount(); + long theTime = + (m_Core->GetDoc()->GetCurrentViewTime() + theDeltaTime) / theDeltaTime * theDeltaTime; + m_Core->GetDoc()->NotifyTimeChanged(theTime); +} + +//============================================================================= +/** + * Used for track wheel to do smooth tracking on mac, just scrolls the playhead. + */ +void CStudioApp::ReduceUltraBigTime() +{ + long theDeltaTime = CStudioPreferences::GetBigTimeAdvanceAmount(); + long theTime = (m_Core->GetDoc()->GetCurrentViewTime() - 1) / theDeltaTime * theDeltaTime; + m_Core->GetDoc()->NotifyTimeChanged(theTime); +} + +//============================================================================== +/** + * If the presentation is currently playing, it is stopped. Otherwise, the + * presetation starts playing from its current position. Called when the user + * presses the Enter key. + */ +void CStudioApp::PlaybackToggle() +{ + // If the presentation is playing, stop it and leave the playhead where it is + if (m_Core->GetDoc()->IsPlaying()) + PlaybackStopNoRestore(); + // Otherwise, the presentation is stopped, so start it playing + else + PlaybackPlay(); +} + +CInspectableBase *CStudioApp::GetInspectableFromSelectable(Q3DStudio::SSelectedValue inSelectable) +{ + CInspectableBase *theInspectableBase = nullptr; + if (inSelectable.empty() == false) { + switch (inSelectable.getType()) { + case Q3DStudio::SelectedValueTypes::Slide: + theInspectableBase = new CUICDMInspectable( + *this, m_Core, inSelectable.getData().m_Instance); + break; + case Q3DStudio::SelectedValueTypes::MultipleInstances: + case Q3DStudio::SelectedValueTypes::Instance: { + + // We need to decide whether to display SlideInspectable or UICDMInspectable + // We display SlideInspectable if user selects a Scene or Component where the current + // active slide belongs, + // for example when user selects the Root in Timeline Palette + CDoc *theDoc = m_Core->GetDoc(); + UICDM::TInstanceHandleList theSelectedInstances = + theDoc->GetSelectedValue().GetSelectedInstances(); + UICDM::CUICDMInstanceHandle theSelectedInstance; + if (theSelectedInstances.size() == 1) + theSelectedInstance = theSelectedInstances[0]; + + if (m_Core->GetDoc()->GetDocumentReader().IsInstance(theSelectedInstance)) { + CClientDataModelBridge *theBridge = + theDoc->GetStudioSystem()->GetClientDataModelBridge(); + UICDM::CUICDMSlideHandle theCurrentActiveSlide = theDoc->GetActiveSlide(); + + // Slide, scene or component + if (theSelectedInstance + == theBridge->GetOwningComponentInstance(theCurrentActiveSlide)) { + CUICDMInstanceHandle theCurrentActiveSlideInstance = + theDoc->GetStudioSystem()->GetSlideSystem()->GetSlideInstance( + theCurrentActiveSlide); + + if (theBridge->IsSceneInstance(theSelectedInstance)) + theInspectableBase = new CUICDMSceneInspectable( + *this, m_Core, theSelectedInstance, theCurrentActiveSlideInstance); + else if (theBridge->IsComponentInstance(theSelectedInstance)) + theInspectableBase = new CUICDMInspectable( + *this, m_Core, theSelectedInstance, theCurrentActiveSlideInstance); + } + if (theInspectableBase == nullptr) { + if (theBridge->IsMaterialBaseInstance(theSelectedInstance)) + theInspectableBase = + new CUICDMMaterialInspectable(*this, m_Core, theSelectedInstance); + else + theInspectableBase = + new CUICDMInspectable(*this, m_Core, theSelectedInstance); + } + } + } break; + case Q3DStudio::SelectedValueTypes::Guide: { + UICDM::CUICDMGuideHandle theGuide = inSelectable.getData(); + theInspectableBase = CGuideInspectable::CreateInspectable(*m_Core, theGuide); + } break; + }; + } + + return theInspectableBase; +} + +void CStudioApp::RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler) +{ + inShortcutHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CStudioApp::AdvanceTime), 0, Qt::Key_Period); + inShortcutHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CStudioApp::ReduceTime), 0, Qt::Key_Comma); + inShortcutHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CStudioApp::AdvanceUltraBigTime), + Qt::ShiftModifier, Qt::Key_Greater); + inShortcutHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CStudioApp::ReduceUltraBigTime), + Qt::ShiftModifier, Qt::Key_Less); + inShortcutHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CStudioApp::OnToggleAutosetKeyframes), 0, Qt::Key_K); + inShortcutHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CStudioApp::OnSaveAs), + Qt::ControlModifier | Qt::ShiftModifier, Qt::Key_S); + inShortcutHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CStudioApp::OnSave), Qt::ControlModifier, + Qt::Key_S); + inShortcutHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CStudioApp::OnSaveCopy), + Qt::ControlModifier | Qt::AltModifier, Qt::Key_S); + inShortcutHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CStudioApp::OnFileNew), + Qt::ControlModifier, Qt::Key_N); + inShortcutHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CStudioApp::OnFileOpen), + Qt::ControlModifier, Qt::Key_O); + inShortcutHandler->RegisterKeyUpEvent( + new CDynHotKeyConsumer(this, &CStudioApp::PlaybackStop), 0, + Qt::Key_Space); + inShortcutHandler->RegisterKeyDownEvent( + new CDynHotKeyConsumer(this, &CStudioApp::PlaybackPlay), 0, + Qt::Key_Space); + inShortcutHandler->RegisterKeyDownEvent( + new CDynHotKeyConsumer(this, &CStudioApp::PlaybackToggle), 0, + Qt::Key_Return); + + if (m_Views) + m_Views->RegisterGlobalKeyboardShortcuts(inShortcutHandler); +} + +//============================================================================= +/** + * Handles the Save command + * This will save the file, if the file has not been saved before this will + * do a save as operation. + * @return true if the file was successfully saved. + */ +bool CStudioApp::OnSave() +{ + CUICFile theCurrentDoc = m_Core->GetDoc()->GetDocumentPath(); + if (!theCurrentDoc.IsFile()) { + return OnSaveAs(); + } else if (!theCurrentDoc.CanWrite()) { + m_Dialogs->DisplaySavingPresentationFailed(); + return false; + } else { + m_Core->OnSaveDocument(theCurrentDoc); + return true; + } +} + +//============================================================================= +/** + * Command handler for the File Save As menu option. + * This will prompt the user for a location to save the file out to then + * will perform the save. + * @return true if the file was successfully saved. + */ +bool CStudioApp::OnSaveAs() +{ + CUICFile theFile = m_Dialogs->GetSaveAsChoice().first; + if (theFile.GetPath() != "") { + m_Core->OnSaveDocument(theFile); + return true; + } + return false; +} + +//============================================================================= +/** + * Command handler for the File Save As menu option. + * This will prompt the user for a location to save the file out to then + * save a copy, leaving the original file open in the editor. + * @return true if the file was successfully saved. + */ +bool CStudioApp::OnSaveCopy() +{ + CUICFile theFile = m_Dialogs->GetSaveAsChoice().first; + if (theFile.GetPath() != "") { + // Send in a "true" to teh save function to indicate this is a copy + m_Core->OnSaveDocument(theFile, true); + return true; + } + return false; +} + +//============================================================================= +/** + * Call to load a new document. + * There should not be a currently active document when this is called. + * @param inDocument the path to the UIP file to be loaded. + * @param inShowStartupDialogOnError true to show startup dialog if loading document is error + * @return true if loading was successful + */ +bool CStudioApp::OnLoadDocument(const CUICFile &inDocument, bool inShowStartupDialogOnError) +{ + m_Core->GetDispatch()->FireOnProgressBegin(CString::fromQString(QObject::tr("Loading...")), inDocument.GetName(), + CString::fromQString(QObject::tr("Loading..."))); + + bool theLoadResult = false; + int theLoadErrorParameter = -1; + Q3DStudio::CString theErrorText; + try { + OnLoadDocumentCatcher(inDocument); + m_Core->GetDispatch()->FireOnOpenDocument(inDocument, true); + // Loading was successful + theLoadResult = true; + } catch (CUnsupportedFileFormatException &) { + theErrorText = CString::fromQString(QObject::tr("The file could not be opened. It is either invalid or was made with an " + "old version of Studio.")); + // We've encountered a file format that is older than the current, OR + // corrupt files, unsupported file formats and illegal types. + } catch (CInvalidFileFormatException &) { + theErrorText = CString::fromQString(QObject::tr("The file could not be opened. It appears to have been made with a newer " + "version of Studio.")); + // Cannot support opening newer file format, the UIP or (AP ie client portion)'s version is + // mismatched. + } catch (CLoadReferencedFileException &inError) { + // referenced files (e.g. Data Files) failed to load + theErrorText.Format(L"%ls failed to load due to invalid referenced file: %ls.", + static_cast(inDocument.GetName()), + inError.GetFilePath()); // TODO: Localize + const wchar_t *theDesc = inError.GetDescription(); + if (theDesc && wcslen(theDesc) > 0) { + // append any description is provided + theErrorText += L"\n"; + theErrorText += inError.GetDescription(); + } + } catch (CIOException &) { // provide specific error message if possible + if (inDocument.Exists() == false) + theLoadErrorParameter = IDS_ERROR_LOADFILENOTEXIST; + qCCritical(qt3ds::INTERNAL_ERROR) + << "Failed to load document, IO error (file may be unreadable or nonexistent)"; + } catch (...) { + qCCritical(qt3ds::INTERNAL_ERROR) << "Failed to load document, uknown error"; + // We don't know exactly what went wrong during a load, but let studio 'fail gracefully'. + } + + if (theErrorText.Length()) { + qCCritical(qt3ds::INTERNAL_ERROR) << "Failed to load document: " + << theErrorText.GetCharStar(); + } + + m_Core->GetDispatch()->FireOnProgressEnd(); + + // load fail + if (!theLoadResult) { + if (!theErrorText.IsEmpty()) + m_Dialogs->DisplayKnownErrorDialog(theErrorText); + else + m_Dialogs->DisplayLoadingPresentationFailed(inDocument, theLoadErrorParameter); + + m_Core->GetDispatch()->FireOnOpenDocument(inDocument, false); + + // Show startup dialog +#ifdef KDAB_TEMPORARILY_REMOVED + if (inShowStartupDialogOnError) + if (!ShowStartupDialog()) + PostQuitMessage(WM_QUIT); +#endif + } else { + m_Dialogs->ResetSettings(inDocument.GetPath()); + + m_subpresentations.clear(); + m_Core->GetDoc()->LoadUIASubpresentations(m_Core->GetDoc()->GetDocumentUIAFile(), + m_subpresentations); + } + + m_AuthorZoom = false; + + m_Core->GetDispatch()->FireAuthorZoomChanged(); + + return theLoadResult; +} + + +//============================================================================= +/** + * + */ +void CStudioApp::SaveUIAFile() +{ + QStringList list; + for (SubPresentationRecord r : m_subpresentations) { + list.append(r.m_type); + list.append(r.m_id); + list.append(r.m_argsOrSrc); + } + Q3DStudio::CFilePath doc(GetCore()->GetDoc()->GetDocumentPath().GetAbsolutePath()); + uic::state::IApplication::EnsureApplicationFile(doc.GetCharStar(), list); +} + +//============================================================================= +/** + * Called by OnLoadDocument, to allow the error reporting to be inserted. + * Because of the nature of the error reporting, OnLoadDocument has to have + * a certain structure that limits it (C type variables, no object destructors). + */ +void CStudioApp::OnLoadDocumentCatcher(const CUICFile &inDocument) +{ + { + CDispatchDataModelNotificationScope __scope(*m_Core->GetDispatch()); + m_Core->GetDoc()->CloseDocument(); + m_Core->GetDoc()->LoadDocument(inDocument); + } + + // Make sure the client scene is resized properly + if (m_Views) + m_Views->RecheckMainframeSizingMode(); +} + +void CStudioApp::OnFileOpen() +{ + if (PerformSavePrompt()) { + CUICFile theFile = m_Dialogs->GetFileOpenChoice(); + if (theFile.GetPath() != "") + OnLoadDocument(theFile); + } +} +using namespace std; + +void CStudioApp::OnFileNew() +{ + if (PerformSavePrompt()) { + pair theFile = m_Dialogs->GetNewDocumentChoice(); + if (theFile.first.GetPath() != "") + m_Core->OnNewDocument(theFile.first, theFile.second); + } +} + +bool CStudioApp::IsAuthorZoom() +{ + return m_AuthorZoom; +} + +void CStudioApp::SetAuthorZoom(bool inZoom) +{ + if (m_AuthorZoom != inZoom) { + m_AuthorZoom = inZoom; + m_Core->GetDispatch()->FireAuthorZoomChanged(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// These commands come over the dispatch from inside the core. The core doesn't +// have access to the CMsgRouter at the moment, so this relays the message. +void CStudioApp::OnAsynchronousCommand(CCmd *inCmd) +{ + CMsgRouter::GetInstance()->SendCommand(inCmd, m_Core); +} + +void CStudioApp::OnDisplayAppStatus(Q3DStudio::CString &inStatusMsg) +{ + // Do nothing, it was used to show this in the status bar +} + +void CStudioApp::OnProgressBegin(const Q3DStudio::CString &inActionText, + const Q3DStudio::CString &inFileName, + const Q3DStudio::CString &inWindowTitle) +{ + m_Dialogs->DisplayProgressScreen(inActionText, inFileName, inWindowTitle); +} + +void CStudioApp::OnProgressEnd() +{ + m_Dialogs->DestroyProgressScreen(); +} + +void CStudioApp::OnAssetDeleteFail() +{ + m_Dialogs->DisplayAssetDeleteFailed(); +} + +void CStudioApp::OnPasteFail() +{ + m_Dialogs->DisplayPasteFailed(); +} + +void CStudioApp::OnBuildconfigurationFileParseFail(const Q3DStudio::CString &inMessage) +{ + m_Dialogs->DisplayMessageBox(::LoadResourceString(IDS_BUILDCONFIGS_ERROR_TITLE), inMessage, + CUICMessageBox::ICON_ERROR, false); +} + +void CStudioApp::OnSaveFail(bool inKnownError) +{ + qCCritical(qt3ds::INTERNAL_ERROR) << "Failed to save project: " + << (inKnownError ? "KnownError" : "UnknownError"); + if (inKnownError) { + m_Dialogs->DisplaySavingPresentationFailed(); + } else { + m_Dialogs->DisplayKnownErrorDialog(::LoadResourceString(IDS_SAVE_UNKNOWN_ERROR)); + } +} + +void CStudioApp::OnProjectVariableFail(const Q3DStudio::CString &inMessage) +{ + m_Dialogs->DisplayEnvironmentVariablesError(inMessage); +} + +void CStudioApp::OnErrorFail(const Q3DStudio::CString &inText) +{ + qCCritical(qt3ds::INTERNAL_ERROR) << inText.GetCharStar(); + m_Dialogs->DisplayMessageBox(::LoadResourceString(IDS_PROJNAME), inText, + CUICMessageBox::ICON_ERROR, false); +} + +void CStudioApp::OnRefreshResourceFail(const Q3DStudio::CString &inResourceName, + const Q3DStudio::CString &inDescription) +{ + qCCritical(qt3ds::INTERNAL_ERROR) << "Failed to refresh resource: " + << inResourceName.GetCharStar(); + qCCritical(qt3ds::INTERNAL_ERROR) << inDescription.GetCharStar(); + m_Dialogs->DisplayRefreshResourceFailed(inResourceName, inDescription); +} + +void CStudioApp::OnNewPresentation() +{ + m_Core->GetDoc()->GetStudioSystem()->GetAnimationSystem()->SetAutoKeyframe( + CStudioPreferences::IsAutosetKeyframesOn()); + qCInfo(qt3ds::TRACE_INFO) << "New Presentation: " + << m_Core->GetDoc()->GetDocumentPath().GetAbsolutePath().GetCharStar(); +} + +void CStudioApp::OnPresentationModifiedExternally() +{ + int theUserChoice = m_Dialogs->DisplayChoiceBox( + ::LoadResourceString(IDS_TITLE_WARNING), + ::LoadResourceString(IDS_PRESENTATION_MODIFIED_EXTERNALLY), CUICMessageBox::ICON_WARNING); + if (theUserChoice == IDYES) { + CUICFile theCurrentDoc = m_Core->GetDoc()->GetDocumentPath(); + OnLoadDocument(theCurrentDoc); + } +} diff --git a/src/Authoring/Studio/_Win/Application/StudioApp.h b/src/Authoring/Studio/_Win/Application/StudioApp.h new file mode 100644 index 00000000..caea5158 --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/StudioApp.h @@ -0,0 +1,255 @@ +/**************************************************************************** +** +** 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_STUDIO_APP_H +#define INCLUDED_STUDIO_APP_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "CmdLineParser.h" +#include "StudioObjectTypes.h" +#ifdef KDAB_TEMPORARILY_REMOVED +#include +#include +#endif +#include "DispatchListeners.h" +#include "UICDMHandles.h" + +#include + +namespace Q3DStudio { +class IInternalDirectoryWatchingSystem; +class IDirectoryWatchingSystem; +class ITickTock; +class IStudioRenderer; +struct SSelectedValue; +}; + +namespace UICDM { +class ISignalConnection; +}; + +struct StudioManipulationModes +{ + enum Enum { + Local, + Global, + }; +}; + +//============================================================================== +// Forwards +//============================================================================== +class CCore; +class CDialogs; +class CSplashView; +class CInspectableBase; +class CDirectoryWatchingSystemWrapper; +class CHotKeys; +class CViews; +class CMainFrame; +enum EStudioObjectType; +struct SubPresentationRecord; + +class CStudioApp : public CCoreAsynchronousEventListener, + public CAppStatusListener, + public CFailListener, + public CPresentationChangeListener // to setup auto set keyframes +{ +public: + CStudioApp(); + virtual ~CStudioApp(); + + // Overrides +public: + virtual BOOL InitInstance(int argc, char *argv[]); + virtual int ExitInstance(); + virtual int Run(); +#ifdef KDAB_TEMPORARILY_REMOVED + virtual UINT GetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nDefault); + virtual BOOL WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue); + virtual ::CString GetProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, + LPCTSTR lpszDefault = nullptr); + virtual BOOL WriteProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue); +#endif + + void OnAppAbout(); + +public: + void PerformShutdown(); +#ifdef KDAB_TEMPORARILY_REMOVED + static void StudioUnhandledCrashHandler(EXCEPTION_POINTERS *pExPtrs); +#endif + Q3DStudio::IDirectoryWatchingSystem &GetDirectoryWatchingSystem(); + void SetupTimer(long inMessageId, QWidget *inWnd); + Q3DStudio::ITickTock &GetTickTock(); + Q3DStudio::IStudioRenderer &GetRenderer(); + void ClearGuides(); + +protected: + int RunApplication(); + int BlankRunApplication(); + int RunCmdLineTests(const Q3DStudio::CString &inTestArgs); + int RunSystemTests(const Q3DStudio::CString &inTestArgs); + int OpenAndRunApplication(const Q3DStudio::CString &inFilename); + void InitCore(); + void InitHelpSystem(); + bool ShowStartupDialog(); + bool HandleWelcomeRes(int res, bool recursive); + + CCore *m_Core; + CSplashView *m_SplashPalette; ///< Startup splash palette + QString m_OldHelpFilePath; ///< Stores a pointer to the old + CCmdLineParser m_CmdLineParser; ///< Stores and returns execution modes + int m_UnitTestResults; ///< 0 on success; 1 on failure + bool m_IsSilent; ///< true indicates Studio running in silent mode (no GUI) + CViews *m_Views; + long m_ToolMode; + StudioManipulationModes::Enum + m_ManipulationMode; ///< Controls what space the tras,rot,and scale manipulations work in. + long m_SelectMode; + CDialogs *m_Dialogs; + long m_PlaybackTime; ///< Stores the playhead's starting position so that it can be restored + ///after playing the presentation for a little while + UICDM::CUICDMSlideHandle + m_PlaybackOriginalSlide; ///< Stores the current slide handle before playback started. + + std::shared_ptr m_TickTock; + std::shared_ptr m_DirectoryWatchingSystem; + std::shared_ptr m_DirectoryWatcherTicker; + std::shared_ptr m_Renderer; + bool m_AuthorZoom; + +private: +#ifdef KDAB_TEMPORARILY_REMOVED + Gdiplus::GdiplusStartupInput m_gdiplusStartupInput; + ULONG_PTR m_pGdiToken; +#endif + + bool m_welcomeShownThisSession; + // are we are launching welcome screen again due to + // user canceling file dialog? + bool m_goStraightToWelcomeFileDialog; + int m_tutorialPage; +public: + CMainFrame* m_pMainWnd; + + CCore *GetCore(); + CViews *GetViews(); + CDialogs *GetDialogs(); + long GetToolMode(); + void SetToolMode(long inToolMode); + long GetSelectMode(); + void SetSelectMode(long inSelectMode); + + StudioManipulationModes::Enum GetMinpulationMode() const; + void SetMinpulationMode(StudioManipulationModes::Enum inManipulationMode); + + bool CanUndo(); + bool CanRedo(); + void OnCopy(); + bool CanCopy(); + Q3DStudio::CString GetCopyType(); + void OnCut(); + bool CanCut(); + void OnPaste(); + bool CanPaste(); + Q3DStudio::CString GetPasteType(); + void SetSelectedObjectTimebarColor(); + bool CanChangeTimebarColor(); + void HandleSetChangedKeys(); + void DeleteSelectedKeys(); + void HandleDuplicateCommand(); + bool CanDuplicateObject(); + void OnToggleAutosetKeyframes(); + void SetAutosetKeyframes(bool inFlag); + void PlaybackPlay(); + void PlaybackStopNoRestore(); + void PlaybackRewind(); + void OnRevert(); + bool CanRevert(); + void OnFileOpenRecent(const CUICFile &inDocument); + bool PerformSavePrompt(); + void PlaybackStop(); + void AdvanceTime(); + void ReduceTime(); + void AdvanceUltraBigTime(); + void ReduceUltraBigTime(); + void PlaybackToggle(); + CInspectableBase *GetInspectableFromSelectable(Q3DStudio::SSelectedValue inSelectable); + void RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler); + bool OnSave(); + bool OnSaveAs(); + bool OnSaveCopy(); + bool OnLoadDocument(const CUICFile &inDocument, bool inShowStartupDialogOnError = true); + void OnLoadDocumentCatcher(const CUICFile &inLocation); + void OnFileOpen(); + void OnFileNew(); + bool IsAuthorZoom(); + void SetAuthorZoom(bool inZoom); + + // CCoreAsynchronousEventListener + void OnAsynchronousCommand(CCmd *inCmd) override; + + // CAppStatusListener + void OnDisplayAppStatus(Q3DStudio::CString &inStatusMsg) override; + void OnProgressBegin(const Q3DStudio::CString &inActionText, + const Q3DStudio::CString &inFileName, + const Q3DStudio::CString &inWindowTitle) override; + void OnProgressEnd() override; + + // CFailListener + void OnAssetDeleteFail() override; + void OnPasteFail() override; + void OnBuildconfigurationFileParseFail(const Q3DStudio::CString &inMessage) override; + void OnSaveFail(bool inKnownError) override; + void OnProjectVariableFail(const Q3DStudio::CString &inMessage) override; + void OnErrorFail(const Q3DStudio::CString &inText) override; + void OnRefreshResourceFail(const Q3DStudio::CString &inResourceName, + const Q3DStudio::CString &inDescription) override; + + // CPresentationChangeListener + void OnNewPresentation() override; + void OnPresentationModifiedExternally() override; + + Q3DStudio::CString m_pszHelpFilePath; + + QVector m_subpresentations; + void SaveUIAFile(); +}; + +extern CStudioApp g_StudioApp; + +#endif // INCLUDED_STUDIO_APP_H diff --git a/src/Authoring/Studio/_Win/Application/StudioColors.h b/src/Authoring/Studio/_Win/Application/StudioColors.h new file mode 100644 index 00000000..776047a5 --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/StudioColors.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2002 Anark Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_STUDIOCOLORS_H +#define INCLUDED_STUDIOCOLORS_H + +#pragma once + +//============================================================================== +// Studio colors +//============================================================================== + +const COLORREF STUDIO_MATTE_COLOR = RGB(119, 122, 125); // GetSysColor( COLOR_APPWORKSPACE ); +const COLORREF MENU_IMAGELIST_BACKCOLOR = RGB(255, 0, 255); // RGB( 255, 128, 0 ); + +//============================================================================== +// TimeBar colors +//============================================================================== + +// TimeBar pen colors + +const COLORREF TIMEBAR_PEN_COLOR_INNER = RGB(254, 254, 254); +const COLORREF TIMEBAR_PEN_COLOR_INACTIVE = RGB(132, 130, 132); +const COLORREF TIMEBAR_PEN_COLOR_ACTIVE = RGB(0, 0, 0); + +// TimeBar shadow colors + +const COLORREF TIMEBAR_INACTIVE_SHADOW_COLOR = RGB(0xC4, 0xC4, 0xC4); +const COLORREF TIMEBAR_ACTIVE_SHADOW_COLOR = RGB(0x84, 0x84, 0x84); + +// TimeBar comment colors + +const COLORREF TIMEBAR_COMMENT_ACTIVE_TC = RGB(0x00, 0x00, 0x00); +const COLORREF TIMEBAR_COMMENT_INACTIVE_TC = RGB(0x72, 0x72, 0x72); + +const COLORREF COLOR_TIMEBAR_DISABLED = RGB(207, 207, 207); +const COLORREF COLOR_TIMEBAR_BEHAVIOR = + RGB(148, 189, 150); // RGB( 92, 164, 131 );//RGB( 243, 243, 243 ); +const COLORREF COLOR_TIMEBAR_MATERIAL = + RGB(194, 155, 181); // RGB( 190, 184, 152 ); //RGB( 239, 230, 210 ); +const COLORREF COLOR_TIMEBAR_IMAGE = + RGB(194, 155, 181); // RGB( 190, 184, 152 ); //RGB( 198, 225, 199 ); +const COLORREF COLOR_TIMEBAR_LOCKED = RGB(228, 228, 228); + +const COLORREF TIMEBAR_COLOR_TRANSPARENT = RGB(255, 0, 255); + +// A constant to represent color for inner white rectangle of center bar +const COLORREF COLOR_INNER_BAR_RECTANGLE = RGB(253, 253, 254); +// Default timebar fill color +const COLORREF COLOR_TIMEBAR_DEFAULT_FILL = RGB( + 163, 178, 227); // RGB( 174, 183, 210 ); //RGB( 148, 166, 189 ); //RGB( 211, 226, 240 ); + +// Selected time bar colors + +const COLORREF COLOR_TIMEBAR_SELECTED = RGB(75, 75, 75); // RGB( 14, 49, 98 ); +const COLORREF COLOR_TIMEBAR_SELECTED_TEXT = RGB(255, 255, 255); +const COLORREF COLOR_TIMEBAR_SELECTED_BEHAVIOR = RGB(174, 216, 176); +const COLORREF COLOR_TIMEBAR_SELECTED_HIGHLIGHT = RGB(27, 73, 136); + +// const COLORREF COLOR_SELECTED_TIMEBAR_3DOBJECT = RGB( 190, 191, 202 +// ); + +const COLORREF COLOR_TIMEBAR_HIGHLIGHT = RGB(190, 191, 202); +const COLORREF COLOR_TIMEBAR_HIGHLIGHT_GROUP = RGB(174, 216, 176); + +const COLORREF COLOR_PLAYHEADSCRUBTIME = RGB(0, 85, 0); + +//============================================================================== +// Timeline colors +//============================================================================== + +const BOOL INVERT_TIMELINE_TEXT_COLOR = TRUE; + +const COLORREF COLOR_SELECTEDTEXT = RGB(255, 255, 255); +const COLORREF COLOR_SELECTEDTEXTBKGRND = RGB(14, 49, 98); +const COLORREF COLOR_DRAGDROPTARGETTEXT = RGB(255, 255, 255); +const COLORREF COLOR_DRAGDROPTARGETBKGRND = RGB(24, 98, 198); + +const COLORREF COLOR_SHADOW = RGB(165, 162, 161); // RGB( 132, 130, 132 ); + +const COLORREF COLOR_PLAYHEADLINE = RGB(0xDD, 0x04, 0x05); +const COLORREF COLOR_BACKGRND = + GetSysColor(COLOR_3DFACE); // RGB( 206, 203, 198 ); //RGB( 0xE7, 0xE7, 0xE7 ); +const COLORREF COLOR_SELECTED = RGB(255, 255, 255); +const COLORREF COLOR_DEFAULTOBJECTS = RGB(206, 203, 198); // RGB( 0xE7, 0xE7, 0xE7 ); +const COLORREF COLOR_3DOBJECTS = RGB(206, 203, 198); // RGB( 0xC7, 0xD4, 0xE1 ); +const COLORREF COLOR_DEFAULTOBJECTHIGHLIGHT = RGB(222, 223, 222); // RGB( 255, 255, 255 ); +const COLORREF COLOR_DRAGHIGHLIGHT = RGB(255, 255, 255); +const COLORREF COLOR_INSERTMARK = RGB(0x00, 0x00, 0x00); +const COLORREF COLOR_TIMELINEINSERTMARK = RGB(0x00, 0x00, 0xFF); +const COLORREF COLOR_TEXTCOLOR = RGB(0x00, 0x00, 0x00); +const COLORREF COLOR_CONTAINERTEXTCOLOR = RGB(80, 80, 140); +const COLORREF COLOR_LOCKEDTEXTCOLOR = RGB(0x80, 0x80, 0x80); +const COLORREF COLOR_INDEPENDENTOBJECT = RGB(0x80, 0x80, 0x80); +const COLORREF COLOR_SPLITLINE = RGB(0x00, 0x00, 0x7F); +const COLORREF COLOR_SEPARATORLINE = RGB(0x00, 0x00, 0x20); +const COLORREF COLOR_LIGHTMODEL = RGB(206, 203, 198); // RGB( 198, 211, 224 ); +const COLORREF COLOR_GROUP = + RGB(206, 203, 198); // RGB( 198, 211, 224 ); //RGB( 199, 220, 193 ); +const COLORREF COLOR_PROPERTY = RGB(228, 225, 219); // RGB( 241, 241, 241 ); +const COLORREF COLOR_CHANNEL = RGB(228, 225, 219); // RGB( 241, 241, 241 ); +const COLORREF COLOR_CONTAINER = + RGB(228, 225, 219); // RGB( 206, 203, 198 ); //RGB( 231, 231, 231 ); +const COLORREF COLOR_MATERIAL = RGB(210, 210, 210); // RGB( 170, 224, 170 ); +const COLORREF COLOR_CONTAINERHIGHLIGHT = RGB(193, 180, 180); +const COLORREF COLOR_BEHAVIOR = RGB(199, 220, 193); +const COLORREF COLOR_BEHAVIORHIGHLIGHT = RGB(255, 255, 255); +const COLORREF COLOR_IMGLISTTRANSPARENT = RGB(0xFF, 0x00, 0xFF); +const COLORREF COLOR_TIMEMEASURE = GetSysColor(COLOR_3DFACE); // RGB( 170, 166, 160 ); + +#endif diff --git a/src/Authoring/Studio/_Win/Application/SubPresentationsDlg.cpp b/src/Authoring/Studio/_Win/Application/SubPresentationsDlg.cpp new file mode 100644 index 00000000..e3e25fa1 --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/SubPresentationsDlg.cpp @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "StudioDefs.h" +#include "Strings.h" +#include "StringLoader.h" + +//============================================================================== +// Includes +//============================================================================== +#include "SubPresentationsDlg.h" +#include "ui_SubPresentationsDlg.h" +#include "ProductInfo.h" +#include "HotKeys.h" +#include "Preferences.h" +#include "StudioPreferences.h" + +#include +#include +#include +#include + +CSubPresentationsDlg::CSubPresentationsDlg( + const QString &directory, + const QVector &subpresentations, + QWidget *parent) + : QDialog(parent, Qt::MSWindowsFixedSizeDialogHint) + , m_directory(directory) + , m_records(subpresentations) + , m_ui(new Ui::SubPresentationsDlg) +{ + m_ui->setupUi(this); + + connect(m_ui->deleteButton, &QPushButton::clicked, this, + &CSubPresentationsDlg::OnDeletePresentation); + connect(m_ui->pushButtonNew, &QPushButton::clicked, this, + &CSubPresentationsDlg::OnNewPresentation); + connect(m_ui->pushButtonBrowse, &QPushButton::clicked, this, + &CSubPresentationsDlg::OnBrowsePresentation); + connect(m_ui->comboBox, static_cast(&QComboBox::currentIndexChanged), + this, &CSubPresentationsDlg::OnSelectPresentation); + connect(m_ui->lineEditId, &QLineEdit::textEdited, this, &CSubPresentationsDlg::OnIdChanged); + + OnInitDialog(); +} + +CSubPresentationsDlg::~CSubPresentationsDlg() +{ + delete m_ui; +} + +QVector CSubPresentationsDlg::subpresentations() const +{ + return m_records; +} + +void CSubPresentationsDlg::OnInitDialog() +{ + current = -1; + if (m_records.size() > 0) { + for (SubPresentationRecord rec : m_records) + m_ui->comboBox->addItem(rec.m_id); + current = 0; + m_ui->lineEditId->setText(m_records[0].m_id); + m_ui->lineEditPreview->setText(m_records[0].m_argsOrSrc); + } + m_ui->lineEditPreview->setReadOnly(true); + m_ui->buttonBox->setFocusPolicy(Qt::NoFocus); +} + +void CSubPresentationsDlg::OnSelectPresentation(int selectionIndex) +{ + if (selectionIndex >= 0 && selectionIndex < m_records.size()) { + current = selectionIndex; + m_ui->lineEditId->setText(m_records[current].m_id); + m_ui->lineEditPreview->setText(m_records[current].m_argsOrSrc); + } else { + m_ui->lineEditId->setText(QString()); + m_ui->lineEditPreview->setText(QString()); + } +} + +void CSubPresentationsDlg::OnDeletePresentation() +{ + if (current >= 0 && current < m_records.size()) { + m_records.remove(current); + m_ui->comboBox->removeItem(current); + current = qMax(current - 1, 0); + if (m_records.size() == 0) + current = -1; + OnSelectPresentation(current); + } +} + +void CSubPresentationsDlg::OnNewPresentation() +{ + int index = m_records.size(); + m_records.push_back( + SubPresentationRecord(QStringLiteral("presentation-qml"), + QStringLiteral("presentation-id"), QString())); + m_ui->comboBox->addItem(QStringLiteral("presentation-id")); + m_ui->comboBox->setCurrentIndex(index); + OnSelectPresentation(index); +} + +void CSubPresentationsDlg::OnBrowsePresentation() +{ + const QString file = QDir::toNativeSeparators( + QFileDialog::getOpenFileName(nullptr, nullptr, m_directory, + QStringLiteral("*.qml; *.uip"))); + QString shortFile = file; + int subdir = file.indexOf(m_directory); + if (subdir >= 0) + shortFile.remove(subdir, m_directory.size() + 1); + + QFileInfo fileInfo(file); + if (fileInfo.exists()) { + if (fileInfo.suffix() == QStringLiteral("qml")) + m_records[current].m_type = QStringLiteral("presentation-qml"); + else + if (fileInfo.suffix() == QStringLiteral("uip")) + m_records[current].m_type = QStringLiteral("presentation"); + + m_records[current].m_argsOrSrc = shortFile; + m_ui->lineEditPreview->setText(shortFile); + } +} + +void CSubPresentationsDlg::OnIdChanged(const QString &text) +{ + m_records[current].m_id = text; + m_ui->comboBox->setItemText(current, text); +} + +void CSubPresentationsDlg::on_buttonBox_accepted() +{ + QDialog::accept(); +} + +void CSubPresentationsDlg::on_buttonBox_rejected() +{ + QDialog::reject(); +} diff --git a/src/Authoring/Studio/_Win/Application/SubPresentationsDlg.h b/src/Authoring/Studio/_Win/Application/SubPresentationsDlg.h new file mode 100644 index 00000000..75828c4e --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/SubPresentationsDlg.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 SUBPRESENTATIONSDLG_H +#define SUBPRESENTATIONSDLG_H + +#include + +#include "UICString.h" +#include "Doc.h" + +#ifdef QT_NAMESPACE +using namespace QT_NAMESPACE; +#endif + +QT_BEGIN_NAMESPACE +namespace Ui { + class SubPresentationsDlg; +} +QT_END_NAMESPACE + +class CSubPresentationsDlg : public QDialog +{ + Q_OBJECT +public: + CSubPresentationsDlg(const QString &directory, + const QVector &subpresentations, + QWidget* parent = nullptr); + ~CSubPresentationsDlg(); + + // Implementation +protected: + + void OnInitDialog(); + +public: + + QVector subpresentations() const; + + void OnDeletePresentation(); + void OnNewPresentation(); + void OnBrowsePresentation(); + void OnSelectPresentation(int selectionIndex); + void OnIdChanged(const QString &text); + +private Q_SLOTS: + void on_buttonBox_accepted(); + void on_buttonBox_rejected(); + +private: + QString m_directory; + QVector m_records; + Ui::SubPresentationsDlg *m_ui; + int current; +}; + +#endif diff --git a/src/Authoring/Studio/_Win/Application/SubPresentationsDlg.ui b/src/Authoring/Studio/_Win/Application/SubPresentationsDlg.ui new file mode 100644 index 00000000..db673925 --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/SubPresentationsDlg.ui @@ -0,0 +1,152 @@ + + + SubPresentationsDlg + + + + 0 + 0 + 512 + 169 + + + + Sub-presentations + + + + + 10 + 130 + 491 + 31 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::NoFocus + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + 10 + 10 + 491 + 111 + + + + + + + + + Sub-presentation + + + + + + + Presentation Id + + + + + + + Filename + + + + + + + + + + + + + + <html><head/><body><p>Edit the name of the sub-presentation</p></body></html> + + + + + + + + + + + + + + + + + + + + + <html><head/><body><p>Delete currently selected sub-presentation</p></body></html> + + + Remove + + + + + + + <html><head/><body><p>Add new sub-presentation</p></body></html> + + + Add + + + + + + + <html><head/><body><p>Browse for the sub-presentation source</p></body></html> + + + Browse... + + + + + + + + + + + diff --git a/src/Authoring/Studio/_Win/Application/TextLink.cpp b/src/Authoring/Studio/_Win/Application/TextLink.cpp new file mode 100644 index 00000000..a68aaea8 --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/TextLink.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** 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" + +#ifdef _DEBUG +//#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +//============================================================================== +// Includes +//============================================================================== + +#include "TextLink.h" +#include "Resource.h" + +///////////////////////////////////////////////////////////////////////////// +// CTextLink class + +//============================================================================== +/** + * Constructor: Initializes the object. + */ +//============================================================================== +CTextLink::CTextLink() + : CBaseLink() +{ + // Set default colors + m_ColorText = CStudioPreferences::GetNormalColor(); + m_ColorBackground = CStudioPreferences::GetBaseColor(); +} + +//============================================================================== +/** + * Destructor: Releases the object. + */ +//============================================================================== +CTextLink::~CTextLink() +{ +} + +//============================================================================== +/** + * SetColor: Sets the text color and background color + * + * @param inText Text color for the control. + * @param inBackground Background color for the control. + */ +//============================================================================== +void CTextLink::SetColor(COLORREF inText, COLORREF inBackground) +{ + m_ColorText = inText; + m_ColorBackground = inBackground; +} + +//============================================================================== +/** + * ShowLink: Shows the link. + * + * @param None + */ +//============================================================================== +void CTextLink::ShowLink() +{ + if (IsWindow(m_hWnd)) { + ShowTextLink(m_ColorText, m_ColorBackground, DT_VCENTER | DT_SINGLELINE, m_bCapture); + } +} diff --git a/src/Authoring/Studio/_Win/Application/TextLink.h b/src/Authoring/Studio/_Win/Application/TextLink.h new file mode 100644 index 00000000..85f5fedf --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/TextLink.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** 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 _TEXTLINK_H_ +#define _TEXTLINK_H_ + +#include "BaseLink.h" + +///////////////////////////////////////////////////////////////////////////// +// CTextLink window + +class CTextLink : public CBaseLink +{ + // Construction +public: + CTextLink(); + + // Attributes +public: + // Operations +public: + virtual void SetColor(COLORREF inText, COLORREF inBackground); + +protected: + COLORREF m_ColorText; + COLORREF m_ColorBackground; + + virtual void ShowLink(); + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CTextLink) + //}}AFX_VIRTUAL + + // Implementation +public: + virtual ~CTextLink(); + + // Generated message map functions +protected: + //{{AFX_MSG(CTextLink) + //}}AFX_MSG +}; + +///////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/src/Authoring/Studio/_Win/Application/WebLink.cpp b/src/Authoring/Studio/_Win/Application/WebLink.cpp new file mode 100644 index 00000000..258bdffb --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/WebLink.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" + +#ifdef _DEBUG +//#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +//============================================================================== +// Includes +//============================================================================== + +#include "WebLink.h" +#include "Resource.h" +#include "BCMenu.h" +#include "StudioColors.h" + +///////////////////////////////////////////////////////////////////////////// +// CWebLink class + +//============================================================================== +/** + * Constructor: Initializes the object. + */ +//============================================================================== +CWebLink::CWebLink() + : CBaseLink() +{ + // Set default link colors + m_ColorLink = CStudioPreferences::GetMasterColor(); // green + m_ColorHighlight = RGB(0xFF, 0x00, 0x00); // red + m_ColorVisited = RGB(0x7F, 0x00, 0x7F); // purple + m_ColorBackground = CStudioPreferences::GetDarkBaseColor(); + + m_bVisited = FALSE; + + m_URL.Empty(); + + m_Bitmap = nullptr; + + m_bPopup = FALSE; +} + +//============================================================================== +/** + * Destructor: Releases the object. + */ +//============================================================================== +CWebLink::~CWebLink() +{ +} + +//============================================================================== +// Message Map +//============================================================================== + +BEGIN_MESSAGE_MAP(CWebLink, CWnd) +//{{AFX_MSG_MAP(CWebLink) +ON_WM_PAINT() +ON_WM_SETCURSOR() +ON_WM_LBUTTONDOWN() +ON_WM_MOUSEMOVE() +ON_WM_CONTEXTMENU() +//}}AFX_MSG_MAP +END_MESSAGE_MAP() + +//============================================================================== +/** + * SetURL: Sets the URL for the control. + * + * @param inURL URL to point the default browser to when the control is clicked. + */ +//============================================================================== +void CWebLink::SetURL(CString inURL) +{ + m_URL = inURL; +} + +//============================================================================== +/** + * SetImage: Sets an bitmap image for the control. + * + * @param inResBmp BITMAP resource for the image to load. + * @param inAutoSizeFlag TRUE if the control should be resized to the image size. + */ +//============================================================================== +void CWebLink::SetImage(UINT inResBmp, bool inAutoSizeFlag) +{ + HBITMAP theBitmap = (HBITMAP)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(inResBmp), + IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); + + if (theBitmap != nullptr) { + this->SetImage(theBitmap, inAutoSizeFlag); + } +} + +//============================================================================== +/** + * SetImage: Sets an bitmap image for the control. + * + * @param inBitmap HBITMAP handle of the loaded bitmap. + * @param inAutoSizeFlag TRUE if the control should be resized to the image size. + */ +//============================================================================== +void CWebLink::SetImage(HBITMAP inBitmap, bool inAutoSizeFlag) +{ + m_Bitmap = inBitmap; + + if (inAutoSizeFlag && m_Bitmap != nullptr) { + // Resize this control based on the size of the bitmap. + BITMAP theBitmapStruct; + int theWidth, theHeight; + + GetObject(m_Bitmap, sizeof(BITMAP), &theBitmapStruct); + theWidth = theBitmapStruct.bmWidth; + theHeight = theBitmapStruct.bmHeight; + + SetWindowPos(nullptr, 0, 0, theWidth, theHeight, SWP_NOZORDER | SWP_NOMOVE); + } + + this->ShowLink(); +} + +//============================================================================== +/** + * SetText: Sets the text for the control. + * + * @param inText Text for the control. + */ +//============================================================================== +void CWebLink::SetText(CString inText) +{ + SetWindowText(inText); + m_Bitmap = nullptr; + this->ShowLink(); +} + +COLORREF CWebLink::GetColor() +{ + if (m_bCapture) { + return m_ColorHighlight; + } else { + if (m_bVisited) + return m_ColorVisited; + else + return m_ColorLink; + } +} + +//============================================================================== +/** + * ShowLink: Shows the link. + * + * @param None + */ +//============================================================================== +void CWebLink::ShowLink() +{ + if (IsWindow(m_hWnd)) { + // Is the link represented by an image? + if (m_Bitmap != nullptr) { + ShowBitmapLink(); + } else { + ShowTextLink(GetColor(), m_ColorBackground, DT_WORDBREAK | SS_LEFT, true); + } + } +} + +//============================================================================== +/** + * ShowLink: Shows the bitmap link. + * + * @param None + */ +//============================================================================== +void CWebLink::ShowBitmapLink() +{ + if (IsWindow(m_hWnd)) { + CRect theRect; + CDC *theDC; + CDC theMemDC; + + BITMAP theBitmapStruct; + long theWidth, theHeight; + CBrush theBrush; + + theDC = GetDC(); + theMemDC.CreateCompatibleDC(theDC); + CBitmap *theBitmap = CBitmap::FromHandle(m_Bitmap); + + CBitmap *theOldBmp = (CBitmap *)theMemDC.SelectObject(theBitmap); + + GetObject(m_Bitmap, sizeof(BITMAP), &theBitmapStruct); + theWidth = theBitmapStruct.bmWidth; + theHeight = theBitmapStruct.bmHeight; + + theDC->BitBlt(0, 0, theWidth, theHeight, &theMemDC, 0, 0, SRCCOPY); + + COLORREF theColor = GetColor(); + if (theColor == m_ColorHighlight || theColor == m_ColorVisited) { + // Draw a highlight frame + GetClientRect(&theRect); + + theBrush.CreateSolidBrush(theColor); + theDC->FrameRect(&theRect, &theBrush); + theBrush.DeleteObject(); + } + + theMemDC.SelectObject(theOldBmp); + + theMemDC.DeleteDC(); + ReleaseDC(theDC); + } +} + +//============================================================================== +/** + * JumpLink: Jumps to the link URL. + * + * @param None + */ +//============================================================================== +void CWebLink::JumpLink() +{ + CString theWebLink; + + GetWindowText(theWebLink); + + if (!m_URL.IsEmpty()) + theWebLink = m_URL; + + if (!theWebLink.IsEmpty()) { + this->OpenURL(theWebLink); + } +} + +//============================================================================== +/** + * OpenURL: Opens the specified URL with the default browser. + * + * @param inURL URL to open with the browser. + */ +//============================================================================== +void CWebLink::OpenURL(CString inURL) +{ + HCURSOR thePrevCursor; + + thePrevCursor = SetCursor(LoadCursor(nullptr, IDC_APPSTARTING)); + ShellExecute(GetSafeHwnd(), L"open", inURL, nullptr, nullptr, SW_SHOWNORMAL); + SetCursor(thePrevCursor); +} + +///////////////////////////////////////////////////////////////////////////// +// CWebLink message handlers + +//============================================================================== +/** + * OnSetCursor + * + * Handle the WM_SETCURSOR message. + * + * @param inWnd Pointer to the parent CWnd object. + * @param inHitTest Specifies the hit-test area code. The hit test determines the + *cursor�s location. + * @param inMessage Specifies the mouse message number. + */ +//============================================================================== +BOOL CWebLink::OnSetCursor(CWnd *inWnd, UINT inHitTest, UINT inMessage) +{ + UNREFERENCED_PARAMETER(inWnd); + UNREFERENCED_PARAMETER(inHitTest); + UNREFERENCED_PARAMETER(inMessage); + + if (m_bPopup) { + SetCursor(LoadCursor(nullptr, IDC_ARROW)); + } else { + SetCursor(LoadCursor(nullptr, IDC_HAND)); + } + + return TRUE; +} + +//============================================================================== +/** + * OnLButtonDown + * + * Windows callback handler for the WM_LBUTTONDOWN message + * + * @param inFlags Flags for the left button down message + * @param inPoint Point where the mouse was left clicked (client coordinates) + */ +//============================================================================== +void CWebLink::OnLButtonDown(UINT inFlags, CPoint inPoint) +{ + UNREFERENCED_PARAMETER(inFlags); + UNREFERENCED_PARAMETER(inPoint); + + if (IsWindowEnabled()) { + m_bCapture = FALSE; + ReleaseCapture(); + + m_bVisited = TRUE; + this->ShowLink(); + + this->JumpLink(); + } +} + +//============================================================================== +/** + * OnContextMenu: Handle for the WM_CONTEXTMENU message. + * + * @param inWnd Window for the context menu. + * @param inPoint Mouse position when the right button was clicked. + */ +//============================================================================== +void CWebLink::OnContextMenu(CWnd *inWnd, CPoint inPoint) +{ + UNREFERENCED_PARAMETER(inWnd); + + BCMenu theContextMenu; + BCMenu *thePopupMenu = nullptr; + long theMenuCmd; + + ReleaseCapture(); + + // Load the context menu + theContextMenu.LoadMenu(IDR_WEBLINK_CONTEXT_MENU); +#ifdef _USECONTENTMENUIMAGES_ + theContextMenu.SetBitmapBackground(MENU_IMAGELIST_BACKCOLOR); + theContextMenu.LoadToolbar(IDR_WEBLINKCONTEXTTOOLBAR); +#endif + + thePopupMenu = (BCMenu *)theContextMenu.GetSubMenu(0); + + // Set the default menu item to "Open" + SetMenuDefaultItem(thePopupMenu->m_hMenu, IDM_OPENLINK, FALSE); + + m_bPopup = TRUE; + + // Show the context menu + theMenuCmd = (long)thePopupMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RETURNCMD, + inPoint.x, inPoint.y, this); + + m_bPopup = FALSE; + + m_bCapture = FALSE; + + theContextMenu.DestroyMenu(); + + this->ShowLink(); + + // Handle the popup menu command + + switch (theMenuCmd) { + case IDM_OPENLINK: + this->JumpLink(); + break; + + case IDM_COPYSHORTCUT2: + this->CopyShortcut(); + break; + + default: + break; + } + + theContextMenu.DestroyMenu(); +} + +//============================================================================== +/** + * CopyShortcut: Copy the link URL text to the clipboard. + * + * @param None + */ +//============================================================================== +void CWebLink::CopyShortcut() +{ + // Open the clipboard so we can copy data to it. + if (OpenClipboard()) { + DWORD theBufferSize; + HGLOBAL theGlobalBuffer; + LPSTR theClipboardText; + + // Determine the buffer size, based on the length of the URL + theBufferSize = m_URL.GetLength(); + + // Clear the contents of the clipboard + ::EmptyClipboard(); + + // Allocate a global buffer and copy the text to it + theGlobalBuffer = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, theBufferSize + 1); + theClipboardText = (LPSTR)GlobalLock(theGlobalBuffer); + + CopyMemory(theClipboardText, m_URL, theBufferSize + 1); + + // Unlock the buffer + GlobalUnlock(theGlobalBuffer); + + // Pass the data to the clipboard + SetClipboardData(CF_TEXT, theGlobalBuffer); + + // Close the clipboard, but do not GlobalFree() the global buffer + CloseClipboard(); + } +} diff --git a/src/Authoring/Studio/_Win/Application/WebLink.h b/src/Authoring/Studio/_Win/Application/WebLink.h new file mode 100644 index 00000000..4ca3dede --- /dev/null +++ b/src/Authoring/Studio/_Win/Application/WebLink.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** 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 _WEBLINK_H_ +#define _WEBLINK_H_ + +#include "BaseLink.h" + +///////////////////////////////////////////////////////////////////////////// +// CWebLink window + +class CWebLink : public CBaseLink +{ + // Construction +public: + CWebLink(); + + // Attributes +public: + // Operations +public: + virtual void SetImage(UINT uiResBmp, bool bAutoSize = true); + virtual void SetImage(HBITMAP hBmp, bool bAutoSize = true); + virtual void SetText(CString inText); + virtual void SetURL(CString inURL); + +protected: + COLORREF m_ColorLink; + COLORREF m_ColorHighlight; + COLORREF m_ColorVisited; + COLORREF m_ColorBackground; + + bool m_bVisited; + bool m_bPopup; + + HBITMAP m_Bitmap; + + CString m_URL; + + virtual COLORREF GetColor(); + + virtual void CopyShortcut(); + + virtual void JumpLink(); + + virtual void OpenURL(CString inURL); + + virtual void ShowLink(); + + virtual void ShowBitmapLink(); + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CWebLink) + //}}AFX_VIRTUAL + + // Implementation +public: + virtual ~CWebLink(); + + // Generated message map functions +protected: + //{{AFX_MSG(CWebLink) + virtual afx_msg BOOL OnSetCursor(CWnd *pWnd, UINT nHitTest, UINT message); + virtual afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + virtual afx_msg void OnContextMenu(CWnd *pWnd, CPoint pos); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/src/Authoring/Studio/_Win/Controls/AppFonts.cpp b/src/Authoring/Studio/_Win/Controls/AppFonts.cpp new file mode 100644 index 00000000..54039331 --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/AppFonts.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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== + +#include "stdafx.h" +#include "Strings.h" + +//============================================================================== +// Includes +//============================================================================== + +#include "AppFonts.h" +#include "StudioPreferences.h" +#include "StringLoader.h" + +//============================================================================= +/** + * Constructor for a CAppFonts object. + */ +//============================================================================= +CAppFonts::CAppFonts() +{ + // Normal font + const QString theFontFace = CStudioPreferences::GetFontFaceName(); + Q3DStudio::CString theFontSize = ::LoadResourceString(IDS_STUDIOFONT_SIZE); + + m_NormalFont.setFamily(theFontFace); + m_NormalFont.setPointSize(13); // atoi( theFontSize.GetCharStar( ) ); +} + +//============================================================================== +/** + * Releases the object. + */ +//============================================================================== +CAppFonts::~CAppFonts() +{ +} + +//============================================================================== +/** + * Returns a pointer to the only instance of this class. Automatically cleaned + * up when the program exits. + */ +//============================================================================== +CAppFonts *CAppFonts::GetInstance() +{ + static CAppFonts theAppFonts; + return &theAppFonts; +} + +//============================================================================== +/** + * Returns the normal font for use on GUI elements for the application. + */ +//============================================================================== +QFont CAppFonts::GetNormalFont() +{ + return m_NormalFont; +} diff --git a/src/Authoring/Studio/_Win/Controls/AppFonts.h b/src/Authoring/Studio/_Win/Controls/AppFonts.h new file mode 100644 index 00000000..e2036c0e --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/AppFonts.h @@ -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$ +** +****************************************************************************/ + +//============================================================================== +// Includes +//============================================================================== + +#ifndef INCLUDED_APP_FONTS_H +#define INCLUDED_APP_FONTS_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +#include +//============================================================================== +/** + * Dispatches commands + */ +//============================================================================== +class CAppFonts +{ +public: + CAppFonts(); + virtual ~CAppFonts(); + static CAppFonts *GetInstance(); + QFont GetNormalFont(); + +private: + QFont m_NormalFont; +}; + +#endif // INCLUDED_APP_FONTS_H diff --git a/src/Authoring/Studio/_Win/Controls/BufferedRenderer.cpp b/src/Authoring/Studio/_Win/Controls/BufferedRenderer.cpp new file mode 100644 index 00000000..34076704 --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/BufferedRenderer.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** 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 "BufferedRenderer.h" +#include "AppFonts.h" + + +//============================================================================= +/** + * Create a buffered renderer. + * @param inSize the size of this renderer. + */ +CBufferedRenderer::CBufferedRenderer(const QSize &inSize) + : CWinRenderer() +{ + m_CurrentBitmap = QPixmap(inSize); + + // KDAB_TODO: I don't see why m_OldBitmap is needed, nor what is the difference between CBufferedRenderer and COffscreenRenderer + m_OldBitmap = m_CurrentBitmap; + + m_painter = new QPainter(&m_CurrentBitmap); + QFont font = CAppFonts::GetInstance()->GetNormalFont(); + m_painter->setFont(font); + + m_Size = inSize; + + PushClippingRect(QRect(QPoint(0,0), inSize)); +} + + +//============================================================================= +/** + * Destructor + */ +CBufferedRenderer::~CBufferedRenderer() +{ + delete m_painter; + m_painter = nullptr; +} + +//============================================================================= +/** + * Copy this BufferedRenderer to inRenderer using alpha blend. + * This will semi-transparently copy the contents of this buffer to inRenderer + * using the alpha. + * @param inRenderer the destination renderer. + * @param inAlpha the opacity, 255 = opaque 0 = transparent. + */ +/*void CBufferedRenderer::TransparentBltTo( CRenderer* inRenderer, short inAlpha ) +{ + + CPt theDestination; + theDestination.Offset( inRenderer->GetTranslation( ) ); + + AlphaBlendExt( inRenderer->GetGraphicsDevice( )->m_hDC, (short)theDestination.x, +(short)theDestination.y, (short)m_Size.x, (short)m_Size.y, m_DC->m_hDC, 0, 0, (short)m_Size.x, +(short)m_Size.y, inAlpha ); +// ::DrawAlphaBlendBitmap( inRenderer->GetDC( ), (short)theDestination.x, +(short)theDestination.y, m_CurrentBitmap, (short)m_Size.x, (short)m_Size.y, 0, 0, inAlpha ); + +}*/ + +//============================================================================== +/** + * Draws a bitmap using alpha blending. Works in NT/2000/9x + * + * @param inDCDest Destination device context + * @param inX X coordinate for drawing + * @param inY Y coordinate for drawing + * @param inWidth Drawing width + * @param inHeight Drawing height + * @param inDCSrc Source device context + * @param inSourceX X source coordinate + * @param inSourceY Y source coordinate + * @param inSourceWidth Source drawing width + * @param inSourceHeight Source drawing height + * @param inAlpha Alpha blend: 0-255, where 255 is opaque + */ +//============================================================================== +/*bool CBufferedRenderer::AlphaBlendExt( HDC inDCDest, short inX, short inY, short inWidth, short +inHeight, HDC inDCSrc, short inSourceX, short inSourceY, short inSourceWidth, short inSourceHeight, +short inAlpha ) +{ + BITMAPINFOHEADER theBMI; + + theBMI.biSize = sizeof( BITMAPINFOHEADER ); + theBMI.biWidth = inWidth; + theBMI.biHeight = inHeight; + theBMI.biPlanes = 1; + theBMI.biBitCount = 32; // 24 bits + alpha channel + theBMI.biCompression = BI_RGB; // no compression + theBMI.biSizeImage = 0; + theBMI.biXPelsPerMeter = 0; + theBMI.biYPelsPerMeter = 0; + theBMI.biClrUsed = 0; // use the whole palette + theBMI.biClrImportant = 0; + + BYTE* theSrcBits; + HBITMAP theBmpSrc; + + // Create DIB section in shared memory + theBmpSrc = CreateDIBSection( inDCSrc, ( BITMAPINFO* ) &theBMI, DIB_RGB_COLORS, ( void** ) +&theSrcBits, 0, 0L ); + + BYTE* theDestBits; + HBITMAP theBmpDest; + + // Create DIB section in shared memory + theBmpDest = CreateDIBSection( inDCDest, ( BITMAPINFO* ) &theBMI, DIB_RGB_COLORS, ( void** ) +&theDestBits, 0, 0L ); + + // Copy our source and destination bitmaps onto our DIBSections. + // so we can get access to their bits using the BYTE*'s we used + // in the CreateDIBSection()s above. + + HDC theDC = CreateCompatibleDC( nullptr ); + + HBITMAP theDCOld = ( HBITMAP ) SelectObject( theDC, theBmpSrc ); + + if ( !StretchBlt( theDC, 0, 0, inWidth, inHeight, inDCSrc, inSourceX, inSourceY, +inSourceWidth, inSourceHeight, SRCCOPY ) ) + { + SelectObject( theDC, theDCOld ); + DeleteDC( theDC ); + DeleteObject( theBmpSrc ); + DeleteObject( theBmpDest ); + return false; + } + + SelectObject( theDC, theBmpDest ); + + if (! StretchBlt( theDC, 0, 0, inWidth, inHeight, inDCDest, inX, inY, inWidth, inHeight, +SRCCOPY ) ) + { + SelectObject( theDC, theDCOld ); + DeleteDC( theDC ); + DeleteObject( theBmpSrc ); + DeleteObject( theBmpDest ); + return true; + } + + SelectObject( theDC, theDCOld ); + DeleteDC( theDC ); + + short theXLoop, theYLoop; + + for( theYLoop=0; theYLoop> 8 ); + theSrcRGB[1] = ( BYTE ) ( ( theDestRGB[1] * ( 255 - inAlpha ) + theSrcRGB[1] +* inAlpha ) >> 8 ); + theSrcRGB[2] = ( BYTE ) ( ( theDestRGB[2] * ( 255 - inAlpha ) + theSrcRGB[2] +* inAlpha ) >> 8 ); + + theSrcRGB += 4; + theDestRGB += 4; + } + } + + theDC = CreateCompatibleDC( nullptr ); + + theDCOld = ( HBITMAP ) SelectObject( theDC, theBmpSrc ); + + if ( !BitBlt( inDCDest, inX, inY, inWidth, inHeight, theDC, 0, 0, SRCCOPY ) ) + { + SelectObject( theDC, theDCOld ); + DeleteDC( theDC ); + DeleteObject( theBmpSrc ); + DeleteObject( theBmpDest ); + return false; + } + + SelectObject( theDC, theDCOld ); + DeleteDC( theDC ); + + DeleteObject( theBmpSrc ); + DeleteObject( theBmpDest ); + + return true; +}*/ diff --git a/src/Authoring/Studio/_Win/Controls/BufferedRenderer.h b/src/Authoring/Studio/_Win/Controls/BufferedRenderer.h new file mode 100644 index 00000000..19cc8f78 --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/BufferedRenderer.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_BUFFERED_RENDERER_H +#define INCLUDED_BUFFERED_RENDERER_H 1 + +#pragma once + +#include "WinRenderer.h" + +#include +#include +#include + +class CBufferedRenderer : public CWinRenderer +{ +public: + CBufferedRenderer(const QSize &inSize); + + virtual ~CBufferedRenderer(); + QPixmap pixmap() const override { return m_CurrentBitmap;} + + // void TransparentBltTo( CRenderer* inRenderer, short inAlpha ); + +protected: + QPixmap m_OldBitmap; + QPixmap m_CurrentBitmap; + QSize m_Size; + + // bool AlphaBlendExt( HDC inDCDest, short inX, short inY, short inWidth, short inHeight, HDC + //inDCSrc, short inSourceX, short inSourceY, short inSourceWidth, short inSourceHeight, short + //inAlpha ); +}; +#endif // INCLUDED_BUFFERED_RENDERER_H diff --git a/src/Authoring/Studio/_Win/Controls/MFCEditControl.cpp b/src/Authoring/Studio/_Win/Controls/MFCEditControl.cpp new file mode 100644 index 00000000..19b263d9 --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/MFCEditControl.cpp @@ -0,0 +1,278 @@ +/**************************************************************************** +** +** 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 "MFCEditControl.h" + +//============================================================================== +// Implementation +//============================================================================== + +#ifdef USE_RICHEDIT +IMPLEMENT_DYNAMIC(CMFCEditControl, CRichEditCtrl) +#else +IMPLEMENT_DYNAMIC(CMFCEditControl, CEdit) +#endif + +CMFCEditControl::CMFCEditControl() + : m_Changed(false) + , m_HotKeys(nullptr) +{ +} + +CMFCEditControl::~CMFCEditControl() +{ + // This control's window has been destroyed by PlatformEditControl, + // so a SigTextCommit is potentially dangerous as it will lead to GetText (below) + // which will try to get text from a destroyed window. + // However, if this is needed, note that CEdit works, but CRichEditCtrl don't. + // Can revert to using CEdit by commenting out the line in MFCEditControl.h + + // if ( m_Changed ) + //{ + // m_Changed = false; + // SigTextCommit( ); + //} +} + +Q3DStudio::CString CMFCEditControl::GetText() +{ + Q3DStudio::CString theResult; + +#ifdef USE_RICHEDIT + GETTEXTLENGTHEX getTextLengthEx; + getTextLengthEx.flags = GTL_DEFAULT | GTL_USECRLF; + getTextLengthEx.codepage = 1200; + LRESULT lResult = SendMessage(EM_GETTEXTLENGTHEX, (WPARAM)&getTextLengthEx, 0); + if (lResult > 0) { + GETTEXTEX getTextEx; + getTextEx.cb = (DWORD)(lResult + 2); + getTextEx.codepage = 1200; + getTextEx.flags = GT_DEFAULT | GT_USECRLF; + getTextEx.lpDefaultChar = nullptr; + getTextEx.lpUsedDefChar = nullptr; + wchar_t *ws = new wchar_t[lResult / 2 + 1]; + SendMessage(EM_GETTEXTEX, (WPARAM)&getTextEx, (LPARAM)ws); + theResult = ws; + delete[] ws; + } +#else + ::CString theWindowText; + GetWindowText(theWindowText); + // normal gettext, which depends on machine's locale + theResult = theWindowText; +#endif + + return theResult; +} + +void CMFCEditControl::SetText(const Q3DStudio::CString &inText) +{ + // The text manipulation is actually already being handled by the CEdit/CWnd + // This SetText is called by our custom CPropertyMultilineEdit and screws with the MFC's + // own text handling functions. + // Essentially, we still need this to set up the initial use of the MFC Edit. + if (GetText() == "") { +#ifdef USE_RICHEDIT + SETTEXTEX setTextEx; + setTextEx.codepage = 1200; + setTextEx.flags = ST_DEFAULT; + SendMessage(EM_SETTEXTEX, (WPARAM)&setTextEx, + (LPARAM)(static_cast(inText))); +#else + // normal settext, which depends on machine's locale + SetWindowText(inText.GetMulti()); +#endif + } +} + +#ifdef USE_RICHEDIT +BEGIN_MESSAGE_MAP(CMFCEditControl, CRichEditCtrl) +#else +BEGIN_MESSAGE_MAP(CMFCEditControl, CEdit) +#endif +ON_CONTROL_REFLECT(EN_CHANGE, OnEnChange) +ON_WM_LBUTTONDBLCLK() +ON_WM_SETFOCUS() +ON_WM_KILLFOCUS() +END_MESSAGE_MAP() + +// CMFCEditControl message handlers + +void CMFCEditControl::OnEnChange() +{ + m_Changed = true; + SigTextChanged(); +} + +void CMFCEditControl::OnLButtonDblClk(UINT inSomething, CPoint inPoint) +{ +#ifdef USE_RICHEDIT + CRichEditCtrl::OnLButtonDblClk(inSomething, inPoint); +#else + CEdit::OnLButtonDblClk(inSomething, inPoint); +#endif + + // select all text in this CEdit/CRichEditCtrl + SetSel(0, -1); +} + +void CMFCEditControl::OnSetFocus(CWnd *inWnd) +{ +#ifdef USE_RICHEDIT + CRichEditCtrl::OnSetFocus(inWnd); +#else + CEdit::OnSetFocus(inWnd); +#endif + + m_Changed = false; +} + +void CMFCEditControl::OnKillFocus(CWnd *inWnd) +{ +#ifdef USE_RICHEDIT + CRichEditCtrl::OnKillFocus(inWnd); +#else + CEdit::OnKillFocus(inWnd); +#endif + + if (m_Changed) { + m_Changed = false; + SigTextCommit(); + } +} + +BOOL CMFCEditControl::PreTranslateMessage(MSG *pMsg) +{ + if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) { + // Reserve some keys for Studio's hotkeys + // This is only a subset of Studio's hotkeys as listed in + // CWorkspace::RegisterGlobalKeyboardShortcuts( CHotKeys* inShortcutHandler ) + // We need to make sure that EditControl's hotkeys won't collide with Studio's hotkeys + bool theReservedHotKeys = false; + if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN + || pMsg->message == WM_KEYUP || pMsg->message == WM_SYSKEYUP) { + if (pMsg->wParam >= CHotKeys::KEY_F1 + && pMsg->wParam + <= CHotKeys::KEY_F12) // F1 to F12 keys, this may fail if not in windows + { + theReservedHotKeys = true; + } else if (CHotKeys::IsKeyDown(VK_CONTROL)) { + unsigned int theCharacterCode = ::MapVirtualKey(static_cast(pMsg->wParam), 2); + + switch (theCharacterCode) { + case 's': + case 'S': // save file / save file as + case 'o': + case 'O': // open file + case 'n': + case 'N': // new file + theReservedHotKeys = true; + } + } + } + + if (theReservedHotKeys) { + if (m_HotKeys != nullptr) + m_HotKeys->PreTranslateMessage(pMsg); + } else { + // no idea what all that filtering does, since Bug 1695 appears to be working + // and it is causing problem with Japanese text input (2639) + ::TranslateMessage(pMsg); + ::DispatchMessage(pMsg); + } + return TRUE; + + //// This is REALLY bad, but it's basically filtering all the messages that it thinks it + ///might want and handles those. + // if ((::GetAsyncKeyState(VK_LBUTTON) & 0x8000) == 0 && (::GetAsyncKeyState(VK_RBUTTON) & + // 0x8000) == 0) + //{ + // unsigned int theChar = pMsg->wParam; + + // /* + // * VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39) + // * 0x40 : unassigned + // * VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A) + // */ + + // /* + // #define VK_OEM_1 0xBA // ';:' for US + // #define VK_OEM_PLUS 0xBB // '+' any country + // #define VK_OEM_COMMA 0xBC // ',' any country + // #define VK_OEM_MINUS 0xBD // '-' any country + // #define VK_OEM_PERIOD 0xBE // '.' any country + // #define VK_OEM_2 0xBF // '/?' for US + // #define VK_OEM_3 0xC0 // '`~' for US + // #define VK_OEM_4 0xDB // '[{' for US + // #define VK_OEM_5 0xDC // '\|' for US + // #define VK_OEM_6 0xDD // ']}' for US + // #define VK_OEM_7 0xDE // ''"' for US + // #define VK_OEM_8 0xDF + // */ + + // if ( theChar == VK_RETURN || theChar == VK_BACK || theChar == VK_MENU || + // ( theChar >= VK_SPACE && theChar < VK_LWIN ) || + // ( theChar >= VK_OEM_1 && theChar <= VK_OEM_8 ) + // ) + // { + // ::TranslateMessage( pMsg ); + // ::DispatchMessage( pMsg ); + // return TRUE; + // } + //} + } + +#ifdef USE_RICHEDIT + return CRichEditCtrl::PreTranslateMessage(pMsg); +#else + return CEdit::PreTranslateMessage(pMsg); +#endif +} + +BOOL CMFCEditControl::Create(DWORD dwStyle, const RECT &rect, CWnd *pParentWnd, UINT nID) +{ +// TODO: Add your specialized code here and/or call the base class + +#ifdef USE_RICHEDIT + BOOL theResult = CRichEditCtrl::Create(dwStyle, rect, pParentWnd, nID); + SetEventMask(GetEventMask() | ENM_CHANGE); +#else + BOOL theResult = CEdit::Create(dwStyle, rect, pParentWnd, nID); +#endif + + return theResult; +} diff --git a/src/Authoring/Studio/_Win/Controls/MFCEditControl.h b/src/Authoring/Studio/_Win/Controls/MFCEditControl.h new file mode 100644 index 00000000..9d688fdc --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/MFCEditControl.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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 +//============================================================================== + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "HotKeys.h" + +//============================================================================== +// Class +//============================================================================== + +// RichEditCtrl, though super useful, has some stability issue to be ironed out. +// Use CEdit by commenting out the line below if it is causing crashes. +#define USE_RICHEDIT + +#ifdef USE_RICHEDIT +class CMFCEditControl : public CRichEditCtrl +#else +class CMFCEditControl : public CEdit +#endif +{ +protected: + DECLARE_DYNAMIC(CMFCEditControl) + +public: + boost::signal SigTextChanged; + boost::signal SigTextCommit; + +protected: + bool m_Changed; + CHotKeys *m_HotKeys; // global keyboard shortcut (Studio's hotkeys) + +public: + CMFCEditControl(); + virtual ~CMFCEditControl(); + + Q3DStudio::CString GetText(); + void SetText(const Q3DStudio::CString &inText); + + void SetGlobalKeyboardShortcuts(CHotKeys *inHotKeys) { m_HotKeys = inHotKeys; } + +protected: + DECLARE_MESSAGE_MAP() +public: + afx_msg void OnEnChange(); + afx_msg void OnLButtonDblClk(UINT, CPoint); + afx_msg void OnSetFocus(CWnd *); + afx_msg void OnKillFocus(CWnd *); + + virtual BOOL PreTranslateMessage(MSG *inMessage); + virtual BOOL Create(DWORD dwStyle, const RECT &rect, CWnd *pParentWnd, UINT nID); +}; diff --git a/src/Authoring/Studio/_Win/Controls/OffscreenRenderer.cpp b/src/Authoring/Studio/_Win/Controls/OffscreenRenderer.cpp new file mode 100644 index 00000000..72a5f17b --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/OffscreenRenderer.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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 "OffscreenRenderer.h" +#include "AppFonts.h" + +//============================================================================= +/** + * Constructor: Overrides a protected constructor on the base class. Sets up + * all the requirements so that this renderer is valid. + */ +COffscreenRenderer::COffscreenRenderer(const QRect &inClippingRect) + : CWinRenderer() +{ + m_pixmap = QPixmap(inClippingRect.size()); + m_painter = new QPainter(&m_pixmap); + QFont font = CAppFonts::GetInstance()->GetNormalFont(); + m_painter->setFont(font); + + // Set up the specified clipping region. Renderer is now valid for use. + PushClippingRect(inClippingRect); +} + +//============================================================================= +/** + * Destructor + */ +COffscreenRenderer::~COffscreenRenderer() +{ + delete m_painter; + m_painter = nullptr; +} diff --git a/src/Authoring/Studio/_Win/Controls/OffscreenRenderer.h b/src/Authoring/Studio/_Win/Controls/OffscreenRenderer.h new file mode 100644 index 00000000..dccd259f --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/OffscreenRenderer.h @@ -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$ +** +****************************************************************************/ + +//============================================================================== +// Prefix +//============================================================================== +#ifndef INCLUDED_OFFSCREEN_RENDERER_H +#define INCLUDED_OFFSCREEN_RENDERER_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include "WinRenderer.h" + +//============================================================================= +/** + * Class for creating a renderer compatible with the current display, but that + * does not actually draw to the display. Provided so that you controls can + * query text size outside of their draw functions. This class could be + * further extended to provide offscreen drawing and blitting, though it's + * not currently set up to do so. + */ +class COffscreenRenderer : public CWinRenderer +{ +public: + COffscreenRenderer(const QRect &inClippingRect); + virtual ~COffscreenRenderer(); + + QPixmap pixmap() const override { return m_pixmap;} + +protected: + QPixmap m_pixmap; +}; + +#endif // INCLUDED_OFFSCREEN_RENDERER_H diff --git a/src/Authoring/Studio/_Win/Controls/PlatformEditControl.cpp b/src/Authoring/Studio/_Win/Controls/PlatformEditControl.cpp new file mode 100644 index 00000000..4c581806 --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/PlatformEditControl.cpp @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** 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 "PlatformEditControl.h" +#include "Renderer.h" +#include "StudioPreferences.h" + +#ifdef WIN32 + +CPlatformEditControl::CPlatformEditControl(UICRenderDevice inParent) + : CPlatformWindowControl(inParent) +{ +#ifdef USE_RICHEDIT + BOOL theReturn = m_EditWindow.Create(WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE + | ES_WANTRETURN | ES_AUTOVSCROLL, + CRect(0, 0, 0, 0), CWnd::FromHandle(inParent), 1); +#else + BOOL theReturn = m_EditWindow.CreateEx(0, _T("EDIT"), "", WS_CHILD | WS_VSCROLL | ES_MULTILINE + | ES_WANTRETURN | ES_AUTOVSCROLL, + 0, 0, 0, 0, inParent, nullptr); +#endif + ASSERT(theReturn); + + Q_UNUSED(theReturn); // for release builds + + m_EditWindow.SigTextChanged.connect(std::bind(&CPlatformEditControl::OnTextChanged, this)); + m_EditWindow.SigTextCommit.connect(std::bind(&CPlatformEditControl::OnTextCommit, this)); + + m_Font.CreatePointFont( + 80, CString(CStudioPreferences::GetFontFaceName())); // size specified in 1/10ths of a point + m_EditWindow.SetFont(&m_Font); + m_EditWindow.SetTextMode(TM_PLAINTEXT | TM_MULTILEVELUNDO); + m_EditWindow.SetBackgroundColor(FALSE, CStudioPreferences::GetLightBaseColor()); + + m_Window = m_EditWindow.GetSafeHwnd(); +} + +CPlatformEditControl::~CPlatformEditControl() +{ + m_EditWindow.DestroyWindow(); +} + +//============================================================================= +/** + * Essentially, this just turns the window off. Do not use the CControl::SetVisible + * because that would screw with the control's size and you will notice the inspector + * palette having cut off rows. + * + * @param inIsVisible If the window should be visible + */ +void CPlatformEditControl::SetWindowVisible(bool inIsVisible) +{ + if (inIsVisible) + m_EditWindow.ShowWindow(SW_SHOWNORMAL); + else + m_EditWindow.ShowWindow(SW_HIDE); +} + +void CPlatformEditControl::OnTextChanged() +{ + SigTextChanged(); +} + +void CPlatformEditControl::OnTextCommit() +{ + SigTextCommit(); +} + +void CPlatformEditControl::SetText(const Q3DStudio::CString &inText) +{ + m_EditWindow.SetText(inText); +} + +Q3DStudio::CString CPlatformEditControl::GetText() +{ + return m_EditWindow.GetText(); +} + +void CPlatformEditControl::EnableWindow(bool inEnable) +{ + m_EditWindow.EnableWindow(inEnable); +} + +//============================================================================== +// CControl +//============================================================================== + +void CPlatformEditControl::Draw(CRenderer *inRenderer) +{ + // Create a clipping region for the MFC Edit + CRct theUICClipRect = inRenderer->GetClippingRect(); + RECT theRect(theUICClipRect); + CRgn theClipRgn; + theClipRgn.CreateRectRgnIndirect(&theRect); + HRGN theClipHandle = (HRGN)theClipRgn; + m_EditWindow.SetWindowRgn(theClipHandle, TRUE); + + if (m_EditWindow.IsWindowVisible() == FALSE) + m_EditWindow.ShowWindow(SW_SHOWNORMAL); + + // Draw a bounding box around the entire control + CColor theTopColor = CStudioPreferences::GetControlRectTopLineColor(); + CColor theSideColor = CStudioPreferences::GetControlRectSideLineColor(); + CColor theBottomColor = CStudioPreferences::GetControlRectBottomLineColor(); + + inRenderer->DrawRectOutline(GetSize(), theTopColor, theSideColor, theBottomColor, theSideColor); +} + +#endif // WIN32 diff --git a/src/Authoring/Studio/_Win/Controls/PlatformEditControl.h b/src/Authoring/Studio/_Win/Controls/PlatformEditControl.h new file mode 100644 index 00000000..1347b217 --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/PlatformEditControl.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** 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_PLATFORM_EDIT_CONTROL_H +#define INCLUDED_PLATFORM_EDIT_CONTROL_H 1 + +#pragma once + +//============================================================================== +// Include +//============================================================================== +#include "PlatformWindowControl.h" +#include "MFCEditControl.h" + +//============================================================================== +// Class +//============================================================================== + +#ifdef WIN32 + +class CPlatformEditControl : public CPlatformWindowControl +{ +protected: + CFont m_Font; ///< MFC font for the edit text + CMFCEditControl m_EditWindow; ///< MFC Edit Window + +public: + std::signal0 SigTextChanged; + std::signal0 SigTextCommit; + +public: + CPlatformEditControl(UICRenderDevice inParent); + virtual ~CPlatformEditControl(); + + void SetWindowVisible(bool inIsVisible); + + void SetText(const Q3DStudio::CString &inText); + Q3DStudio::CString GetText(); + void EnableWindow(bool inEnable); + + void SetGlobalKeyboardShortcuts(CHotKeys *inHotKeys) + { + m_EditWindow.SetGlobalKeyboardShortcuts(inHotKeys); + } + + // CControl + virtual void Draw(CRenderer *inRenderer); + +protected: + void OnTextChanged(); + void OnTextCommit(); +}; + +#endif // WIN32 + +#endif // INCLUDED_PLATFORM_EDIT_CONTROL_H diff --git a/src/Authoring/Studio/_Win/Controls/PlatformStaticControl.cpp b/src/Authoring/Studio/_Win/Controls/PlatformStaticControl.cpp new file mode 100644 index 00000000..fc2c2509 --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/PlatformStaticControl.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** 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 "PlatformStaticControl.h" + +#ifdef WIN32 + +CPlatformStaticControl::CPlatformStaticControl(UICRenderDevice inParent) + : CPlatformWindowControl(inParent) +{ + BOOL theReturn = m_EditWindow.CreateEx(0, _T("STATIC"), _T(""), WS_VISIBLE | WS_CHILD, 0, 0, 0, + 0, inParent, nullptr); + ASSERT(theReturn); + theReturn; + + m_Font.CreatePointFont( + 80, CString(CStudioPreferences::GetFontFaceName())); // size specified in 1/10ths of a point + m_EditWindow.SetFont(&m_Font); + + m_Window = m_EditWindow.GetSafeHwnd(); +} + +CPlatformStaticControl::~CPlatformStaticControl() +{ + m_EditWindow.DestroyWindow(); +} + +void CPlatformStaticControl::SetText(const Q3DStudio::CString &inText) +{ + m_EditWindow.SetWindowText(inText); +} + +#endif // WIN32 \ No newline at end of file diff --git a/src/Authoring/Studio/_Win/Controls/PlatformStaticControl.h b/src/Authoring/Studio/_Win/Controls/PlatformStaticControl.h new file mode 100644 index 00000000..e8b68fa6 --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/PlatformStaticControl.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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_PLATFORM_STATIC_CONTROL_H +#define INCLUDED_PLATFORM_STATIC_CONTROL_H 1 + +#pragma once + +//============================================================================== +// Include +//============================================================================== + +#include "PlatformWindowControl.h" + +//============================================================================== +// Class +//============================================================================== + +#ifdef KDAB_TEMPORARILY_REMOVED + +class CPlatformStaticControl : public CPlatformWindowControl +{ +protected: + CFont m_Font; ///< MFC font for the static text + CStatic m_EditWindow; ///< MFC Edit Window + +public: + CPlatformStaticControl(UICRenderDevice inParent); + virtual ~CPlatformStaticControl(); + + void SetText(const Q3DStudio::CString &inText); +}; + +#endif // WIN32 + +#endif // INCLUDED_PLATFORM_STATIC_CONTROL_H diff --git a/src/Authoring/Studio/_Win/Controls/PlatformWindowControl.cpp b/src/Authoring/Studio/_Win/Controls/PlatformWindowControl.cpp new file mode 100644 index 00000000..89279702 --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/PlatformWindowControl.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 +//============================================================================== +#include "PlatformWindowControl.h" + +CPlatformWindowControl::CPlatformWindowControl(UICRenderDevice inParent) + : m_Window(nullptr) +{ + inParent; +} + +CPlatformWindowControl::~CPlatformWindowControl() +{ +} + +//============================================================================== +// CControl +//============================================================================== + +void CPlatformWindowControl::SetPosition(CPt inPosition) +{ + CControl::SetPosition(inPosition); + + CPt theGlobalPosition = CControl::GetGlobalPosition(CPt(0, 0)); + + ::SetWindowPos(m_Window, nullptr, theGlobalPosition.x + 1, theGlobalPosition.y + 1, 0, 0, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); +} + +void CPlatformWindowControl::SetSize(CPt inSize) +{ + CControl::SetSize(inSize); + + ::SetWindowPos(m_Window, nullptr, 0, 0, inSize.x - 2, inSize.y - 2, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE); +} + +void CPlatformWindowControl::Invalidate(bool inInvalidate) +{ + CControl::Invalidate(inInvalidate); + + // This is neccesary to handle the scroll behavior when + // this item is embedded in a scroll window. + CPt theGlobalPosition = CControl::GetGlobalPosition(CPt(0, 0)); + ::SetWindowPos(m_Window, nullptr, theGlobalPosition.x + 1, theGlobalPosition.y + 1, 0, 0, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); +} + +void CPlatformWindowControl::OnVisibleStateChange(bool inIsVisible) +{ + ::ShowWindow(m_Window, ((inIsVisible) ? (SW_SHOWNORMAL) : (SW_HIDE))); +} + +void CPlatformWindowControl::OnParentVisibleStateChanged(bool inIsVisible) +{ + ::ShowWindow(m_Window, ((inIsVisible) ? (SW_SHOWNORMAL) : (SW_HIDE))); +} + +UICRenderDevice CPlatformWindowControl::GetPlatformDevice() +{ + return m_Window; +} diff --git a/src/Authoring/Studio/_Win/Controls/PlatformWindowControl.h b/src/Authoring/Studio/_Win/Controls/PlatformWindowControl.h new file mode 100644 index 00000000..f76697f6 --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/PlatformWindowControl.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** 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_PLATFORM_WINDOW_CONTROL_H +#define INCLUDED_PLATFORM_WINDOW_CONTROL_H 1 + +#pragma once + +//============================================================================== +// Include +//============================================================================== + +#include "Control.h" + +//============================================================================== +// Class +//============================================================================== + +class CPlatformWindowControl : public CControl +{ +protected: + UICRenderDevice m_Window; ///< + +public: + CPlatformWindowControl(UICRenderDevice inParent); + virtual ~CPlatformWindowControl(); + + // CControl + void SetPosition(CPt inPosition) override; + void SetSize(CPt inSize) override; + void Invalidate(bool inInvalidate = true) override; + + void OnVisibleStateChange(bool inIsVisible) override; + void OnParentVisibleStateChanged(bool inIsVisible) override; + + UICRenderDevice GetPlatformDevice() override; +}; + +#endif // INCLUDED_PLATFORM_WINDOW_CONTROL_H diff --git a/src/Authoring/Studio/_Win/Controls/WinRenderer.cpp b/src/Authoring/Studio/_Win/Controls/WinRenderer.cpp new file mode 100644 index 00000000..3b9cddf1 --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/WinRenderer.cpp @@ -0,0 +1,525 @@ +/**************************************************************************** +** +** 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 "WinRenderer.h" +#include "MasterP.h" +#include +#include "CoreUtils.h" + +//============================================================================= +/** + * Leaves the Renderer in an invalid state, only for subclasses. + * In order for this renderer to be valid, you must do two things: (1) you must + * create a CDC and set m_DC equal to it, and (2) you must call PushClippingRect. + */ +CWinRenderer::CWinRenderer() + : m_painter(nullptr) +{ +} + +//============================================================================= +/** + * Leaves the Renderer in an invalid state, only for subclasses. + * PushClippingRect must be called in order for this to become valid. + */ +CWinRenderer::CWinRenderer(QPainter *inDC) +{ + m_painter = inDC; +} + +CWinRenderer::CWinRenderer(QPainter *inDC, const QRect &inClippingRect) +{ + m_painter = inDC; + + PushClippingRect(inClippingRect); +} + +CWinRenderer::~CWinRenderer() +{ + m_Pens.clear(); +} + +//============================================================================= +/** + * Draws a rectangle and fills it with inColor. + * The rectangle has no border and is solid. + * The coordinates are converted to global space using the current translation. + * @param inCoordinates the coordinates of the rectangle. + * @param inColor the color of the rectangle to draw. + */ +void CWinRenderer::FillSolidRect(const QRect &inCoordinates, const QColor &inColor) +{ + QRect theRect(inCoordinates.topLeft() + m_Translation, + inCoordinates.size()); + + m_painter->fillRect(theRect, inColor); +} + +//============================================================================= +/** + * Move the pen to the position. + * This will put the pen at inPoint but will not draw a line there from the + * current location. + * @param inPoint the location to move to, in local coordinates. + */ +void CWinRenderer::MoveTo(const QPoint &inPoint) +{ + m_currentPos = inPoint + m_Translation; +} + +//============================================================================= +/** + * Move the pen to the position. + * This will put the pen to the point but will not draw a line there from the + * current location. + * @param inX the X location to move to, in local coordinates. + * @param inY the Y location to move to, in local coordinates. + */ +void CWinRenderer::MoveTo(long inX, long inY) +{ + MoveTo(QPoint(inX, inY)); +} + +//============================================================================= +/** + * Draw a line from the current pen location to inPoint. + * This will draw a line to inPoint and move the current location of the pen + * to inPoint. + * @param inPoint the location to draw to, in local coordinates. + */ +void CWinRenderer::LineTo(const QPoint &inPoint) +{ + const QPoint point = inPoint + m_Translation; + m_painter->drawLine(m_currentPos, point); + m_painter->drawLine(point, QPoint(point.x(), point.y() + 1)); + m_currentPos = point; +} + +//============================================================================= +/** + * Draw a line from the current pen location to the point. + * This will draw a line to the point and move the current location of the pen + * to inPoint. + * @param inX the X coordinate of the point to draw to, in local coordinates. + * @param inY the Y coordinate of the point to draw to, in local coordinates. + */ +void CWinRenderer::LineTo(long inX, long inY) +{ + LineTo(QPoint(inX, inY)); +} + +//============================================================================= +/** + * Change the active pen color. + * This acts as a stack so that it does not interfere with previous components. + * Once the color is done being used PopPen should be called. + * @param inColor the color to make the current pen. + * @param inWidth the pen width, in pixels. + */ +void CWinRenderer::PushPen(const QColor &inColor, int inWidth) +{ + QPen thePen = GetPen(inColor, inWidth, Qt::SolidLine); + + QPen theCurrentPen = m_painter->pen(); + m_painter->setPen(thePen); + m_PenList.push_back(theCurrentPen); +} + +void CWinRenderer::PopPen() +{ + QPen thePen = m_PenList.back(); + m_PenList.pop_back(); + m_painter->setPen(thePen); +} + +//============================================================================= +/** + * Copy the bits from another renderer into this one. + * This will copy the rect from inRenderer into this renderer. + * inRect will be offset by this renderer's current translation. inXSrc and inYSrc + * will be offset by inRenderer's current translation. + * @param inRect the position and size of the area to be copied into this renderer. + * @param inPixmap the renderer to copy from. + * @param xSrc the x location of the location to copy from in inRenderer. + * @param ySrc the y location of the location to copy from in inRenderer. + */ +void CWinRenderer::BitBltFrom(const QRect &inRect, CRenderer *inRenderer, long inXSrc, long inYSrc) +{ + const auto inTranslation = inRenderer->GetTranslation(); + inXSrc += inTranslation.x(); + inYSrc += inTranslation.y(); + + auto srcRect = inRect; + auto destRect = inRect; + destRect.translate(m_Translation); + srcRect.moveTo(inXSrc, inYSrc); + m_painter->save(); + m_painter->setCompositionMode(QPainter::CompositionMode_DestinationOver); + m_painter->drawPixmap(destRect, inRenderer->pixmap(), srcRect); + m_painter->restore(); +} + +//============================================================================= +/** + * Draws text out without clipping it. + * @param inPoint the point at which to draw the text. (upper left corner) + * @param inText the text to draw. + */ +void CWinRenderer::DrawText(float inX, float inY, const QString &inText) +{ + inX += m_Translation.x(); + inY += m_Translation.y(); + m_painter->drawText(QPointF(inX, inY), inText); +} + +//============================================================================= +/** + * Draws text out to a clipped rectangle. + * If any text occurs outside the bounding box then it will be clipped. + * @param inPoint the point at which to draw the text. (upper left corner) + * @param inText the text to draw. + * @param inBoundingBox the bounding box used to clip the text. + * @param inColor color to draw the text in + */ +void CWinRenderer::DrawText(float inX, float inY, const QString &inText, + const QRect &inBoundingBox, const QColor &inColor) +{ + inX += m_Translation.x(); + inY += m_Translation.y(); + + QRectF rect(inBoundingBox); + rect.translate(inX, inY); + m_painter->save(); + QPen pen(inColor); + m_painter->setPen(pen); + m_painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, inText); + m_painter->restore(); +} + +//============================================================================= +/** + * Draws BOLD text out to a clipped rectangle. + * If any text occurs outside the bounding box then it will be clipped. + * @param inPoint the point at which to draw the text. (upper left corner) + * @param inText the text to draw. + * @param inBoundingBox the bounding box used to clip the text. + * @param inColor color to draw the text in + */ +void CWinRenderer::DrawBoldText(float inX, float inY, const QString &inText, + const QRect &inBoundingBox, const QColor &inColor) +{ + inX += m_Translation.x(); + inY += m_Translation.y(); + + QRectF rect(inBoundingBox); + rect.translate(inX, inY); + m_painter->save(); + QPen pen(inColor); + m_painter->setPen(pen); + QFont font = m_painter->font(); + font.setBold(true); + m_painter->setFont(font); + m_painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, inText); + m_painter->restore(); +} + +//============================================================================= +/** + * Gets the dimensions of the text string as it would be written out to the + * screen. + * @param inText the text to check the length on. + * @return the length of the text in pixels. + */ +QSize CWinRenderer::GetTextSize(const QString &inText) +{ + QFontMetrics fm = m_painter->fontMetrics(); + return fm.size(Qt::TextSingleLine, inText); +} + +//============================================================================= +/** + * Draws a a three-dimensional rectangle with the top and left sides in the + * color specified by inTopLeftColor and the bottom and right sides in the color + * specified by inBottomRightColor. + * + * @param inRect The rectangle to draw + * @param inTopLeftColor Color for the top and left sides of the rect + * @param inBottomRightColor Color for the bottom and right sides of the rect + */ +void CWinRenderer::Draw3dRect(const QRect &inRect, const QColor &inTopLeftColor, + const QColor &inBottomRightColor) +{ + auto rect = inRect; + rect.translate(m_Translation); + m_painter->drawRect(rect); + m_painter->save(); + m_painter->setPen(inTopLeftColor); + m_painter->drawLine(rect.topLeft(), rect.bottomLeft()); + m_painter->drawLine(rect.topLeft(), rect.topRight()); + m_painter->setPen(inBottomRightColor); + m_painter->drawLine(rect.bottomLeft(), rect.bottomRight()); + m_painter->drawLine(rect.bottomRight(), rect.topRight()); + m_painter->restore(); +} + +//============================================================================== +/** + * DrawBitmap + * + * Draw a bitmap given a device context, position and HBITMAP handle. + * + * @param inDC Device context for drawing + * @param inPos CPoint position for drawing + * @param inBitmap Handle of the bitmap to draw + */ +//============================================================================== +void CWinRenderer::DrawBitmap(const QPoint &inPos, const QPixmap &inImage) +{ + m_painter->save(); + m_painter->setCompositionMode(QPainter::CompositionMode_SourceOver); + m_painter->drawPixmap(inPos + m_Translation, inImage); + m_painter->restore();; +} + +void CWinRenderer::PushTranslation(const QPoint &inTranslation) +{ + m_Translation += inTranslation; + + m_Translations.push_back(inTranslation); +} + +void CWinRenderer::PopTranslation() +{ + QPoint thePreviousTranslation = m_Translations.back(); + m_Translation -= thePreviousTranslation; + + m_Translations.pop_back(); +} + +QPoint CWinRenderer::GetTranslation() +{ + return m_Translation; +} + +QPainter* CWinRenderer::GetPainter() +{ + return m_painter; +} + +//============================================================================== +/** + * Get the current clipping rect. + * The clipping rect is the boundary of pixels that will be drawn to the DC. + * This can be used to not draw non-visible objects. + * @return the clipping rect in local coordinates. + */ +QRect CWinRenderer::GetClippingRect() +{ + QRect theClippingRect = m_painter->clipBoundingRect().toRect(); + theClippingRect.translate(-m_Translation); + + return theClippingRect; +} + +//============================================================================== +/** + * Push a clipping rect onto the stack of clipping rects. + * This will cause any drawing outside of the clipping rect to be ignored. The + * Control class also uses this to not draw objects outside of this rect. + * @param inClippingRect the new clipping rect, in local coordinates. + */ +void CWinRenderer::PushClippingRect(const QRect &inClippingRect) +{ + QRect clippingRect(inClippingRect); + clippingRect.translate(m_Translation); + + const QRegion currentRegion = m_painter->clipRegion(); + m_painter->setClipRect(clippingRect); + + m_ClippingRegions.push_back(currentRegion); +} + +//============================================================================== +/** + * Pop the current clipping rect. + * This will change the clipping rect to use the one previous to the current + * one. + */ +void CWinRenderer::PopClippingRect() +{ + if (m_ClippingRegions.size() > 1) { + QRegion thePreviousRegion = m_ClippingRegions.back(); + m_painter->setClipRegion(thePreviousRegion); + m_ClippingRegions.pop_back(); + } +} + +//============================================================================== +/** + * DrawGradiantBitmap + * + * Draws a gradiant based on the begin color + * + * @param inRct Rct tof the control + * @param inBeginColor color to start with + * @param inInverted true if this is inverted + */ +void CWinRenderer::DrawGradientBitmap(const QRect &inRct, const QColor &inBeginColor, bool inInverted, + double inScalingFactor) +{ + QRect rect(inRct); + QRect theClippingRect = GetClippingRect(); + rect &= theClippingRect; + rect.translate(m_Translation); + + long theHeight = rect.height(); + long theWidth = rect.width(); + + QImage theCompatibleBitmap(1, theHeight, QImage::Format_RGB32); + + int theR = inBeginColor.red(); + int theG = inBeginColor.green(); + int theB = inBeginColor.blue(); + + double theExtraRModifier = inScalingFactor * (1.0 - (theR / 255.0)); + double theExtraGModifier = inScalingFactor * (1.0 - (theG / 255.0)); + double theExtraBModifier = inScalingFactor * (1.0 - (theB / 255.0)); + + for (long thePixel = 0; thePixel < theHeight; ++thePixel) { + double theNormPixel = (double)thePixel / (theHeight * 4.8); + double theCos = 1.0 / (theNormPixel * theNormPixel + 1.0); + double theRValue = (double)theR * (theCos + theExtraRModifier); + double theGValue = (double)theG * (theCos + theExtraGModifier); + double theBValue = (double)theB * (theCos + theExtraBModifier); + + QColor theTempColor(::dtoi(theRValue), ::dtoi(theGValue), ::dtoi(theBValue)); + if (inInverted) { + theCompatibleBitmap.setPixelColor(0, qMax(0l, theHeight - thePixel - 2), theTempColor); + } else { + theCompatibleBitmap.setPixelColor(0, thePixel, theTempColor); + } + theExtraRModifier *= 0.3; + theExtraGModifier *= 0.3; + theExtraBModifier *= 0.3; + } + + m_painter->save(); + m_painter->drawImage(QRect(rect.x(), rect.y(), theWidth, theHeight), theCompatibleBitmap); + m_painter->restore(); +} + +//============================================================================= +/** + * Scroll the selected area of the current view by the specified amount. + * This will take the rectangle represented by inVisibleSize and 'scroll' it + * by inAmount. The section that goes out of the visible size will be clipped + * off and the area entering the visible area will be empty. + * @param inAmount the amount to scroll by. + * @param inVisibleSize the rectangle to be scrolled. + * @return the smallest rect of area that needs to be redrawn. + */ +QRect CWinRenderer::Scroll(const QPoint &inAmount, const QRect &inVisibleSize) +{ +#if KDAB_TEMPORARILY_REMOVED + inAmount.Offset(m_Translation); + inVisibleSize.Offset(m_Translation); + + QRect theVisibleRect(QPoint(inVisibleSize.position.x, inVisibleSize.position.y), + QSize(inVisibleSize.size.x, inVisibleSize.size.y)); + + CRgn theDirtyRegion; + CRect theDirtyRect; + m_painter->ScrollDC(inAmount.x, inAmount.y, theVisibleRect, theVisibleRect, &theDirtyRegion, + &theDirtyRect); + + QRect theDirtyRct(theDirtyRect.left, theDirtyRect.top, theDirtyRect.right - theDirtyRect.left, + theDirtyRect.bottom - theDirtyRect.top); + + theDirtyRct.Offset(QPoint(-m_Translation.x, -m_Translation.y)); + + return theDirtyRct; +#else + return {}; +#endif +} + +//============================================================================= +/** + * Draw a gradient over inRect. + * This will blend horizontally across the rect from inBeginColor into inEndColor. + * This does linear interpolation. + * @param inRect the rect to draw on. + * @param inBeginColor the start (left most) color. + * @param inEndColor the final (right most) color. + */ +void CWinRenderer::DrawGradient(const QRect &inRect, const QColor &inBeginColor, const QColor &inEndColor) +{ + const QRect rect = inRect.translated(m_Translation); + QLinearGradient gradient(rect.topLeft(), rect.topRight()); + gradient.setColorAt(0, inBeginColor); + gradient.setColorAt(1, inEndColor); + + QBrush brush(gradient); + m_painter->fillRect(rect, brush); +} + +void CWinRenderer::FillHashed(const QRect &inRect, const QColor &inForegroundColor) +{ + m_painter->save(); + + QBrush theBrush(inForegroundColor, Qt::BDiagPattern); + QPen pen(inForegroundColor); + m_painter->setPen(pen); + m_painter->setBrush(theBrush); + m_painter->drawRect(inRect.translated(m_Translation)); + + m_painter->restore(); +} + +QPen CWinRenderer::GetPen(const QColor &inColor, int inWidth, Qt::PenStyle inStyle) +{ + QPen thePen; + SPenInfo theInfo = { inColor, inWidth, inStyle }; + TPenMap::iterator thePos = m_Pens.find(theInfo); + if (thePos != m_Pens.end()) { + thePen = thePos->second; + } else { + thePen.setColor(inColor); + thePen.setWidth(inWidth); + m_Pens[theInfo] = thePen; + } + return thePen; +} + +QPixmap CWinRenderer::pixmap() const +{ + return {}; +} diff --git a/src/Authoring/Studio/_Win/Controls/WinRenderer.h b/src/Authoring/Studio/_Win/Controls/WinRenderer.h new file mode 100644 index 00000000..4ebcc689 --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/WinRenderer.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** 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_WIN_RENDERER_H +#define INCLUDED_WIN_RENDERER_H 1 + +#pragma once + +#include +#include + +#include "Pt.h" +#include "Rct.h" +#include "Renderer.h" + +#include +#include + +QT_BEGIN_NAMESPACE +class QPixmap; +QT_END_NAMESPACE + +class CWinRenderer : public CRenderer +{ + typedef std::vector TPenList; + typedef std::vector TClippingRegions; + +protected: + CWinRenderer(); ///< Leaves CRenderer in an invalid state, only for subclasses + CWinRenderer(QPainter *inDC); ///< Leaves CRenderer in an invalid state, only for subclasses + +public: + CWinRenderer(QPainter *inDC, const QRect &inClippingRect); + virtual ~CWinRenderer(); + + void FillSolidRect(const QRect &inCoordinates, const QColor &inColor) override; + + void MoveTo(const QPoint &inPoint) override; + void MoveTo(long inX, long inY) override; + void LineTo(const QPoint &inPoint) override; + void LineTo(long inX, long inY) override; + + void PushPen(const QColor &inColor, int inWidth = 1) override; + void PopPen() override; + void BitBltFrom(const QRect &inRect, CRenderer *inRenderer, long inXSrc, long inYSrc) override; + + void DrawText(float inX, float inY, const QString &inText) override; + void DrawText(float inX, float inY, const QString &inText, + const QRect &inBoundingRect, const QColor &inColor = Qt::black) override; + void DrawBoldText(float inX, float inY, const QString &inText, + const QRect &inBoundingRect, const QColor &inColor = Qt::black) override; + + QSize GetTextSize(const QString &inText) override; + + void DrawBitmap(const QPoint &inPos, const QPixmap &inImage) override; + void Draw3dRect(const QRect &inRect, const QColor &inTopLeftColor, + const QColor &inBottomRightColor) override; + void DrawGradientBitmap(const QRect &inRct, const QColor &inBeginColor, bool inInverted, + double inScalingFactor = .99) override; + + void DrawGradient(const QRect &inRect, const QColor &inBeginColor, const QColor &inEndColor) override; + + void PushTranslation(const QPoint &inTranslation) override; + void PopTranslation() override; + QPoint GetTranslation() override; + + QRect GetClippingRect() override; + void PushClippingRect(const QRect &inRect) override; + void PopClippingRect() override; + void PushAbsoluteClippingRect(const QRect &inRect) override {} + void FillHashed(const QRect &inRect, const QColor &inForeGroundColor) override; + QRect Scroll(const QPoint &inAmount, const QRect &inVisibleSize) override; + QPainter *GetPainter() override; + QPen GetPen(const QColor &inColor, int inWidth, Qt::PenStyle inStyle); + + QPixmap pixmap() const override; + +protected: + TPenList m_PenList; + TClippingRegions m_ClippingRegions; + QPainter *m_painter; + QPoint m_currentPos; + +protected: + struct SPenInfo + { + QColor Color; + long Width; + Qt::PenStyle Style; + }; + + class CPenInfoLessThan : public std::binary_function + { + public: + inline bool operator()(const SPenInfo &inValL, const SPenInfo &inValR) const + { + return memcmp(&inValL, &inValR, sizeof(SPenInfo)) < 0; + } + }; + + typedef std::map TPenMap; + TPenMap m_Pens; +}; +#endif // INCLUDED_WIN_RENDERER_H diff --git a/src/Authoring/Studio/_Win/Controls/WndControl.cpp b/src/Authoring/Studio/_Win/Controls/WndControl.cpp new file mode 100644 index 00000000..c218f9b9 --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/WndControl.cpp @@ -0,0 +1,1006 @@ +/**************************************************************************** +** +** 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 "WndControl.h" +#include "WinRenderer.h" +#include "Control.h" +#include "MasterP.h" +#include "AppFonts.h" +#include "ContextMenu.h" +#include "HotKeys.h" +#include "StudioPreferences.h" +#include "WinDnd.h" +#include "Doc.h" +#include "DropSource.h" +#include "IDragable.h" +#include "OffscreenRenderer.h" + +BEGIN_MESSAGE_MAP(CWndControl, CWnd) +//{{AFX_MSG_MAP(CWndControl) +ON_WM_KILLFOCUS() +ON_WM_SETFOCUS() +ON_WM_PAINT() +ON_WM_LBUTTONUP() +ON_WM_LBUTTONDOWN() +ON_WM_RBUTTONDOWN() +ON_WM_RBUTTONUP() +ON_WM_LBUTTONDBLCLK() +ON_WM_SIZING() +ON_WM_ERASEBKGND() +ON_WM_SIZE() +ON_WM_MOUSEMOVE() +ON_WM_CREATE() +ON_WM_MOUSEACTIVATE() +ON_WM_MOUSEWHEEL() +ON_WM_CTLCOLOR() +ON_CONTROL_REFLECT(EN_CHANGE, OnEnChange) +//}}AFX_MSG_MAP +ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) +ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover) +END_MESSAGE_MAP() + +//============================================================================= +/** + * Creates the pass thru class for the wnd control. + */ +CWndControlControlListener::CWndControlControlListener(CWndControl *inParent) +{ + m_Parent = inParent; +} + +//============================================================================= +/** + * Notification from the control that the window was invalidated. + */ +void CWndControlControlListener::OnControlInvalidated() +{ + m_Parent->OnControlInvalidated(); +} + +//============================================================================= +/** + * Notification from the control to do a popup at the specified location. + */ +long CWndControlControlListener::DoPopup(CContextMenu *inContextMenu, CPt inPoint) +{ + return m_Parent->DoPopup(inContextMenu, inPoint); +} + +//============================================================================= +/** + * Get the location of the point in Screen coordinates. + */ +CPt CWndControlControlListener::ClientToScreen(CPt inPoint) +{ + CPoint thePoint(inPoint.x, inPoint.y); + m_Parent->ClientToScreen(&thePoint); + + return CPt(thePoint.x, thePoint.y); +} + +//============================================================================= +/** + * Get the location of the point into client coordinates. + */ +CPt CWndControlControlListener::ScreenToClient(CPt inPoint) +{ + CPoint thePoint(inPoint.x, inPoint.y); + m_Parent->ScreenToClient(&thePoint); + + return CPt(thePoint.x, thePoint.y); +} + +//============================================================================= +/** + * Get the platform dependent view that this is embedding. + * Used when platform dependent controls need to be embedded into the Controls. + */ +TPlatformView CWndControlControlListener::GetPlatformView() +{ + return m_Parent->m_hWnd; +} + +//============================================================================= +/** + * Pass-thru to the CWndControl's SetIsDragging function. + * @param inIsDragging true to specify that a drag is occurring or false to cancel a drag + */ +void CWndControlControlListener::SetIsDragging(bool inIsDragging) +{ + m_Parent->SetIsDragging(inIsDragging); +} + +//============================================================================= +/** + * Pass-thru to the CWndControl's ShowTooltips function. + * @param inLocation mid-point of the tooltip in global coordinates + * @param inText text to display as a tooltip + */ +void CWndControlControlListener::ShowTooltips(CPt inLocation, Q3DStudio::CString inText) +{ + m_Parent->ShowTooltips(inLocation, inText); +} + +//============================================================================= +/** + * Pass-thru to the CWndControl's HideTooltips function. + */ +void CWndControlControlListener::HideTooltips() +{ + m_Parent->HideTooltips(); +} + +//============================================================================= +/** + * Pass-thru to the CWndControl's ShowMoveableTooltips function. + * @param inLocation mid-point of the tooltip in global coordinates + * @param inText text to display as a tooltip + */ +void CWndControlControlListener::ShowMoveableWindow(CPt inLocation, Q3DStudio::CString inText, + CRct inBoundingRct) +{ + m_Parent->ShowMoveableWindow(inLocation, inText, inBoundingRct); +} + +//============================================================================= +/** + * Pass-thru to the CWndControl's HideMoveableTooltips function. + */ +void CWndControlControlListener::HideMoveableWindow() +{ + m_Parent->HideMoveableWindow(); +} + +void CWndControlControlListener::DoStartDrag(IDragable *inDragable) +{ + m_Parent->DoStartDrag(inDragable); +} + +//=============================================================================== +/** +* performs a drag operation on a file +*/ +void CWndControlControlListener::DoStartDrag(std::vector &inDragFileNameList) +{ + m_Parent->DoStartDrag(inDragFileNameList); +} + +IMPLEMENT_OBJECT_COUNTER(CWndControl); + +//============================================================================== +/** + * Constructor + */ +CWndControl::CWndControl(CControl *inControl) + : m_MouseOver(false) + , m_MemDC(nullptr) + , m_IsDragging(false) + , m_ControlListener(this) + , m_IsMouseDown(false) +{ + ADDTO_OBJECT_COUNTER(CWndControl); + + m_Control = inControl; + + if (m_Control) + m_Control->SetWindowListener(&m_ControlListener); + + RegisterWindowClass(); + + // Create the tooltip for this window (there's only one per view) + m_Tooltip.CreateEx(WS_EX_TOOLWINDOW, AfxRegisterWndClass(CS_SAVEBITS), L"CPopupWndTooltip", + WS_POPUP | WS_BORDER, CRect(0, 0, 20, 10), this, 0); + m_Tooltip.SetStationary(true); + + // Create the tooltip for this window (there's only one per view) + m_MoveableTooltip.CreateEx(WS_EX_TOOLWINDOW, AfxRegisterWndClass(CS_SAVEBITS), + L"CPopupWndTooltip", WS_POPUP | WS_BORDER, CRect(0, 0, 20, 10), this, + 0); + m_MoveableTooltip.SetStationary(false); + + m_Brush.CreateSolidBrush(CStudioPreferences::GetBaseColor()); + +#ifdef _DEBUG + m_IsPainting = false; +#endif +} + +//============================================================================== +/** + * Destructor + */ +CWndControl::~CWndControl() +{ + DeleteBuffers(); + + REMOVEFROM_OBJECT_COUNTER(CWndControl); +} + +// Register the window class if it has not already been registered. +BOOL CWndControl::RegisterWindowClass() +{ + WNDCLASS wndcls; + HINSTANCE hInst = AfxGetInstanceHandle(); + + if (!(::GetClassInfo(hInst, WNDCONTROL_CLASSNAME, &wndcls))) { + // otherwise we need to register a new class + wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; + wndcls.lpfnWndProc = ::DefWindowProc; + wndcls.cbClsExtra = wndcls.cbWndExtra = 0; + wndcls.hInstance = hInst; + wndcls.hIcon = nullptr; + wndcls.hCursor = nullptr; + wndcls.hbrBackground = m_Brush; + wndcls.lpszMenuName = nullptr; + wndcls.lpszClassName = WNDCONTROL_CLASSNAME; + + if (!AfxRegisterClass(&wndcls)) { + AfxThrowResourceException(); + return FALSE; + } + } + + return TRUE; +} + +//============================================================================== +/** + * Create: Handles the WM_CREATE message. + * + * Creates the view, sets the font, and loads the toolbar. + * + * @param lpszClassName Names the Windows class. The class name can be any name + *registered with the AfxRegisterWndClass + * @param lpszWindowName Represents the window name. Used as text for the title bar. + * @param dwStyle Specifies the window style attributes. + * @param rect Specifies the size and position of the window. + * @param pParentWnd Pointer to the parent of the view. + * @param nID The ID for the view. + * @param pContext Create context for the view. + * + * @return TRUE if creation was successful, otherwise FALSE. + */ +//============================================================================== +int CWndControl::OnCreate(LPCREATESTRUCT lpCreateStruct) +{ + return CWnd::OnCreate(lpCreateStruct); +} + +//============================================================================= +/** + * MFC notification that this window needs to be redrawn. + * This buffers the draw DC, makes a Renderer and has the Control draw to the + * buffered DC. + */ +void CWndControl::OnPaint() +{ +#ifdef _DEBUG + m_IsPainting = true; +#endif + + UICPROFILE(OnPaint); + + CPaintDC dc(this); + + HDC theDeviceContext = dc.GetSafeHdc(); + + RECT theSize; + this->GetClientRect(&theSize); + + bool theRedrawAllFlag = false; + + if (m_MemDC == nullptr) { + m_MemDC = new CDC(); + m_MemDC->CreateCompatibleDC(&dc); + m_MemDC->SelectObject(CAppFonts::GetInstance()->GetNormalFont()); + + m_MemBitmap = ::CreateCompatibleBitmap(theDeviceContext, theSize.right, theSize.bottom); + + m_OldBitmap = (HBITMAP)m_MemDC->SelectObject(m_MemBitmap); + + theRedrawAllFlag = true; + } + + CRct theDirtyRect; + { + UICPROFILE(OnPaint_Render); + CWinRenderer theRenderer(m_MemDC, CRct(0, 0, theSize.right, theSize.bottom)); + if (m_Control) + m_Control->OnDraw(&theRenderer, theDirtyRect, theRedrawAllFlag); + } + + // Copy (BitBlt) bitmap from bitmap memory DC to memory DC + // ::BitBlt( theDeviceContext, theDirtyRect.position.x, theDirtyRect.position.y, + //theDirtyRect.size.x, theDirtyRect.size.y, m_MemDC->GetSafeHdc( ), theDirtyRect.position.x, + //theDirtyRect.position.y, SRCCOPY ); + ::BitBlt(theDeviceContext, 0, 0, theSize.right, theSize.bottom, m_MemDC->GetSafeHdc(), 0, 0, + SRCCOPY); + +#ifdef _DEBUG + m_IsPainting = false; +#endif +} + +void CWndControl::DeleteBuffers() +{ + if (m_MemDC != nullptr) { + m_MemDC->SelectObject(m_OldBitmap); + ::DeleteObject(m_MemBitmap); + m_MemDC->DeleteDC(); + delete m_MemDC; + m_MemDC = nullptr; + } +} + +//============================================================================= +/** + * Notification to this window that it has lost focus. + * @param pNewWnd the window that has gained focus. + */ +void CWndControl::OnKillFocus(CWnd *pNewWnd) +{ + CWnd::OnKillFocus(pNewWnd); + + // This is used for special cases where we lose control of the mouse and lose focus as well. + // It makes sure we are not still receiving mouse messages. + if (m_IsMouseDown) { + // Tell the control that it got a mouse up + if (m_Control) + m_Control->OnMouseUp(CPt(-1, -1), CHotKeys::GetCurrentKeyModifiers()); + ReleaseCapture(); + } + + if (m_Control) { + // For the case where pNewWnd is an "embedded" control in m_Control (eg. + // CPlatformEditControl) + // m_Control should not lose focus. + // Note that since most of the Studio controls uses a common PlatformDevice (the Studio + // window), + // this (OnKillFocus) only occurs when 1) switching to another app, 2) popping up a dialog + // box or 3) an embedded control + // takes focus. + // This takes care of the case when an embedded control takes focus but unwittingly causes + // its parent to lose focus. + // This can have dire consequences if the parent control were to do something on losing + // focus, such as + // destroying all its children. For example, Bug3421. + if (!m_Control->IsChildPlatformDevice(pNewWnd->GetSafeHwnd())) + m_Control->OnLoseFocus(); + } +} + +void CWndControl::OnSetFocus(CWnd *pPrevWnd) +{ + CWnd::OnSetFocus(pPrevWnd); + if (m_Control) + m_Control->OnGainFocus(); +} + +//============================================================================= +/** + * Notification of mouse up. + */ +void CWndControl::OnLButtonUp(UINT nFlags, CPoint inPoint) +{ + Q_UNUSED(nFlags); + m_IsMouseDown = false; + // Tell the control that it got a mouse up + if (m_Control) + m_Control->OnMouseUp(CPt(inPoint.x, inPoint.y), CHotKeys::GetCurrentKeyModifiers()); + + ReleaseCapture(); + + CWnd::OnLButtonUp(nFlags, inPoint); +} + +//============================================================================= +/** + * Notification of a mouse click. + */ +void CWndControl::OnLButtonDown(UINT nFlags, CPoint inPoint) +{ + Q_UNUSED(nFlags); + m_IsMouseDown = true; + SetCapture(); + // Tell the control that it got a mouse down. + if (m_Control) + m_Control->OnMouseDown(CPt(inPoint.x, inPoint.y), CHotKeys::GetCurrentKeyModifiers()); + + CWnd::OnLButtonDown(nFlags, inPoint); +} + +//============================================================================= +/** + * Notification of a mouse click. + */ +void CWndControl::OnRButtonDown(UINT nFlags, CPoint inPoint) +{ + SetCapture(); + + if (m_IsMouseDown) { + // Tell the control that it got a mouse up + if (m_Control) + m_Control->OnMouseUp(CPt(inPoint.x, inPoint.y), CHotKeys::GetCurrentKeyModifiers()); + m_IsMouseDown = false; + } + + // Tell the control that it got a mouse down. + if (m_Control) + m_Control->OnMouseRDown(CPt(inPoint.x, inPoint.y), CHotKeys::GetCurrentKeyModifiers()); + + CWnd::OnRButtonDown(nFlags, inPoint); +} + +//============================================================================= +/** + * Notification of mouse up. + */ +void CWndControl::OnRButtonUp(UINT nFlags, CPoint inPoint) +{ + Q_UNUSED(nFlags); + + // Tell the control that it got a mouse up + if (m_Control) + m_Control->OnMouseRUp(CPt(inPoint.x, inPoint.y), CHotKeys::GetCurrentKeyModifiers()); + + ReleaseCapture(); +} + +long CWndControl::DoPopup(CContextMenu *inMenu, CPt inPoint) +{ + CPoint thePoint(inPoint.x, inPoint.y); + ClientToScreen(&thePoint); + + long theSelectedItem = inMenu->DoPopup(CPt(thePoint.x, thePoint.y), m_hWnd); + if (m_IsMouseDown) { + m_IsMouseDown = false; + if (m_Control) + m_Control->OnMouseUp(CPt(-1, -1), 0); + } + ReleaseCapture(); + + return theSelectedItem; +} + +//============================================================================= +/** + * Notification of a mouse double click. + */ +void CWndControl::OnLButtonDblClk(UINT nFlags, CPoint inPoint) +{ + Q_UNUSED(nFlags); + + // Tell the control that it got a mouse down. + if (m_Control) + m_Control->OnMouseDoubleClick(CPt(inPoint.x, inPoint.y), nFlags); +} + +//============================================================================= +/** + * Notification of a key down message. + */ +bool CWndControl::OnKeyDown(UINT inChar, UINT, UINT) +{ + return m_Control->OnKeyDown(inChar, CHotKeys::GetCurrentKeyModifiers()); +} + +//============================================================================= +/** + * Notification of a key up messages. May be hooked up later. + */ +bool CWndControl::OnKeyUp(UINT inChar, UINT, UINT) +{ + return m_Control->OnKeyUp(inChar, CHotKeys::GetCurrentKeyModifiers()); +} + +//============================================================================= +/** + * Notification of a character press message. + * + * @return true if the character was processed by the control, otherwise false + */ +bool CWndControl::OnChar(UINT inChar, UINT, UINT) +{ + return m_Control->OnChar(inChar, CHotKeys::GetCurrentKeyModifiers()); +} + +//============================================================================= +/** + * Displays a tooltip at the desired location, and with the desired text. + * @param inLocation mid-point of the tooltext message box to be displayed + * @param inText text to be displayed as the tooltip + */ +void CWndControl::ShowTooltips(CPt inLocation, Q3DStudio::CString inText) +{ + // If the global preference for tooltips is enabled + if (CStudioPreferences::ShouldShowTooltips()) { + // If the tooltip text is not empty, show the tooltip + if (!inText.IsEmpty()) { + // So that tooltip text renders within the window + // this would be nicely taken care of if this were a MFC control... + COffscreenRenderer theOffscreenRenderer(CRct(0, 0, 1, 1)); + float theWidth(0); + float theHeight(0); + theOffscreenRenderer.GetTextSize(inText, theWidth, theHeight); + + long theRightMargin = m_Control->GetPosition().x + m_Control->GetSize().x; + if (inLocation.x + ::dtol(theWidth) > theRightMargin) // re-centers this + inLocation.x = theRightMargin - ::dtol(theWidth) / 2; + + // Convert the point to screen coordinates + ::CPoint theScreenCoords = ::CPoint(inLocation.x, inLocation.y); + ClientToScreen(&theScreenCoords); + m_Tooltip.UpdateToolTip(theScreenCoords, ::CString(inText.GetMulti()), true); + } + // If the tooltip text is empty, hide the tooltip + else + m_Tooltip.ShowWindow(SW_HIDE); + } +} + +//============================================================================= +/** + * Hides any tooltip currently being displayed. + */ +void CWndControl::HideTooltips() +{ + m_Tooltip.ShowWindow(SW_HIDE); +} + +//============================================================================= +/** + * Starts the Dragging process. + * On the given IDragable. + * @param inAsset the Asset to be drug. + */ +void CWndControl::DoStartDrag(IDragable *inDragable) +{ + // Tell the window that we are beginning a drag + if (inDragable && !m_IsDragging) { + // This should prevent the Container from dragging while it is already dragging. + SetIsDragging(true); + + // This is a Wrapper for the OLEDROP + CWinDragManager theDragManager; + + // Theoretically: there is no limit to the amount of data you can add. + // For now only one object will work, until i figure out how to drag multiple objects in + // windows. + Q3DStudio::CAutoMemPtr theDropSource = + CDropSourceFactory::Create(inDragable->GetFlavor(), inDragable); + + // Add the UIC_GESTURE_FLAVOR. This will allow us to drag to StudioControls. + theDragManager.AddData(inDragable->GetFlavor(), &theDropSource, sizeof(CDropSource *)); + // This is a blocking call when we get done with this call we should have no more data in + // our Drag list. + theDragManager.StartDrag(); + + // Tell the window that we are done dragging + SetIsDragging(false); + } +} + +//=============================================================================== +/** +* performs a drag operation on a file +*/ +void CWndControl::DoStartDrag(std::vector &inDragFileNameList) +{ + // Tell the window that we are beginning a drag + if (!m_IsDragging) { + SetIsDragging(true); + + try { + CWinDragManager theDragManager; + + std::vector::iterator thePos = inDragFileNameList.begin(); + std::vector::iterator theEndPos = inDragFileNameList.end(); + + Q3DStudio::CAutoMemPtr theDropSource; + Q3DStudio::CAutoMemPtr theDragFile; + for (; thePos != theEndPos; ++thePos) { + Q3DStudio::CString theDragFileName = *thePos; + if (theDragFileName.Length() > 0) { + theDragFile = new CUICFile(theDragFileName); + theDropSource = CDropSourceFactory::Create( + EUIC_FLAVOR_ASSET_UICFILE, (void *)theDragFile, sizeof(theDragFile)); + // Add the UIC_GESTURE_FLAVOR. This will allow us to drag to StudioControls. + theDragManager.AddData(EUIC_FLAVOR_ASSET_UICFILE, &theDropSource, + sizeof(CDropSource *)); + break; + } + } + theDragManager.StartDrag(); + } catch (...) { // if there are any errors that throws an exception, there + // there will be no more drag and drop, since the flag will not be reset. + } + // Tell the window that we are done dragging + SetIsDragging(false); + } +} + +//============================================================================= +/** + * Notification of a mouse wheel movement. + */ +BOOL CWndControl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) +{ + ScreenToClient(&pt); + if (m_Control) + m_Control->OnMouseWheel(CPt(pt.x, pt.y), zDelta, CHotKeys::GetCurrentKeyModifiers()); + + //Q_UNUSED( nFlags ); + //Q_UNUSED( zDelta ); + //Q_UNUSED( pt ); + return CWnd::OnMouseWheel(nFlags, zDelta, pt); +} + +LRESULT CWndControl::OnRegisteredMouseWheel(WPARAM, LPARAM) +{ + return 0; +} + +//============================================================================= +/** + * Notification that this window is being resized. + */ +void CWndControl::OnSizing(UINT nSide, LPRECT lpRect) +{ + Q_UNUSED(nSide); + Q_UNUSED(lpRect); +} + +//============================================================================= +/** + * Override of erase to prevent flashing of the background. + */ +BOOL CWndControl::OnEraseBkgnd(CDC *pDC) +{ + Q_UNUSED(pDC); + return FALSE; +} + +//============================================================================= +/** + * Notification that this window has been resized. + */ +void CWndControl::OnSize(UINT nType, int cx, int cy) +{ + CWnd::OnSize(nType, cx, cy); + + MoveWindow(0, 0, cx, cy); + + CRect theSize; + GetClientRect(&theSize); + + if (m_Control) + m_Control->SetSize(CPt(theSize.right, theSize.bottom)); + + // Gotta recreate the buffered objects, otherwise they will be the wrong dimensions + DeleteBuffers(); +} + +//============================================================================= +/** + * Event notification that the mouse has moved. + */ +void CWndControl::OnMouseMove(UINT, CPoint point) +{ +#ifdef _DEBUG + m_IsPainting = true; +#endif + + UICPROFILE(OnMouseMove); + + // Track the mouse while it's in here, this will give us the hover msg + m_MouseOver = true; + + TRACKMOUSEEVENT theEventStruct; + theEventStruct.cbSize = sizeof(TRACKMOUSEEVENT); + theEventStruct.dwFlags = TME_HOVER | TME_LEAVE; + theEventStruct.hwndTrack = GetSafeHwnd(); + theEventStruct.dwHoverTime = HOVER_DEFAULT; + + ::TrackMouseEvent(&theEventStruct); + + // Notify the control that the mouse moved + if (m_Control) { + m_Control->OnMouseMove(CPt(point.x, point.y), CHotKeys::GetCurrentKeyModifiers()); + + // If the control invalidated because of a mouse event then we want to do an immediate + // redraw. + // this ensures consistent visible feedback. + if (m_Control->IsChildInvalidated()) { + UICPROFILE(RedrawWindow); + RedrawWindow(nullptr, nullptr, RDW_UPDATENOW); + } + } + +#ifdef _DEBUG + m_IsPainting = false; +#endif +} + +//============================================================================= +/** + * Notification that the mouse has left this window. + */ +LRESULT CWndControl::OnMouseLeave(WPARAM inwParam, LPARAM inlParam) +{ +#ifdef _DEBUG + if (!m_IsPainting) { +#endif _DEBUG + + Q_UNUSED(inwParam); + Q_UNUSED(inlParam); + + CPoint thePoint; + + ::GetCursorPos(&thePoint); + + // This will tell me what window is under this point. + HWND theWindow = ::WindowFromPoint(thePoint); + + if (theWindow != m_hWnd) { + m_MouseOver = false; + if (m_Control) + m_Control->OnMouseMove(CPt(-1, -1), 0); + } + +#ifdef _DEBUG + } +#endif + + return 0; +} + +//============================================================================= +/** + * Override to provide the hover message to the control. + */ +LRESULT CWndControl::OnMouseHover(WPARAM inwParam, LPARAM inlParam) +{ + + long theX = inlParam & 0xFFFF; + long theY = (inlParam >> 16) & 0xFFFF; + + if (m_Control) + m_Control->OnMouseHover(CPt(theX, theY), (UINT)inwParam); + + TRACKMOUSEEVENT theEventStruct; + theEventStruct.cbSize = sizeof(TRACKMOUSEEVENT); + theEventStruct.dwFlags = TME_HOVER | TME_LEAVE; + theEventStruct.hwndTrack = GetSafeHwnd(); + theEventStruct.dwHoverTime = HOVER_DEFAULT; + + ::TrackMouseEvent(&theEventStruct); + + return 0; +} + +//============================================================================= +/** + * Callback from the control that it has been invalidated. + * This will post a message for a redraw. + */ +void CWndControl::OnControlInvalidated() +{ + if (::IsWindow(m_hWnd)) { + Invalidate(); + ::PostMessage(m_hWnd, WM_PAINT, 0, 0); + } +} + +//============================================================================= +/** + * Override of PreTranslateMessage for dragging implementation. + */ +BOOL CWndControl::PreTranslateMessage(MSG *inMessage) +{ + BOOL theReturn = FALSE; + + switch (inMessage->message) { + case WM_KEYDOWN: { + theReturn = + OnKeyDown((UINT)inMessage->wParam, inMessage->lParam & 0xFFFF, (UINT)inMessage->lParam); + + BYTE theKeyboardState[256]; + ::GetKeyboardState(theKeyboardState); + + theKeyboardState[VK_CONTROL] = 0; + + WORD theChar = 0; + // Get the ascii character for the VK key. + ::ToAscii((UINT)inMessage->wParam, (inMessage->lParam >> 16) & 0xFF, theKeyboardState, + &theChar, 0); + unsigned int theCharacterCode = (char)theChar; + + if (theCharacterCode != 0) { + theReturn = theReturn + || OnChar(theCharacterCode, inMessage->lParam & 0xFFFF, (UINT)inMessage->lParam); + } + } break; + + case WM_KEYUP: + // Do the OnKeyUp + theReturn = + OnKeyUp((UINT)inMessage->wParam, inMessage->lParam & 0xFFFF, (UINT)inMessage->lParam); + break; + + case WM_CHAR: + theReturn = OnChar((UINT)inMessage->wParam, 0, 0); + break; + + default: + break; + } + + return theReturn; +} + +//============================================================================= +/** + * Call this function to indicate that a drag operation is currently taking + * place or has just finished. If the drag operation just finished, a mouse up + * event will be sent to all children so that the one who initiated the drag + * can clean things up. + * @param inIsDragging true to specify that a drag is occurring or false if a drag ended + */ +void CWndControl::SetIsDragging(bool inIsDragging) +{ + m_IsDragging = inIsDragging; + + // If we are no longer dragging, notify the children that a mouse up occurred since OLE won't + // tell us that + if (!m_IsDragging) + m_Control->OnMouseUp(CPt(-1, -1), 0); +} + +//============================================================================= +/** + * Override of MouseActivate to set the focus on this. + */ +int CWndControl::OnMouseActivate(CWnd *pDesktopWnd, UINT nHitTest, UINT message) +{ + CWnd::OnMouseActivate(pDesktopWnd, nHitTest, message); + SetFocus(); + m_Control->OnGainFocus(); + return MA_ACTIVATE; +} + +bool CWndControl::OnDragWithin(CDropSource &inSource) +{ + bool theReturn = false; + CPt thePoint = inSource.GetCurrentPoint(); + long theFlags = inSource.GetCurrentFlags(); + CDropTarget *theDropTarget = m_Control->FindDropCandidate(thePoint, theFlags); + + if (theDropTarget) { + theReturn = theDropTarget->Accept(inSource); + delete theDropTarget; + } + return theReturn; +} + +bool CWndControl::OnDragReceive(CDropSource &inSource) +{ + bool theReturn = false; + CPt thePoint = inSource.GetCurrentPoint(); + long theFlags = inSource.GetCurrentFlags(); + + CDropTarget *theDropTarget = m_Control->FindDropCandidate(thePoint, theFlags); + + if (theDropTarget) { + theReturn = theDropTarget->Drop(inSource); + delete theDropTarget; + } + return theReturn; +} + +void CWndControl::OnDragLeave() +{ + m_MouseOver = false; + m_Control->OnMouseMove(CPt(-1, -1), 0); +} + +void CWndControl::OnReflectMouse(CPt &inPoint, long inFlags) +{ + // Notify the control that the mouse moved + m_Control->OnMouseMove(inPoint, inFlags /*CHotKeys::GetCurrentKeyModifiers( )*/); + + // If the control invalidated because of a mouse event then we want to do an immediate redraw. + // this ensures consistent visible feedback. + if (m_Control->IsChildInvalidated()) { + UICPROFILE(RedrawWindow); + RedrawWindow(nullptr, nullptr, RDW_UPDATENOW); + } +} + +void CWndControl::ShowMoveableWindow(CPt inLocation, Q3DStudio::CString inText, CRct inBoundingRct) +{ + // If the global preference for tooltips is enabled + if (CStudioPreferences::ShouldShowTooltips()) { + // This flag is set when the control is created, it tells itself that things should + // not move around outside its boundaries. + if (inLocation.x < inBoundingRct.position.x) + inLocation.x = inBoundingRct.position.x; + if (inLocation.y < inBoundingRct.position.y) + inLocation.y = inBoundingRct.position.y; + if (inLocation.x > (inBoundingRct.position.x + inBoundingRct.size.x)) + inLocation.x = inBoundingRct.position.x + inBoundingRct.size.x; + if (inLocation.y > (inBoundingRct.position.y + inBoundingRct.size.y)) + inLocation.y = inBoundingRct.position.y + inBoundingRct.size.y; + + // Convert the point to screen coordinates + ::CPoint theScreenCoords = ::CPoint(inLocation.x, inLocation.y); + ClientToScreen(&theScreenCoords); + // If the tooltip text is not empty, show the tooltip + if (!inText.IsEmpty()) + m_MoveableTooltip.UpdateToolTip(theScreenCoords, ::CString(inText.GetMulti()), true); + // If the tooltip text is empty, hide the tooltip + else + m_MoveableTooltip.ShowWindow(SW_HIDE); + } +} + +void CWndControl::HideMoveableWindow() +{ + m_MoveableTooltip.ShowWindow(SW_HIDE); +} + +//============================================================================= +/** + * Override of OnCtlColor( ) to provide a callback when the dialog is closed. + */ +HBRUSH CWndControl::OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor) +{ + // Call the base class implementation first! Otherwise, it may undo what we are trying to + // accomplish here. + HBRUSH hbr = CWnd::OnCtlColor(pDC, pWnd, nCtlColor); + + // Set the text color to red. + // pDC->SetTextColor(RGB(255, 0, 0)); + + // pDC->SetBkColor( CStudioPreferences::GetBaseColor( ) ); + + // Return handle to our CBrush object. + // hbr = m_Brush; + + return hbr; +} + +//============================================================================= +/** + * Override of EN_CHANGE + */ +void CWndControl::OnEnChange() +{ +} diff --git a/src/Authoring/Studio/_Win/Controls/WndControl.h b/src/Authoring/Studio/_Win/Controls/WndControl.h new file mode 100644 index 00000000..a7e3c72a --- /dev/null +++ b/src/Authoring/Studio/_Win/Controls/WndControl.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** 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_WND_CONTROL_H +#define INCLUDED_WND_CONTROL_H 1 + +#pragma once + +#include "Control.h" +#include "PopupWnd.h" +#include "DropContainer.h" + +#define WNDCONTROL_CLASSNAME _T("WNDCONTROL") + +class CWndControl; +class IDragable; + +class CWndControlControlListener : public CControlWindowListener +{ +public: + CWndControlControlListener(CWndControl *inParent); + virtual void OnControlInvalidated(); + virtual long DoPopup(CContextMenu *inMenu, CPt inLocation); + virtual CPt ClientToScreen(CPt inPoint); + virtual CPt ScreenToClient(CPt inPoint); + virtual TPlatformView GetPlatformView(); + virtual void SetIsDragging(bool inIsDragging); + virtual void ShowTooltips(CPt inLocation, Q3DStudio::CString inText); + virtual void HideTooltips(); + virtual void DoStartDrag(IDragable *inDragable); + virtual void DoStartDrag(std::vector &inDragFileNameList); + virtual void ShowMoveableWindow(CPt inLocation, Q3DStudio::CString inText, CRct inBoundingRct); + virtual void HideMoveableWindow(); + +protected: + CWndControl *m_Parent; +}; + +class CWndControl : public CWnd, public CWinDropContainer +{ + +public: + CWndControl(CControl *inAgent); + virtual ~CWndControl(); + + DEFINE_OBJECT_COUNTER(CWndControl) + + BOOL RegisterWindowClass(); + + virtual void OnControlInvalidated(); + long DoPopup(CContextMenu *inMenu, CPt inLocation); + void SetIsDragging(bool inIsDragging); + void DeleteBuffers(); + bool OnKeyDown(UINT inChar, UINT inRepCnt, UINT inFlags); + bool OnKeyUp(UINT inChar, UINT inRepCnt, UINT inFlags); + bool OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); + void ShowTooltips(CPt inLocation, Q3DStudio::CString inText); + void HideTooltips(); + void DoStartDrag(IDragable *inDragable); + void DoStartDrag(std::vector &inDragFileNameList); + virtual void ShowMoveableWindow(CPt inLocation, Q3DStudio::CString inText, CRct inBoundingRct); + virtual void HideMoveableWindow(); + + bool OnDragWithin(CDropSource &inSource); + bool OnDragReceive(CDropSource &inSource); + void OnDragLeave(); + void OnReflectMouse(CPt &inPoint, long inFlags); + + //{{AFX_MSG(CWndControl) + afx_msg void OnKillFocus(CWnd *pNewWnd); + afx_msg void OnSetFocus(CWnd *pOldWnd); + afx_msg void OnPaint(); + afx_msg void OnLButtonUp(UINT nFlags, CPoint point); + afx_msg void OnLButtonDown(UINT nFlags, CPoint point); + afx_msg void OnRButtonDown(UINT nFlags, CPoint point); + afx_msg void OnRButtonUp(UINT nFlags, CPoint point); + afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point); + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + afx_msg void OnSizing(UINT nFlags, LPRECT pRect); + afx_msg BOOL OnEraseBkgnd(CDC *pDC); + afx_msg void OnSize(UINT nType, int cx, int cy); + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); + afx_msg LRESULT OnRegisteredMouseWheel(WPARAM wParam, LPARAM lParam); + afx_msg int OnMouseActivate(CWnd *pDesktopWnd, UINT nHitTest, UINT message); + afx_msg HBRUSH OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor); + afx_msg void OnEnChange(); + //}}AFX_MSG + + afx_msg LRESULT OnMouseLeave(WPARAM inwParam, LPARAM inlParam); + afx_msg LRESULT OnMouseHover(WPARAM inwParam, LPARAM inlParam); + DECLARE_MESSAGE_MAP() +protected: + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLibraryView) +public: +protected: + virtual BOOL PreTranslateMessage(MSG *pMsg); + //}}AFX_VIRTUAL + + CControl *m_Control; + CControl *m_Focus; + CPopupWnd m_Tooltip; + CPopupWnd m_MoveableTooltip; + CBrush m_Brush; + bool m_MouseOver; + CDC *m_MemDC; + HBITMAP m_MemBitmap; + HBITMAP m_OldBitmap; + bool m_IsMouseDown; /// This is used for a hack to make controls get a mouse up when we lose + /// focuse and +/// the mouse is down... say we try and delete a layer while dragging and it is the last layer + +#ifdef _DEBUG + bool m_IsPainting; +#endif + bool m_IsDragging; + CWndControlControlListener m_ControlListener; +}; + +#endif // INCLUDED_WND_CONTROL_H diff --git a/src/Authoring/Studio/_Win/DragNDrop/DropProxy.cpp b/src/Authoring/Studio/_Win/DragNDrop/DropProxy.cpp new file mode 100644 index 00000000..ac835c00 --- /dev/null +++ b/src/Authoring/Studio/_Win/DragNDrop/DropProxy.cpp @@ -0,0 +1,341 @@ +/**************************************************************************** +** +** 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 "HotKeys.h" +#include "DropProxy.h" +#include "DropContainer.h" +#include "DropSource.h" +#include "UICFile.h" +#include "UICString.h" +#include "IDragable.h" + +#include +#include + +//============================================================================= +/** + * Constructor + * @param inParent gesture listener that messages will be passed to + */ +CDropProxy::CDropProxy(CDropContainer *inParent) +{ + m_Parent = inParent; +} + +//============================================================================= +/** + * Destructor + */ +CDropProxy::~CDropProxy() +{ +} + +//============================================================================= +/** + * Called when a drag begins over a window. + */ +void CDropProxy::dragEnterEvent(QDragEnterEvent *event) +{ + event->ignore(); + if (GetDragItemCount(event->mimeData())) { + CDropContainer::TFlavorItr theItr = m_Parent->GetFlavorBegin(); + CDropContainer::TFlavorItr theEnd = m_Parent->GetFlavorEnd(); + + for (; theItr != theEnd; ++theItr) { + if (HasMainFlavor(event->mimeData(), *theItr)) { + event->accept(); + event->setDropAction(Qt::CopyAction); + break; + } + } + } +} + +//=============================================================================== +/** + * This will extract the Data from the OLEDropObject and convert it to a CDropSource. + * @param inDataObject the Win specific dropSource. + * @param inFlavor the Flavor we need. + * @param inItem the position of the data in the DataObject. + * @return Newly extracted or created DropSource. + * Note: if we created it we need to make sure we destroy this object. + */ +CDropSource *CDropProxy::GetDropSource(const QMimeData *inDataObject, long inFlavor, long inItem) +{ + const CDropSource *theDropSource = nullptr; + switch (inFlavor) { + case EUIC_FLAVOR_FILE: { + // Check if we have a Drop File on our hands. + if (inDataObject->hasUrls()) { + // Get the number of files being dragged + short theFileCount = inDataObject->urls().count(); + + // Only allow single files to be dragged + if (theFileCount > inItem && !inDataObject->urls().isEmpty()) { + // Get the filename of the object being dragged + QString theFilename = inDataObject->urls().at(inItem).toLocalFile(); + + CUICFile theFile(Q3DStudio::CString::fromQString(theFilename)); + // Dragging a single file + theDropSource = + CDropSourceFactory::Create(EUIC_FLAVOR_FILE, &theFile, sizeof(CUICFile *)); + } + } + } break; + case EUIC_FLAVOR_TEXT: + // Don't do anythiing for this + case EUIC_FLAVOR_LISTBOX: + // Don't do anythiing for this + case EUIC_FLAVOR_BASIC_OBJECTS: + // Don't do anythiing for this + case EUIC_FLAVOR_ASSET_LIB: + // make an Aset out of this. + case EUIC_FLAVOR_ASSET_TL: + // make an Aset out of this. + case EUIC_FLAVOR_ASSET_UICFILE: + // make an Aset out of this. + // Get a pointer to the object + theDropSource = dynamic_cast(inDataObject); + if (theDropSource != nullptr && theDropSource->GetFlavor() != inFlavor) + theDropSource = nullptr; + break; + } + return const_cast(theDropSource); +} + +//=============================================================================== +/** + * This is to count the number of objects in the DataObject. + * @param inDataObject the WinSpecific dropobject + * @return The number of items found. + */ +long CDropProxy::GetDragItemCount(const QMimeData *inDataObject) +{ + long theCount = 0; + + // Check if we have a Drop File on our hands. + if (inDataObject->hasUrls()) { + // Get the number of files being dragged + theCount = inDataObject->urls().count(); + } else { + auto source = dynamic_cast(inDataObject); + theCount = source != nullptr ? 1 : 0; + } + + return theCount; +} +//=============================================================================== +/** + * This will check the DataObject for the Flavor. + * @param inDataObject the Win specific data object. + * @param inFlavor the requested Flavor. + * @param true if the DataObject contains the flavor. + */ +bool CDropProxy::HasMainFlavor(const QMimeData *inDataObject, long inFlavor) +{ + if (inFlavor == EUIC_FLAVOR_FILE) + return inDataObject->hasUrls(); + auto source = dynamic_cast(inDataObject); + return source != nullptr && source->GetFlavor() == inFlavor; +} + +//============================================================================= +/** + * Called when a drag event leaves the window. May cause the drag to end if + * the mouse button is no longer down. + */ +void CDropProxy::dragLeaveEvent(QDragLeaveEvent *event) +{ + if (m_Parent) { + m_Parent->OnDragLeave(); + event->accept(); + } +} + +//============================================================================= +/** + * Called when an item is being dragged over this window. Passes the message + * on to the gesture listener. + */ +void CDropProxy::dragMoveEvent(QDragMoveEvent *event) +{ + bool theAcceptFlag = false; + + if (m_Parent) { + long theCount = GetDragItemCount(event->mimeData()); + for (long theIndex = 0; theIndex < theCount; ++theIndex) { + Qt::KeyboardModifiers theModifyerFlags = ReflectMouse(event->pos().x(), event->pos().y()); + + CDropContainer::TFlavorItr theItr = m_Parent->GetFlavorBegin(); + CDropContainer::TFlavorItr theEnd = m_Parent->GetFlavorEnd(); + + for (; theItr != theEnd; ++theItr) { + // Find the Flavor of this Item. + if (HasMainFlavor(event->mimeData(), *theItr)) { + CDropSource *theDropSource = GetDropSource(event->mimeData(), *theItr, theIndex); + if (theDropSource) { + CPt thePoint(event->pos()); + theModifyerFlags = CHotKeys::GetCurrentKeyModifiers(); + theDropSource->SetCurrentPoint(thePoint); + theDropSource->SetCurrentFlags(theModifyerFlags); + + theDropSource->InterpretKeyFlags(theModifyerFlags); + // This will be implemented in the cross platform code. + theAcceptFlag = m_Parent->OnDragWithin(*theDropSource); + event->setAccepted(theAcceptFlag); + if (theAcceptFlag) { + if (theDropSource->CanCopy()) + event->setDropAction(Qt::CopyAction); + else + event->setDropAction(Qt::MoveAction); + // Breakout of the outer loop. + theIndex = theCount; + } + + // delete the drop source if it was a file + if (EUIC_FLAVOR_FILE == theDropSource->GetFlavor()) { + delete theDropSource; + } + break; + } + } + } + } + } +} + +//============================================================================= +/** + * Called when an OLE item is dropped on this window. + * @return TRUE if the drop was valid, otherwise FALSE + */ +void CDropProxy::dropEvent(QDropEvent *event) +{ + if (m_Parent) { + long theCount = GetDragItemCount(event->mimeData()); + for (long theIndex = 0; theIndex < theCount; ++theIndex) { + Qt::KeyboardModifiers theModifyerFlags = ReflectMouse(event->pos().x(), event->pos().y()); + + theModifyerFlags = CHotKeys::GetCurrentKeyModifiers(); + + CDropContainer::TFlavorItr theItr = m_Parent->GetFlavorBegin(); + CDropContainer::TFlavorItr theEnd = m_Parent->GetFlavorEnd(); + + for (; theItr != theEnd; ++theItr) { + // Find the Flavor of this Item. + if (HasMainFlavor(event->mimeData(), *theItr)) { + // This will convert all stuff into a DropSource + CDropSource *theDropSource = GetDropSource(event->mimeData(), *theItr, theIndex); + + // This will be implemented in the cross platform code. + if (theDropSource) { + CPt thePoint(event->pos()); + theDropSource->SetCurrentPoint(thePoint); + theDropSource->SetCurrentFlags(theModifyerFlags); + + // Don't call the recieve if we did not have a valid droptarget to begin + // with. + if (theDropSource->GetHasValidTarget()) { + theDropSource->InterpretKeyFlags(theModifyerFlags); + // This will be implemented in the cross platform code. + m_Parent->OnDragReceive(*theDropSource); + } + } + + // Don't delete the drop source here, the creator will destroy it + // delete theDropSource; + } + } + } + } + + event->accept(); +} +//=============================================================================== +/** + * This function is used to report back to the container where the mouse is during a drag. + * The container can send this to children as MouseOvers so the children can do mouseover + *things. + * @param inX the X position + * @param inY the Y position. + * @return the Key modifyers. + */ +Qt::KeyboardModifiers CDropProxy::ReflectMouse(long inX, long inY) +{ + Qt::KeyboardModifiers theModifierFlags = Qt::NoModifier; + + if (m_Parent) { + // Get the mouse stuff + CPt theMouseLoc(inX, inY); + + // Determine which modifier keys are down so that we can pass them along + + theModifierFlags = CHotKeys::GetCurrentKeyModifiers(); + + // Pass the gesture into the studio control + m_Parent->OnReflectMouse(theMouseLoc, theModifierFlags); + } + return theModifierFlags; +} + +void CDropProxy::Register(QWidget *widget) +{ + widget->installEventFilter(this); + widget->setAcceptDrops(true); +} + +bool CDropProxy::eventFilter(QObject *watched, QEvent *event) +{ + Q_UNUSED(watched); + + switch (event->type()) { + case QEvent::DragEnter: + dragEnterEvent(static_cast(event)); + return event->isAccepted(); + case QEvent::DragLeave: + dragLeaveEvent(static_cast(event)); + return event->isAccepted(); + case QEvent::DragMove: + dragMoveEvent(static_cast(event)); + return event->isAccepted(); + case QEvent::Drop: + dropEvent(static_cast(event)); + return event->isAccepted(); + default: + return false; + } +} diff --git a/src/Authoring/Studio/_Win/DragNDrop/DropProxy.h b/src/Authoring/Studio/_Win/DragNDrop/DropProxy.h new file mode 100644 index 00000000..eadb9b83 --- /dev/null +++ b/src/Authoring/Studio/_Win/DragNDrop/DropProxy.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_DROP_PROXY +#define INCLUDED_DROP_PROXY 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include + +//============================================================================== +// Forwards +//============================================================================== + +class CDropContainer; +class CStudioApp; +class CDropSource; + +class QDragEnterEvent; +class QDragLeaveEvent; +class QDragMoveEvent; +class QDropEvent; +class QMimeData; + +class CDropProxy : public QObject +{ + Q_OBJECT +public: + CDropProxy(CDropContainer *inParent); + virtual ~CDropProxy(); + + void dragEnterEvent(QDragEnterEvent *event); + void dragLeaveEvent(QDragLeaveEvent *event); + void dragMoveEvent(QDragMoveEvent *event); + void dropEvent(QDropEvent *event); + + CDropSource *GetDropSource(const QMimeData *inDataObject, long inFlavor, long inItem); + long GetDragItemCount(const QMimeData *inDataObject); + bool HasMainFlavor(const QMimeData *inDataObject, long inFlavor); + Qt::KeyboardModifiers ReflectMouse(long inX, long inY); + + void Register(QWidget* widget); + + bool eventFilter(QObject *watched, QEvent *event) override; + +protected: + CDropContainer *m_Parent; +}; + +#endif // INCLUDED_DROP_PROXY diff --git a/src/Authoring/Studio/_Win/DragNDrop/WinDnd.cpp b/src/Authoring/Studio/_Win/DragNDrop/WinDnd.cpp new file mode 100644 index 00000000..d6216200 --- /dev/null +++ b/src/Authoring/Studio/_Win/DragNDrop/WinDnd.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2003 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "WinDnd.h" +#include "DropSource.h" + +//=============================================================================== +/** + * Constructor + */ +CWinDragManager::CWinDragManager() +{ + memset(&m_DragItem, 0, sizeof(SDropItem)); +} + +//=============================================================================== +/** + * Dtor + */ +CWinDragManager::~CWinDragManager() +{ +} + +//=============================================================================== +/** + * This will take any data flavor and wrap it up into out drag data. + */ +void CWinDragManager::AddData(long inFlavor, void *inData, unsigned long inSize) +{ + m_DragItem.m_Flavor = inFlavor; + m_DragItem.m_Data = inData; + m_DragItem.m_Size = inSize; +} + +//=============================================================================== +/** + * I made this so it would kind of match the MAC version. + */ +void CWinDragManager::StartDrag() +{ + Track(); +} + +//=============================================================================== +/** + * This is the Blocking function that does the Dragging. + * It is assumed that all of the Data is is requested to be dragged, is already in the list + * and we take it out of the list and pack it into the Win OLEDropSource and let it go. + * We should only return when the whole operation is over. + */ +void CWinDragManager::Track() +{ + // Convert our data into a OLE DragSource. + HGLOBAL theGlobalData = nullptr; + COleDataSource theDataSource; + + // Empty the data source + theDataSource.Empty(); + + // long theDataSize = m_DragItem.m_Size; + void *theData = m_DragItem.m_Data; + long theFlavor = m_DragItem.m_Flavor; + + // if ( theDataSize > 0 ) + { + // Allocate a global block of data + DWORD theGlobalObjectSize = sizeof(CDropSource *);//sizeof(long /*theDataSize*/); + theGlobalData = GlobalAlloc(GHND, theGlobalObjectSize); + + // Lock down the global memory object for copying data + CDropSource *theDropSource = reinterpret_cast(GlobalLock(theGlobalData)); + + // Copy the CDropSource pointer + CopyMemory(theDropSource, theData, theGlobalObjectSize); + + // Unlock, but do not free + GlobalUnlock(theGlobalData); + + // Prepare OLE data for transfer + theDataSource.CacheGlobalData((CLIPFORMAT)theFlavor, theGlobalData, nullptr); + } + + // This will go through the framework. + if (DROPEFFECT_NONE == theDataSource.DoDragDrop()) { + theDataSource.Empty(); + if (theGlobalData) + ::GlobalFree(theGlobalData); + } +} diff --git a/src/Authoring/Studio/_Win/DragNDrop/WinDnd.h b/src/Authoring/Studio/_Win/DragNDrop/WinDnd.h new file mode 100644 index 00000000..8af759c7 --- /dev/null +++ b/src/Authoring/Studio/_Win/DragNDrop/WinDnd.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2003 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 +//============================================================================== +#ifndef INCLUDED_WINDND +#define INCLUDED_WINDND + +#include + +typedef struct _SDropItem +{ + long m_Flavor; // The Type of Data. + void *m_Data; ///< A nullptr value will cause the Data to be created Later on ( Promise ) + unsigned long m_Size; //< The size of the Data. +} SDropItem; + +//============================================================================= +/** + * This class only supports dragging one item. + */ +class CWinDragManager +{ +protected: + SDropItem m_DragItem; ///< the dragged item + +public: + CWinDragManager(); + virtual ~CWinDragManager(); + + void Track(); + void StartDrag(); + + void AddData(long inFlavor, void *inData, unsigned long inSize); +}; + +#endif diff --git a/src/Authoring/Studio/_Win/Include/StudioPrefixWin32.h b/src/Authoring/Studio/_Win/Include/StudioPrefixWin32.h new file mode 100644 index 00000000..114e3bf8 --- /dev/null +++ b/src/Authoring/Studio/_Win/Include/StudioPrefixWin32.h @@ -0,0 +1,39 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_STUDIO_PREFIX_WIN_32_H +#define INCLUDED_STUDIO_PREFIX_WIN_32_H 1 + +#pragma once + +#define AK_LITTLE_ENDIAN +//#define WIN32 + +#include + +#endif // INCLUDED_STUDIO_PREFIX_WIN_32_H diff --git a/src/Authoring/Studio/_Win/Palettes/PaletteManager.cpp b/src/Authoring/Studio/_Win/Palettes/PaletteManager.cpp new file mode 100644 index 00000000..41f0fe42 --- /dev/null +++ b/src/Authoring/Studio/_Win/Palettes/PaletteManager.cpp @@ -0,0 +1,902 @@ +/**************************************************************************** +** +** 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 "PaletteManager.h" +#include "StudioApp.h" +#include "Views.h" +#include "MainFrm.h" +#include "StringLoader.h" +#include "TimelineControl.h" +#include "BasicObjectsView.h" +#include "SlideView.h" +#include "StringTokenizer.h" +#include "Preferences.h" +#include "WidgetControl.h" +#include "InspectorControlView.h" +#include "ActionView.h" +#include "IDragable.h" +#include "ActionView.h" +#include "ProjectView.h" +#include "TabOrderHandler.h" + +#include + +//============================================================================== +/** + * Class for std::for_each to delete each control + */ +template +class CDeleteAll +{ +public: + void operator()(const T *inControl) const { delete inControl; } +}; + +//============================================================================== +/** + * Constructor + */ +CPaletteManager::CPaletteManager(CMainFrame *inMainFrame) + : m_MainFrame(inMainFrame) +{ + // Position tabs to the right + inMainFrame->setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::East); + + QDockWidget *basicObjectsDock = new QDockWidget(QObject::tr("Basic Objects"), inMainFrame); + basicObjectsDock->setObjectName("basic_objects"); + basicObjectsDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea + | Qt::BottomDockWidgetArea); + auto basicObjectsView = new BasicObjectsView(basicObjectsDock); + basicObjectsDock->setWidget(basicObjectsView); + inMainFrame->addDockWidget(Qt::RightDockWidgetArea, basicObjectsDock); + m_ControlList.insert(std::make_pair(CONTROLTYPE_BASICOBJECTS, basicObjectsDock)); + + QDockWidget *projectDock = new QDockWidget(QObject::tr("Project"), inMainFrame); + projectDock->setObjectName("project"); + projectDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea + | Qt::BottomDockWidgetArea); + auto projectView = new ProjectView(projectDock); + projectDock->setWidget(projectView); + inMainFrame->addDockWidget(Qt::RightDockWidgetArea, projectDock); + inMainFrame->tabifyDockWidget(basicObjectsDock, projectDock); + m_ControlList.insert(std::make_pair(CONTROLTYPE_PROJECT, projectDock)); + + QDockWidget *slideDock = new QDockWidget(QObject::tr("Slide"), inMainFrame); + slideDock->setObjectName("slide"); + slideDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea); + auto slideView = new SlideView(slideDock); + slideDock->setWidget(slideView); + inMainFrame->addDockWidget(Qt::LeftDockWidgetArea, slideDock); + m_ControlList.insert(std::make_pair(CONTROLTYPE_SLIDE, slideDock)); + + QDockWidget *timelineDock = new QDockWidget(QObject::tr("Timeline"), inMainFrame); + timelineDock->setObjectName("timeline"); + timelineDock->setAllowedAreas(Qt::BottomDockWidgetArea); + auto c = new CTimelineControl(); + auto w = new WidgetControl(c, timelineDock); + timelineDock->setWidget(w); + w->setMinimumWidth(500); + inMainFrame->addDockWidget(Qt::BottomDockWidgetArea, timelineDock); + m_ControlList.insert(std::make_pair(CONTROLTYPE_TIMELINE, timelineDock)); + + int actionViewMinWidth = CStudioPreferences::valueWidth() + + CStudioPreferences::idWidth() + 40; // 40 added to accommodate tabs + + QDockWidget *actionDock = new QDockWidget(QObject::tr("Action"), inMainFrame); + actionDock->setObjectName("action"); + actionDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea + | Qt::BottomDockWidgetArea); + auto actionView = new ActionView(actionDock); + actionDock->setWidget(actionView); + actionView->setMinimumWidth(actionViewMinWidth); + inMainFrame->addDockWidget(Qt::BottomDockWidgetArea, actionDock); + m_ControlList.insert(std::make_pair(CONTROLTYPE_ACTION, actionDock)); + + QDockWidget *inspectorDock = new QDockWidget(QObject::tr("Inspector Control"), inMainFrame); + inspectorDock->setObjectName("inspector_control"); + inspectorDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea + | Qt::BottomDockWidgetArea); + auto inspectorView = new InspectorControlView(inspectorDock); + inspectorDock->setWidget(inspectorView); + inspectorView->setMinimumWidth(actionViewMinWidth); // Same min size as action view + inMainFrame->addDockWidget(Qt::BottomDockWidgetArea, inspectorDock); + inMainFrame->tabifyDockWidget(actionDock, inspectorDock); + m_ControlList.insert(std::make_pair(CONTROLTYPE_INSPECTOR, inspectorDock)); + + w->RegiserForDnd(w); + w->AddMainFlavor(EUIC_FLAVOR_LISTBOX); + w->AddMainFlavor(EUIC_FLAVOR_FILE); + w->AddMainFlavor(EUIC_FLAVOR_ASSET_UICFILE); + w->AddMainFlavor(EUIC_FLAVOR_ASSET_LIB); + w->AddMainFlavor(EUIC_FLAVOR_ASSET_TL); + w->AddMainFlavor(EUIC_FLAVOR_BASIC_OBJECTS); + + // Set to a default state + Reset(); +} + +//============================================================================== +/** + * Destructor + */ +CPaletteManager::~CPaletteManager() +{ + TControlMap::iterator theIterator = m_ControlList.begin(); + TControlMap::iterator theEndIterator = m_ControlList.end(); +#ifdef KDAB_TEMPORARILY_REMOVED + for (; theIterator != theEndIterator; ++theIterator) { + // Remove the palette from the old master + long theType = theIterator->first; + CMasterControl *theOldMaster = FindMasterPalette(theType); + if (theOldMaster) + RemoveControlFromMaster(theOldMaster, theType); + } + std::for_each(m_PaletteList.begin(), m_PaletteList.end(), CDeleteAll()); +#endif + // Delete all the controls + for (theIterator = m_ControlList.begin(); theIterator != theEndIterator; ++theIterator) + delete theIterator->second; +} + +//============================================================================== +/** + * Clear out old lists and reset all the palettes + */ +void CPaletteManager::Reset() +{ +#ifdef KDAB_TEMPORARILY_REMOVED + // Set the visible state to false + TControlMap::iterator theIterator = m_ControlList.begin(); + TControlMap::iterator theEndIterator = m_ControlList.end(); + for (; theIterator != theEndIterator; ++theIterator) { + CControl *theControl = theIterator->second; + if (theControl) + theControl->SetVisible(false); + } + + // Undock all palette + TPaletteList::iterator thePaletteIterator = m_PaletteList.begin(); + for (; thePaletteIterator != m_PaletteList.end(); ++thePaletteIterator) { + CStudioPaletteBar *thePaletteBar = (*thePaletteIterator); + thePaletteBar->ShowPalette(false); + } +#endif +} + +//============================================================================== +/** + * Create a palette + */ +CStudioPaletteBar *CPaletteManager::CreatePalette() +{ +#ifdef KDAB_TEMPORARILY_REMOVED + // Build the create context + CCreateContext theCreateContext; + memset(&theCreateContext, 0, sizeof(CCreateContext)); + theCreateContext.m_pNewViewClass = RUNTIME_CLASS(CMasterView); + theCreateContext.m_pCurrentFrame = m_MainFrame; + + // Create the palette bar + CStudioPaletteBar *thePaletteBar = new CStudioPaletteBar; + thePaletteBar->Create(::CString(""), &theCreateContext, GetUniquePaletteId(), + m_MainFrame); + + // Set the provider + CMasterView *theMasterView = (CMasterView *)thePaletteBar->GetView(); + theMasterView->SetProvider(this); + + // Must occur after the provider is set + thePaletteBar->InitialUpdate(); + + // Save the palette + ASSERT(thePaletteBar != nullptr); + m_PaletteList.push_back(thePaletteBar); + + // Store the information + TSMasterInfo theInfo; + theInfo.m_Master = theMasterView->GetMasterControl(); + theInfo.m_PaletteBar = thePaletteBar; + + ASSERT(theInfo.m_PaletteBar != nullptr); + m_MasterList.push_back(theInfo); + + return thePaletteBar; +#endif + return nullptr; +} + +//============================================================================== +/** + * Find a master control with no contained controls + */ +CMasterControl *CPaletteManager::FindUnusedMaster() +{ +#ifdef KDAB_TEMPORARILY_REMOVED + TMasterList::iterator theIterator = m_MasterList.begin(); + TMasterList::iterator theEndIterator = m_MasterList.end(); + for (; theIterator != theEndIterator; ++theIterator) { + if (theIterator->m_Palettes.any() == false) + return theIterator->m_Master; + } +#endif + + return nullptr; +} + +CMasterControl *CPaletteManager::FindMasterByPaletteId(long inPaletteId) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + TMasterList::iterator theIterator = m_MasterList.begin(); + TMasterList::iterator theEndIterator = m_MasterList.end(); + for (; theIterator != theEndIterator; ++theIterator) { + CControlBarInfo theBarInfo; + theIterator->m_PaletteBar->GetBarInfo(&theBarInfo); + + if (theBarInfo.m_nBarID == (UINT)inPaletteId) + return theIterator->m_Master; + } +#endif + return nullptr; +} + +CStudioPaletteBar *CPaletteManager::FindStudioPaletteBar(long inType) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + TMasterList::iterator theIterator = m_MasterList.begin(); + TMasterList::iterator theEndIterator = m_MasterList.end(); + for (; theIterator != theEndIterator; ++theIterator) { + if (theIterator->m_Palettes[inType] == true) + return theIterator->m_PaletteBar; + } +#endif + return nullptr; +} + +CStudioPaletteBar *CPaletteManager::FindStudioPaletteBar(CMasterControl *inMaster) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + TMasterList::iterator theIterator = m_MasterList.begin(); + TMasterList::iterator theEndIterator = m_MasterList.end(); + for (; theIterator != theEndIterator; ++theIterator) { + if (theIterator->m_Master == inMaster) + return theIterator->m_PaletteBar; + } +#endif + return nullptr; +} + +//============================================================================== +/** + * Add a new master to the list of masters + */ +CMasterControl *CPaletteManager::AddMasterPalette(long inType) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + // Remove the palette from the old master + CMasterControl *theOldMaster = FindMasterPalette(inType); + if (theOldMaster) + RemoveControlFromMaster(theOldMaster, inType); + + // Create a new master + CMasterControl *theMasterControl = FindUnusedMaster(); + if (theMasterControl != nullptr) { + // Add the palette to the new master + AddControlToMaster(theMasterControl, inType); + } + + return theMasterControl; +#endif + return nullptr; +} + +//============================================================================== +/** + * Add the specified palette to the specified master + */ +void CPaletteManager::AddControlToMaster(CMasterControl *inMaster, long inType) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + // Make sure this is a valid type ( for backward compatibility ) + TControlMap::iterator theControlIterator = m_ControlList.find(inType); + if (theControlIterator != m_ControlList.end()) { + // Make sure the palette is not already on another master + CMasterControl *theOldMaster = FindMasterPalette(inType); + if (theOldMaster) + RemoveControlFromMaster(theOldMaster, inType); + + // Add the palette to this master + TMasterList::iterator theIterator = m_MasterList.begin(); + for (; theIterator != m_MasterList.end(); ++theIterator) { + if (theIterator->m_Master == inMaster) { + theIterator->m_Palettes[inType] = true; + theIterator->m_Master->AddControl(GetControlName(inType), inType, + theControlIterator->second); + theIterator->m_Master->Invalidate(); + break; + } + } + } +#endif +} + +//============================================================================== +/** + * Remove the specified palette from the specified master + */ +void CPaletteManager::RemoveControlFromMaster(CMasterControl *inMaster, long inType) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + TMasterList::iterator theIterator = m_MasterList.begin(); + for (; theIterator != m_MasterList.end(); ++theIterator) { + if (theIterator->m_Master == inMaster) { + theIterator->m_Palettes[inType] = false; + theIterator->m_Master->RemoveControl(GetControl(inType)); + theIterator->m_Master->Invalidate(); + } + } +#endif +} + +//============================================================================== +/** + * Find the name of the master that contains this palette + */ +CMasterControl *CPaletteManager::FindMasterPalette(long inType) +{ + CMasterControl *theMaster = nullptr; + +#ifdef KDAB_TEMPORARILY_REMOVED + TMasterList::iterator theIterator = m_MasterList.begin(); + TMasterList::iterator theEndIterator = m_MasterList.end(); + for (; theIterator != theEndIterator; ++theIterator) { + if (theIterator->m_Palettes[inType] == true) { + theMaster = theIterator->m_Master; + break; + } + } +#endif + return theMaster; +} + +//============================================================================== +/** + * Query the number of masters + */ +long CPaletteManager::GetMasterCount() +{ + return (long)m_MasterList.size(); +} + +//============================================================================== +/** + * Get the master at the specified index + */ +CMasterControl *CPaletteManager::GetMaster(long inIndex) +{ + CMasterControl *theControl = nullptr; +#ifdef KDAB_TEMPORARILY_REMOVED + TMasterList::iterator theIterator = m_MasterList.begin(); + std::advance(theIterator, inIndex); + if (theIterator != m_MasterList.end()) + theControl = theIterator->m_Master; +#endif + return theControl; +} + +//============================================================================= +/** + * Force a control to become invisible + */ +void CPaletteManager::HideControl(long inType) +{ + auto dock = GetControl(inType); + + if (dock) { + // Make sure the control is invisible + dock->setVisible(false); + } +} +//============================================================================= +/** + * Detemine if a control is currently visible + */ +bool CPaletteManager::IsControlVisible(long inType) const +{ + auto dock = GetControl(inType); + return dock && dock->isVisible(); +} + +//============================================================================= +/** + * Force a control to become visible + */ +void CPaletteManager::ShowControl(long inType) +{ + auto dock = GetControl(inType); + + if (dock) { + // Make sure the control is visible + dock->setVisible(true); + dock->setFocus(); + } +} + +//============================================================================= +/** + * Flip the visible state of a control + */ +void CPaletteManager::ToggleControl(long inType) +{ + if (IsControlVisible(inType)) + HideControl(inType); + else + ShowControl(inType); +} + +//============================================================================== +/** + * Return the Control (Palette) according to its EControlTypes enum. + * @param inType EControlTypes + */ +QDockWidget *CPaletteManager::GetControl(long inType) const +{ + auto dock = m_ControlList.find(inType); + if (dock != m_ControlList.end() && dock->second) + return dock->second; + else + return nullptr; +} + +QWidget *CPaletteManager::getFocusWidget() const +{ + TControlMap::const_iterator end = m_ControlList.end(); + for (TControlMap::const_iterator iter = m_ControlList.begin(); iter != end; ++iter) { + if (iter->second->widget()->hasFocus()) + return iter->second->widget(); + } + return nullptr; +} + +bool CPaletteManager::tabNavigateFocusedWidget(bool tabForward) +{ + QWidget *palette = getFocusWidget(); + if (palette) { + if (auto inspector = qobject_cast(palette)) { + inspector->tabOrderHandler()->tabNavigate(tabForward); + return true; + } else if (auto actionview = qobject_cast(palette)) { + actionview->tabOrderHandler()->tabNavigate(tabForward); + return true; + } + } + return false; +} + +//============================================================================== +/** + * A helper for CMainFrame::GetTimelineControl() to access the CTimelineControl + * inside the QDockWidget + */ +CTimelineControl *CPaletteManager::GetTimelineControl() const +{ + auto dock = GetControl(CPaletteManager::CONTROLTYPE_TIMELINE); + + if (dock) { + auto widget = static_cast(dock->widget()); + + if (widget) + return static_cast(widget->getControl()); + } + + return nullptr; +} + +//============================================================================== +// Serialization +//============================================================================== + +//============================================================================== +/** + * Load the palette state from the registry + */ +bool CPaletteManager::Load() +{ + // Clear out existing local stuff + Reset(); + +#ifdef KDAB_TEMPORARILY_REMOVED + // Test the palette prefs, return false if they don't exist + if (CPreferences::GetUserPreferences().Exists(PALETTE_KEY) == false) + return false; + + long theCurrentPalette = 0; + while (true) { + // Format the subkey name + Q3DStudio::CString theSubKeyName; + theSubKeyName.Format(L"%ls%ld", PALETTE_SUBKEY, theCurrentPalette); + + // Check to see if we should exit the for loop + CPreferences thePalettePrefs = CPreferences::GetUserPreferences(PALETTE_KEY); + if (thePalettePrefs.Exists(theSubKeyName) == false) + break; + + // Format the subkey name + Q3DStudio::CString theFullKeyName; + theFullKeyName.Format(L"%ls\\%ls%ld", PALETTE_KEY, PALETTE_SUBKEY, theCurrentPalette); + + // Grab the prefs + CPreferences thePrefs = CPreferences::GetUserPreferences(theFullKeyName); + + // Default docking value + Q3DStudio::CString theDockString = + thePrefs.GetStringValue(PALETTE_CONTROL_DOCKID, L"0"); // left + long theDockId = ::atol(theDockString.GetCharStar()); + + // Default Rect + QRect theWindowRect; + Q3DStudio::CString theRectString = + thePrefs.GetStringValue(PALETTE_CONTROL_RECT, L"0,0,0,0"); + CStringTokenizer theRectTokenizer(theRectString, L","); + for (long theIndex = 0; theRectTokenizer.HasNextPartition(); + ++theRectTokenizer, ++theIndex) { + Q3DStudio::CString theCurrentString = theRectTokenizer.GetCurrentPartition(); + long theCurrentItem = ::atol(theCurrentString.GetCharStar()); + + switch (theIndex) { + case 0: + theWindowRect.setLeft(theCurrentItem); + break; + case 1: + theWindowRect.setTop(theCurrentItem); + break; + case 2: + theWindowRect.setRight(theCurrentItem); + break; + case 3: + theWindowRect.setBottom(theCurrentItem); + break; + }; + } + + // Palette id + Q3DStudio::CString thePaletteIdString = + thePrefs.GetStringValue(PALETTE_CONTROL_PALETTEID, L"0"); + long thePaletteId = ::atol(thePaletteIdString.GetCharStar()); + + // Read the selected item + Q3DStudio::CString theSelectedString = + thePrefs.GetStringValue(PALETTE_CONTROL_SELECTED, L"0"); + long theSelectedType = ::atol(theSelectedString.GetCharStar()); + + // Grab the palette + CMasterControl *theMasterControl; + if (thePaletteId) + theMasterControl = FindMasterByPaletteId(thePaletteId); + else + theMasterControl = FindUnusedMaster(); + + if (theMasterControl != nullptr) { + CStudioPaletteBar *thePaletteBar = FindStudioPaletteBar(theMasterControl); + + Q3DStudio::CString theContentString = + thePrefs.GetStringValue(PALETTE_CONTROL_LIST, L"0"); + CStringTokenizer theTokenizer(theContentString, L","); + for (; theTokenizer.HasNextPartition(); ++theTokenizer) { + Q3DStudio::CString theCurrentString = theTokenizer.GetCurrentPartition(); + long theCurrentItem = ::atol(theCurrentString.GetCharStar()); + + if (theCurrentItem != CONTROLTYPE_NONE) + AddControlToMaster(theMasterControl, theCurrentItem); + } + + // Dock the bar in the appropriate location (if requested) + if (theDockId != 0) { + CDockBar *theDockBar = + (CDockBar *)m_MainFrame->GetControlBar(theDockId + AFX_IDW_DOCKBAR_TOP); + theDockBar->ClientToScreen(theWindowRect); + + thePaletteBar->SetHorz(CSize(theWindowRect.Width(), theWindowRect.Height())); + thePaletteBar->SetVert(CSize(theWindowRect.Width(), theWindowRect.Height())); + + m_MainFrame->DockControlBar(thePaletteBar, theDockBar, theWindowRect); + m_MainFrame->RecalcLayout(TRUE); + } + + // Select the old item + theMasterControl->SelectControl(theSelectedType); + + // Turn on my heart light + thePaletteBar->ShowPalette(true); + } + + // Move on to the next key + theCurrentPalette++; + } + + if (m_MainFrame) { + // Allow the control bars (docking palettes, etc) the opportunity to restore + // This will use a registry key based off of AFX_IDS_APP_TITLE ("Qt 3D Studio") which + // is different than CPreferences (".../Qt 3D Studio/Settings/...") + CSizingControlBar::GlobalLoadState(m_MainFrame, PALETTE_LAYOUT_KEY_NAME); + m_MainFrame->LoadBarState(PALETTE_LAYOUT_KEY_NAME); + } +#endif + + return true; +} + +//============================================================================== +/** + * Save the palette state to the registry + */ +void CPaletteManager::Save() +{ +#ifdef KDAB_TEMPORARILY_REMOVED + // Destroy current information in the prefs + CPreferences theMasterPrefs = CPreferences::GetUserPreferences(PALETTE_KEY); + theMasterPrefs.Clear(); + + // Iterate through the m_MasterList + TMasterList::iterator theIterator = m_MasterList.begin(); + TMasterList::iterator theEndIterator = m_MasterList.end(); + for (long theMasterIndex = 0; theIterator != theEndIterator; ++theIterator) { + TSMasterInfo &theMasterInfo = *theIterator; + if (theMasterInfo.m_PaletteBar->IsVisible()) { + Q3DStudio::CString theSubKeyName; + theSubKeyName.Format(L"%ls\\%ls%ld", PALETTE_KEY, PALETTE_SUBKEY, theMasterIndex); + + CPreferences thePrefs = CPreferences::GetUserPreferences(theSubKeyName); + + // Save palette contents + Q3DStudio::CString theTempString; + Q3DStudio::CString theContentString; + for (long theIndex = 0; theIndex < (long)theMasterInfo.m_Palettes.size(); ++theIndex) { + if (theMasterInfo.m_Palettes[theIndex]) { + theTempString.Format(L"%ld,", theIndex); + theContentString += theTempString; + } + } + + thePrefs.SetStringValue(PALETTE_CONTROL_LIST, theContentString); + + // Save palette id + CControlBarInfo theBarInfo; + theMasterInfo.m_PaletteBar->GetBarInfo(&theBarInfo); + theTempString.Format(L"%ld", theBarInfo.m_nBarID); + thePrefs.SetStringValue(PALETTE_CONTROL_PALETTEID, theTempString); + + // Save selected item + long theSelectedIndex = theMasterInfo.m_Master->GetActiveIndex(); + theTempString.Format(L"%ld", theSelectedIndex); + thePrefs.SetStringValue(PALETTE_CONTROL_SELECTED, theTempString); + + // Default values + thePrefs.SetStringValue(PALETTE_CONTROL_DOCKID, L"0"); + thePrefs.SetStringValue(PALETTE_CONTROL_RECT, L"0,0,0,0"); + + // Increment the palette counter + ++theMasterIndex; + } + } + + // Allow the control bars (docking palettes, etc) the opportunity to store + // This will use a registry key based off of AFX_IDS_APP_TITLE ("Qt 3D Studio") which + // is different than CPreferences (".../Qt 3D Studio/Settings/...") + if (m_MainFrame) { + CSizingControlBar::GlobalSaveState(m_MainFrame, PALETTE_LAYOUT_KEY_NAME); + m_MainFrame->SaveBarState(PALETTE_LAYOUT_KEY_NAME); + } +#endif +} + +//============================================================================== +// Defaults +//============================================================================== + +//============================================================================== +/** + * Set the palettes to the default state + * + * CONTROLTYPE_ACTION = 1, ///< + * CONTROLTYPE_BASICOBJECTS = 3, ///< + * CONTROLTYPE_INSPECTOR = 4, ///< + * CONTROLTYPE_SLIDE = 6, ///< + * CONTROLTYPE_TIMELINE = 7, ///< + * CONTROLTYPE_COMMAND = 8, ///< + * CONTROLTYPE_PROJECT = 9, ///< + * + * #define AFX_IDW_DOCKBAR_TOP 0xE81B = 0 + * #define AFX_IDW_DOCKBAR_LEFT 0xE81C = 1 + * #define AFX_IDW_DOCKBAR_RIGHT 0xE81D = 2 + * #define AFX_IDW_DOCKBAR_BOTTOM 0xE81E = 3 + * #define AFX_IDW_DOCKBAR_FLOAT 0xE81F = 4 + */ +void CPaletteManager::RestoreDefaults(bool inForce) +{ + Q_UNUSED(inForce); +#ifdef KDAB_TEMPORARILY_REMOVED + + // Destroy current information in the prefs (Palettes) + CPreferences theMasterPrefs = CPreferences::GetUserPreferences(PALETTE_KEY); + theMasterPrefs.Clear(); + + // "3,9,2,5:0:2:0,0,300,250#4,1:0:2:0,251,300,601#6:0:1:0,0,125,125#7:0:3:0,0,250,300"; + Q3DStudio::CString thePaletteString = ::LoadResourceString(IDS_DEFAULT_PALETTE_LAYOUT); + CStringTokenizer thePaletteTokenizer(thePaletteString, L"#"); + for (long thePaletteIndex = 0; thePaletteTokenizer.HasNextPartition(); + ++thePaletteTokenizer, ++thePaletteIndex) { + Q3DStudio::CString theCurrentPalette = thePaletteTokenizer.GetCurrentPartition(); + CStringTokenizer theSubTokenizer(theCurrentPalette, L":"); + + // No error checking, this string better be right! + Q3DStudio::CString theControlList = theSubTokenizer.GetCurrentPartition(); + ++theSubTokenizer; + Q3DStudio::CString theSelectedControl = theSubTokenizer.GetCurrentPartition(); + ++theSubTokenizer; + Q3DStudio::CString theDockId = theSubTokenizer.GetCurrentPartition(); + ++theSubTokenizer; + Q3DStudio::CString theControlRect = theSubTokenizer.GetCurrentPartition(); + ++theSubTokenizer; + + // Create the new registry keys (Palettes\PaletteN) + Q3DStudio::CString theSubKeyName; + theSubKeyName.Format(L"%ls\\%s%ld", PALETTE_KEY, PALETTE_SUBKEY, thePaletteIndex); + CPreferences thePrefs = CPreferences::GetUserPreferences(theSubKeyName); + + thePrefs.SetStringValue(PALETTE_CONTROL_LIST, theControlList); + thePrefs.SetStringValue(PALETTE_CONTROL_SELECTED, theSelectedControl); + thePrefs.SetStringValue(PALETTE_CONTROL_DOCKID, theDockId); + thePrefs.SetStringValue(PALETTE_CONTROL_RECT, theControlRect); + } +#endif + // Load these items + Load(); +} + +//============================================================================== +// Palette Context Menu +//============================================================================== + +//============================================================================= +/** + * Callback to create a new palette of the specified type. + */ +void CPaletteManager::OnNewPalette(CMasterControl *inMaster) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + ASSERT(inMaster != nullptr); + + // Query the current control type + long theType = inMaster->GetActiveType(); + + // Add a new master with that control type + CMasterControl *theNewMaster = AddMasterPalette(theType); + + // Float the new palette + CStudioPaletteBar *thePaletteBar = FindStudioPaletteBar(theNewMaster); + m_MainFrame->FloatControlBar(thePaletteBar, QPoint(0, 0)); + + // Turn on my heart light + thePaletteBar->ShowPalette(true); +#endif +} + +//============================================================================= +/** + * Callback to move a control to the specified palette + */ +void CPaletteManager::OnMovePalette(CMasterControl *inMoveFromMaster, + CMasterControl *inMoveToMaster) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + ASSERT(inMoveFromMaster != nullptr); + ASSERT(inMoveToMaster != nullptr); + + // Move the control to the new master + long theType = inMoveFromMaster->GetActiveType(); + AddControlToMaster(inMoveToMaster, theType); + + // Check to see if the master is empty + if (inMoveFromMaster->GetControlCount() <= 0) { + // Make sure the palette is visible + CStudioPaletteBar *thePaletteBar = FindStudioPaletteBar(inMoveFromMaster); + thePaletteBar->ShowPalette(false); + } +#endif +} + +//============================================================================== +// IMasterControlProvider +//============================================================================== + +void CPaletteManager::OnControlRemoved(CMasterControl *inMaster) +{ + (void)inMaster; +} + +void CPaletteManager::OnContextMenu(CMasterControl *inMaster, const CPt &inPosition, + CContextMenu *inMyMenu) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + CPaletteContextMenu theContextMenu(this, inMaster, inMyMenu); + + // Popup the context menu + inMaster->DoPopup(&theContextMenu, inPosition); +#endif +} + +void CPaletteManager::OnControlSelected(CMasterControl *inMaster, CControl *, long inType) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + Q3DStudio::CString theControlName = GetControlName(inType); + + CStudioPaletteBar *thePalette = FindStudioPaletteBar(inMaster); + ASSERT(thePalette != nullptr); + + thePalette->SetWindowText(theControlName); +#endif +} + +//============================================================================== +// Static Methods +//============================================================================== + +//============================================================================== +/** + * Query the name of the specified palette + */ +Q3DStudio::CString CPaletteManager::GetControlName(long inType) +{ + switch (inType) { + case CONTROLTYPE_ACTION: + return ::LoadResourceString(IDS_PALETTE_ACTION); + case CONTROLTYPE_BASICOBJECTS: + return ::LoadResourceString(IDS_PALETTE_BASIC_OBJECTS); + case CONTROLTYPE_INSPECTOR: + return ::LoadResourceString(IDS_PALETTE_INSPECTOR); + case CONTROLTYPE_SLIDE: + return ::LoadResourceString(IDS_PALETTE_SLIDE); + case CONTROLTYPE_TIMELINE: + return ::LoadResourceString(IDS_PALETTE_TIMELINE); + case CONTROLTYPE_PROJECT: + return ::LoadResourceString(IDS_PALETTE_PROJECT); + default: + return L"< Empty >"; + }; +} + diff --git a/src/Authoring/Studio/_Win/Palettes/PaletteManager.h b/src/Authoring/Studio/_Win/Palettes/PaletteManager.h new file mode 100644 index 00000000..e162e7f7 --- /dev/null +++ b/src/Authoring/Studio/_Win/Palettes/PaletteManager.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_VIEW_MANAGER_H +#define INCLUDED_VIEW_MANAGER_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include +#include "MasterControl.h" +#include "TimelineControl.h" + +//============================================================================== +// Forwards +//============================================================================== +class CStudioApp; +class CMainFrame; +class CStudioPaletteBar; + +class QDockWidget; + +//============================================================================== +/** + * @class CPaletteManager + */ +class CPaletteManager : public IMasterControlProvider +{ +public: + // Do NOT change the order/values of this enum, these + // values are stored in the registry + enum EControlTypes { + CONTROLTYPE_NONE = 0, ///< + CONTROLTYPE_ACTION = 1, ///< + CONTROLTYPE_BASICOBJECTS = 3, ///< + CONTROLTYPE_INSPECTOR = 4, ///< + CONTROLTYPE_SLIDE = 6, ///< + CONTROLTYPE_TIMELINE = 7, ///< + CONTROLTYPE_PROJECT = 9, ///< + + CONTROLTYPE_MAXCONTROLS = 32, ///< the maximum number of palettes( a string of this length + ///is saved in the registry, changing this value will require + ///an upgrade process ) + }; + +public: + typedef std::bitset TPaletteSet; + +protected: + typedef struct _TSMasterInfo + { + CStudioPaletteBar *m_PaletteBar; ///< pointer to the master palette bar + TPaletteSet m_Palettes; ///< the palettes contained by the master + CMasterControl *m_Master; ///< pointer to the master control + + } TSMasterInfo; + + typedef std::map TControlMap; + typedef std::vector TPaletteList; + typedef std::vector TMasterList; + +protected: + CMainFrame *m_MainFrame; ///< + TControlMap m_ControlList; ///< map of EControlTypes and CControl + TPaletteList m_PaletteList; ///< + TMasterList m_MasterList; ///< + + static long s_PaletteIDBase; ///< + +public: + CPaletteManager(CMainFrame *inMainFrame); + virtual ~CPaletteManager(); + + // Access + void AddControlToMaster(CMasterControl *inControl, long inType); + void RemoveControlFromMaster(CMasterControl *inControl, long inType); + CMasterControl *FindMasterPalette(long inType); + long GetMasterCount(); + CMasterControl *GetMaster(long inIndex); + void HideControl(long inType); + bool IsControlVisible(long inType) const; + void ShowControl(long inType); + void ToggleControl(long inType); + + QDockWidget *GetControl(long inType) const; ///< return corresponding Palette according to EControlTypes enum value + QWidget *getFocusWidget() const; + bool tabNavigateFocusedWidget(bool tabForward); + CTimelineControl *GetTimelineControl() const; + + // Commands + void OnNewPalette(CMasterControl *inMaster); + void OnMovePalette(CMasterControl *inMoveFromMaster, CMasterControl *inMoveToMaster); + + // Serialization + bool Load(); + void Save(); + + // Defaults + void RestoreDefaults(bool inForce = false); + + // IMasterControlProvider + void OnControlRemoved(CMasterControl *inControl) override; + void OnContextMenu(CMasterControl *inControl, const CPt &inPosition, + CContextMenu *inMyMenu) override; + void OnControlSelected(CMasterControl *inMaster, CControl *inNewControl, long inType) override; + + // Static Methods + static Q3DStudio::CString GetControlName(long inType); + +protected: + CMasterControl *AddMasterPalette(long inType); + + void Reset(); + CStudioPaletteBar *CreatePalette(); + + CMasterControl *FindUnusedMaster(); + CMasterControl *FindMasterByPaletteId(long inPaletteId); + + CStudioPaletteBar *FindStudioPaletteBar(long inType); + CStudioPaletteBar *FindStudioPaletteBar(CMasterControl *inMaster); + void OnAsyncDestroyWindow(CStudioPaletteBar *inWnd); +}; + +#endif // INCLUDED_VIEW_MANAGER_H diff --git a/src/Authoring/Studio/_Win/Palettes/Progress/ProgressPalette.cpp b/src/Authoring/Studio/_Win/Palettes/Progress/ProgressPalette.cpp new file mode 100644 index 00000000..a9f1e546 --- /dev/null +++ b/src/Authoring/Studio/_Win/Palettes/Progress/ProgressPalette.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** 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 "ProgressPalette.h" +#include "StudioConst.h" +#include "ResourceCache.h" +#include "ResImage.h" +#include "ProgressView.h" + +//============================================================================= +/** + * Constructor + */ +CProgressPalette::CProgressPalette() +{ +} + +//============================================================================= +/** + * Destructor + */ +CProgressPalette::~CProgressPalette() +{ +} + +//============================================================================== +/** + * A wrapper around the CMiniFrameWnd::Create() method. + * Simplifies the create parameters for the palette bar. Overridden because + * the loading screen is different from all the other palettes. + * @return The result from the Create() call (FALSE if unsuccessful) + */ +BOOL CProgressPalette::Create(CString inTitle, CCreateContext *inCreateContext, + CWnd *inParent /* = nullptr */) +{ + CString theWndClass = AfxRegisterWndClass(CS_DBLCLKS, ::LoadCursor(nullptr, IDC_WAIT)); + BOOL theReturnValue = FALSE; + + // Add the title of the bar to the registry location. + m_DialogName = inTitle; + + // Get the rectangle that we want this splash screen to occupy in the middle of the screen + CPt theScreenSize = ::GetAvailableDisplaySize(); + CResImage *theImage = CResourceCache::GetInstance()->GetBitmap("progress-screen.png"); + CPt theImageSize = theImage->GetSize(); + long theTitleBarHeight = ::GetSystemMetrics(SM_CYCAPTION); + long theXPos = theScreenSize.x / 2 - theImageSize.x / 2; + long theYPos = theScreenSize.y / 2 - theImageSize.y / 2; + CRect theWindowRect(theXPos, theYPos, theXPos + theImageSize.x, + theYPos + theImageSize.y + theTitleBarHeight); + + // Create the dialog. + theReturnValue = CFrameWnd::Create(theWndClass, inTitle, WS_POPUP | WS_CAPTION, theWindowRect, + inParent, nullptr, 0, inCreateContext); + + return theReturnValue; +} + +//============================================================================== +/** + * Sends a message to the view that the progress bar needs to be updated to a + * new percentage. + * @param inPercent New percent complete to be displayed + */ +void CProgressPalette::SetProgress(long inPercent) +{ + SendMessageToDescendants(WM_STUDIO_LOADPROGRESS, CProgressView::PROGRESSUPDATE_PERCENT, + static_cast(inPercent)); + Invalidate(); + UpdateWindow(); +} + +//============================================================================== +/** + * Sends a message to the view that the action text (saving/loading) needs to be changed. + * @param inFileName New file name to be displayed + */ +void CProgressPalette::SetActionText(const Q3DStudio::CString &inText) +{ + SendMessageToDescendants(WM_STUDIO_LOADPROGRESS, CProgressView::PROGRESSUPDATE_ACTIONTEXT, + reinterpret_cast(&inText)); +} + +//============================================================================== +/** + * Sends a message to the view that the file name being opened needs to be changed. + * @param inFileName New file name to be displayed + */ +void CProgressPalette::SetFileName(const Q3DStudio::CString &inFileName) +{ + SendMessageToDescendants(WM_STUDIO_LOADPROGRESS, CProgressView::PROGRESSUPDATE_FILENAME, + reinterpret_cast(&inFileName)); +} \ No newline at end of file diff --git a/src/Authoring/Studio/_Win/Palettes/Progress/ProgressPalette.h b/src/Authoring/Studio/_Win/Palettes/Progress/ProgressPalette.h new file mode 100644 index 00000000..7d7cb357 --- /dev/null +++ b/src/Authoring/Studio/_Win/Palettes/Progress/ProgressPalette.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_PROGRESS_PALETTE_H +#define INCLUDED_PROGRESS_PALETTE_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "StudioPaletteBar.h" +#include "ProgressCallback.h" + +//============================================================================= +/** + * Palette for the loading screen + */ +class CProgressPalette : public CStudioDialog, public IProgressCallback +{ +public: + CProgressPalette(); + virtual ~CProgressPalette(); + virtual BOOL Create(CString inTitle, CCreateContext *inCreateContext, CWnd *inParent = nullptr); + void SetProgress(long inPercent); + void SetFileName(const Q3DStudio::CString &inFileName); + void SetActionText(const Q3DStudio::CString &inText); +}; +#endif // INCLUDED_PROGRESS_PALETTE_H \ No newline at end of file diff --git a/src/Authoring/Studio/_Win/Palettes/Progress/ProgressView.cpp b/src/Authoring/Studio/_Win/Palettes/Progress/ProgressView.cpp new file mode 100644 index 00000000..8b7e796c --- /dev/null +++ b/src/Authoring/Studio/_Win/Palettes/Progress/ProgressView.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** 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 "ProgressView.h" +#include "WndControl.h" +#include "StudioApp.h" +#include "ProgressControl.h" + +//============================================================================== +// Message Maps, etc. +//============================================================================== +IMPLEMENT_DYNCREATE(CProgressView, CView) + +BEGIN_MESSAGE_MAP(CProgressView, CView) +//{{AFX_MSG_MAP(CProgressView) +ON_WM_SIZE() +ON_WM_ERASEBKGND() +//}}AFX_MSG_MAP +ON_MESSAGE(WM_STUDIO_INITIALIZE_PALETTES, OnInitializePalettes) +ON_MESSAGE(WM_STUDIO_LOADPROGRESS, OnUpdateProgress) +END_MESSAGE_MAP() + +//============================================================================= +/** + * Constructor: Protected because the view is always created dynamically. + * You must call Initialize() before trying to use this class. + */ +CProgressView::CProgressView() + : m_WndControl(nullptr) + , m_ProgressControl(nullptr) +{ +} + +//============================================================================= +/** + * Destructor + */ +CProgressView::~CProgressView() +{ + if (m_WndControl) { + m_WndControl->DestroyWindow(); + m_WndControl = nullptr; + + SAFE_DELETE(m_ProgressControl); + } +} + +//============================================================================== +/** + * Handles the WM_INITIALUPDATE message. Responsible for preparing the view + * before it is displayed for the first time. + */ +LRESULT CProgressView::OnInitializePalettes(WPARAM, LPARAM) +{ + if (!m_WndControl) { + m_ProgressControl = new CProgressControl; + m_WndControl = new CWndControl(m_ProgressControl); + m_ProgressControl->SetName("Progress Control"); + + if (!::IsWindow(m_WndControl->m_hWnd)) + m_WndControl->CreateEx(0, AfxRegisterWndClass(CS_DBLCLKS, LoadCursor(nullptr, IDC_WAIT), + (HBRUSH)GetStockObject(BLACK_BRUSH)), + L"LoadView", WS_CHILD | WS_VISIBLE | WS_MAXIMIZE, + CRect(0, 0, 200, 200), this, 100); + } + + return 0; +} + +//============================================================================== +/** + * Handles the WM_STUDIO_LOADPROGRESS message. Changes text displayed on the + * load control, depending on what we are trying to update. + * @param inwParam Should be an EProgressMessage to indicate what we are updating + * @param inlParam Depends on inwParam. If the message type is PROGRESSUPDATE_PERCENT, + * this parameter contains a long value indicating the percent. If the message + * type is PROGRESSUPDATE_FILENAME, this parameter contains a pointer to an + * Q3DStudio::CString, which is the name of the file that we are loading. + * @return 0 + */ +LRESULT CProgressView::OnUpdateProgress(WPARAM inwParam, LPARAM inlParam) +{ + EProgressMessage theMessageType = static_cast(inwParam); + + switch (theMessageType) { + // Update the percentage completed + case PROGRESSUPDATE_PERCENT: { + long thePercent = (long)inlParam; + m_ProgressControl->SetProgress(thePercent); + } break; + + // Update the name of the file being loaded + case PROGRESSUPDATE_FILENAME: { + Q3DStudio::CString *theName = reinterpret_cast(inlParam); + m_ProgressControl->SetFileName(*theName); + } break; + + // Update the text above the file name (loading or saving) + case PROGRESSUPDATE_ACTIONTEXT: { + Q3DStudio::CString *theText = reinterpret_cast(inlParam); + m_ProgressControl->SetActionText(*theText); + } break; + + // Nothing to do in the default case + default: + break; + } + + return 0; +} + +//============================================================================= +/** + * Required by base class but does nothing since all drawing is handled by the + * child control. + */ +void CProgressView::OnDraw(CDC *inDC) +{ + Q_UNUSED(inDC); +} + +//============================================================================= +/** + * Resizes the wnd control to fill the whole view. + */ +void CProgressView::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 view to erase before redrawing. Overridden because erasing + * before each draw produces a flashing effect. + * @param inDC the DC to erase on. + * @return FALSE. + */ +BOOL CProgressView::OnEraseBkgnd(CDC *inDC) +{ + Q_UNUSED(inDC); + return FALSE; +} diff --git a/src/Authoring/Studio/_Win/Palettes/Progress/ProgressView.h b/src/Authoring/Studio/_Win/Palettes/Progress/ProgressView.h new file mode 100644 index 00000000..ed023c0c --- /dev/null +++ b/src/Authoring/Studio/_Win/Palettes/Progress/ProgressView.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_PROGRESS_VIEW_H +#define INCLUDED_PROGRESS_VIEW_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +//============================================================================== +// Forwards +//============================================================================== +class CWndControl; +class CProgressControl; +class CStudioApp; + +//============================================================================= +/** + * Windows view encapsulating the splash screen. + */ +class CProgressView : public CView +{ +public: + /// Used to pass messages from the palette, down to this view + enum EProgressMessage { + PROGRESSUPDATE_PERCENT = 0, ///< Inidicates that the percentage displayed should be updated + PROGRESSUPDATE_FILENAME, ///< Indicates that the file name displayed should be updated + PROGRESSUPDATE_ACTIONTEXT, ///< Indicates that the text above the file name needs to be + ///updated + }; + + virtual void OnDraw(CDC *inDC); + virtual LRESULT OnInitializePalettes(WPARAM inwParam, LPARAM inlParam); + virtual LRESULT OnUpdateProgress(WPARAM inwParam, LPARAM inlParam); + +protected: + CWndControl *m_WndControl; + CProgressControl *m_ProgressControl; + + CProgressView(); ///< Constructor is protected because you can only create this view dynamically + DECLARE_DYNCREATE(CProgressView) + virtual ~CProgressView(); + afx_msg void OnSize(UINT inType, int inX, int inY); + afx_msg BOOL OnEraseBkgnd(CDC *inDC); + DECLARE_MESSAGE_MAP() +}; + +#endif // INCLUDED_PROGRESS_VIEW_H \ No newline at end of file diff --git a/src/Authoring/Studio/_Win/Palettes/Splash/SplashPalette.cpp b/src/Authoring/Studio/_Win/Palettes/Splash/SplashPalette.cpp new file mode 100644 index 00000000..112631e6 --- /dev/null +++ b/src/Authoring/Studio/_Win/Palettes/Splash/SplashPalette.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** 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 "SplashPalette.h" +#include "SplashControl.h" // Just for getting the control's size; the view owns the real splash control + +//============================================================================= +/** + * Constructor + */ +CSplashPalette::CSplashPalette() +{ +} + +//============================================================================= +/** + * Destructor + */ +CSplashPalette::~CSplashPalette() +{ +} + +//============================================================================== +/** + * A wrapper around the CMiniFrameWnd::Create() method. + * Simplifies the create parameters for the palette bar. Overridden because + * the splash screen is different from all the other palettes. + * @return The result from the Create() call (FALSE if unsuccessful) + */ +BOOL CSplashPalette::Create(CString inTitle, CCreateContext *inCreateContext, + CWnd *inParent /* = nullptr */) +{ + CString theWndClass = AfxRegisterWndClass(CS_DBLCLKS, ::LoadCursor(nullptr, IDC_ARROW)); + BOOL theReturnValue; + + // Add the title of the bar to the registry location. + m_DialogName = inTitle; + + // Get the rectangle that we want this splash screen to occupy in the middle of the screen + CPt theScreenSize = GetAvailableDisplaySize(); + CSplashControl theSplashControl; // Just for getting the control's size; the view owns the real + // splash control + CPt theImageSize = theSplashControl.GetSize(); + long theXPos = theScreenSize.x / 2 - theImageSize.x / 2; + long theYPos = theScreenSize.y / 2 - theImageSize.y / 2; + CRect theWindowRect(theXPos, theYPos, theXPos + theImageSize.x, theYPos + theImageSize.y); + + // Create the dialog. + DWORD theFlags; +#ifdef DEBUG + theFlags = WS_EX_TOOLWINDOW; +#else + theFlags = WS_EX_TOOLWINDOW | WS_EX_TOPMOST; +#endif + // Create the palette bar. + theReturnValue = CFrameWnd::CreateEx(theFlags, theWndClass, inTitle, WS_POPUP, theWindowRect, + inParent, 0, inCreateContext); + + return theReturnValue; +} diff --git a/src/Authoring/Studio/_Win/Palettes/Splash/SplashPalette.h b/src/Authoring/Studio/_Win/Palettes/Splash/SplashPalette.h new file mode 100644 index 00000000..5f11af0c --- /dev/null +++ b/src/Authoring/Studio/_Win/Palettes/Splash/SplashPalette.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** 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_SPLASH_PALETTE_H +#define INCLUDED_SPLASH_PALETTE_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "StudioPaletteBar.h" + +//============================================================================= +/** + * Palette for the splash screen + */ +class CSplashPalette : public CStudioDialog /*CStudioPaletteBar*/ +{ +public: + CSplashPalette(); + virtual ~CSplashPalette(); + virtual BOOL Create(CString inTitle, CCreateContext *inCreateContext, CWnd *inParent = nullptr); +}; +#endif // INCLUDED_SPLASH_PALETTE_H \ No newline at end of file diff --git a/src/Authoring/Studio/_Win/Palettes/Splash/SplashView.cpp b/src/Authoring/Studio/_Win/Palettes/Splash/SplashView.cpp new file mode 100644 index 00000000..fd78e604 --- /dev/null +++ b/src/Authoring/Studio/_Win/Palettes/Splash/SplashView.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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 "SplashView.h" +#include "WidgetControl.h" +#include "StudioApp.h" +#include "SplashControl.h" + +//============================================================================= +/** + * Constructor: Protected because the view is always created dynamically. + * You must call Initialize() before trying to use this class. + */ +CSplashView::CSplashView(QWidget *parent) + : QWidget(parent, Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint) + , m_WndControl(nullptr) + , m_SplashControl(nullptr) +{ + OnInitializePalettes(); +} + +//============================================================================= +/** + * Destructor + */ +CSplashView::~CSplashView() +{ + delete m_WndControl; + m_WndControl = nullptr; + + delete m_SplashControl; +} + +//============================================================================== +/** + * Handles the WM_INITIALUPDATE message. Responsible for preparing the view + * before it is displayed for the first time. + */ +void CSplashView::OnInitializePalettes() +{ + if (!m_WndControl) { + m_SplashControl = new CSplashControl; + m_WndControl = new WidgetControl(m_SplashControl, this); + m_SplashControl->SetName("Splash Control"); + + setFixedSize(m_WndControl->sizeHint()); + } +} + +//============================================================================= +/** + * Resizes the wnd control to fill the whole view. + */ +void CSplashView::resizeEvent(QResizeEvent *event) +{ + Q_UNUSED(event); + m_WndControl->setGeometry(rect()); +} diff --git a/src/Authoring/Studio/_Win/Palettes/Splash/SplashView.h b/src/Authoring/Studio/_Win/Palettes/Splash/SplashView.h new file mode 100644 index 00000000..28498e95 --- /dev/null +++ b/src/Authoring/Studio/_Win/Palettes/Splash/SplashView.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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_SPLASH_VIEW_H +#define INCLUDED_SPLASH_VIEW_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +#include + +//============================================================================== +// Forwards +//============================================================================== +class WidgetControl; +class CSplashControl; + +//============================================================================= +/** + * Windows view encapsulating the splash screen. + */ +class CSplashView : public QWidget +{ +public: + explicit CSplashView(QWidget *parent = nullptr); + ~CSplashView(); + +protected: + void resizeEvent(QResizeEvent *event) override; + +public: + void OnInitializePalettes(); + +protected: + WidgetControl *m_WndControl; + CSplashControl *m_SplashControl; +}; + +#endif // INCLUDED_SPLASH_VIEW_H diff --git a/src/Authoring/Studio/_Win/Studio/stdafx.cpp b/src/Authoring/Studio/_Win/Studio/stdafx.cpp new file mode 100644 index 00000000..b6cac561 --- /dev/null +++ b/src/Authoring/Studio/_Win/Studio/stdafx.cpp @@ -0,0 +1,33 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// stdafx.cpp : source file that includes just the standard includes +// Studio.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" \ No newline at end of file diff --git a/src/Authoring/Studio/_Win/Studio/stdafx.h b/src/Authoring/Studio/_Win/Studio/stdafx.h new file mode 100644 index 00000000..8fb2d134 --- /dev/null +++ b/src/Authoring/Studio/_Win/Studio/stdafx.h @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifdef __cplusplus +#pragma once + +#pragma warning(disable : 4819) + +#include "UICMacros.h" + +//#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define VC_EXTRALEAN // Exclude morerarely-used stuff from Windows headers + +// Modify the following defines if you have to target a platform prior to the ones specified below. +// Refer to MSDN for the latest info on corresponding values for different platforms. + +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit +#define _AFX_ALL_WARNINGS // turns off MFC's hiding of some common and often safely ignored warning + // messages + +#ifdef DEBUG +#define CHECK_BOUNDS // CHECK_BOUNDS affects the way an item is retrieved from container objects +#endif + +#if _MSC_VER >= 1400 +#if defined _M_IX86 +#pragma comment( \ + linker, \ + "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_IA64 +#pragma comment( \ + linker, \ + "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_X64 +#pragma comment( \ + linker, \ + "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#else +#pragma comment( \ + linker, \ + "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") +#endif +#endif + +//============================================================================== +// Standard Includes +//============================================================================== +#include // Standard includes MUST come first +#include +#include +#include + +//============================================================================== +// STL Includes +//============================================================================== +#pragma warning(push, 3) // Temporarily pop to warning level 3 while including standard headers +#pragma warning(disable : 4018) // Disable mismatched < STL warning +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma warning(pop) // Pop out to previous warning level (probably level 4) + +//============================================================================== +// MFC Includes +//============================================================================== +#pragma warning(push, 1) +#include // MFC core and standard components +#include // MFC extensions +#include // MFC Automation classes +#include // AFX Windows Messages (WM_INITIALUPDATE for example) +#include // MFC support for Internet Explorer 4 Common Controls +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#include +#include +#endif // _AFX_NO_AFXCMN_SUPPORT + +//============================================================================== +// ATL Includes +//============================================================================== +#include "atlbase.h" // For CrystalEdit +#include "afxtempl.h" // For CrystalEdit +#include "afxole.h" // For CrystalEdit +#pragma warning(pop) + +// I put these in to help with some of the data model compile times. +#pragma warning(push) +#pragma warning(disable : 4100) +#pragma warning(disable : 4512) +#pragma warning(disable : 4702) +#pragma warning(disable : 4996) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma warning(pop) + +//============================================================================== +// Disable certain warnings since warnings are errors +//============================================================================== +#pragma warning(disable : 4100) // unreferenced formal parameter +#pragma warning(disable : 4702) // Unreachable code +#pragma warning(disable : 4290) // C++ Exception Specification ignored +#pragma warning(disable : 4514) // Unreferenced inline function +#pragma warning(disable : 4121) // Alignment of member sensative to packing +#pragma warning(disable : 4512) // Assignment not generated +#pragma warning(disable : 4355) // This used in member initializer list. +#pragma warning(disable : 4127) // conditional expression is constant +#pragma warning(disable : 4189) // local variable is initialized but not referenced + +//============================================================================== +// Common Includes +//============================================================================== +#include "GUIDUtilities.h" +#include "UICId.h" + +//============================================================================== +// Application Includes (Aug '08 accumulated most popular include files) +//============================================================================== +#include "UICString.h" +#include "UICMath.h" +#include "StringLoader.h" +#include "StudioException.h" +#include "UICExceptions.h" +#include "Exceptions.h" +#include "UICObjectCounter.h" +#include "STLHelpers.h" +#include "Pt.h" +#include "Rct.h" +#include "SafeArray.h" +#include "PlatformMacros.h" +#include "PlatformTypes.h" +#include "Multicaster.h" +#include "GenericFunctor.h" +#include "CColor.h" +#include "InputStream.h" +#include "OutputStream.h" +#include "StudioUtils.h" +#include "StudioDefs.h" +#include "StudioErrorIDs.h" +#include "Strings.h" +#include "StudioPreferences.h" +#include "Renderer.h" +#include "StudioObjectTypes.h" +#include "HotKeys.h" +#include "Dispatch.h" +#include "Cmd.h" +#include "MasterP.h" +#include "Dialogs.h" +#include "Views.h" +#include "ResourceCache.h" +#include "CmdBatch.h" +#include "DispatchListeners.h" +#include "UICFile.h" +#include "StudioConst.h" +#include "resource.h" +#include "StudioProjectSettings.h" +#include "Preferences.h" +#include "StudioClipboard.h" +#include "DropTarget.h" +#include "ContextMenu.h" +#include "TextButton.h" + +#include "StudioPrefixWin32.h" + +//============================================================================== +// Common Includes +//============================================================================== +#include "Resource.h" + +//============================================================================== +// OpenGL Includes +//============================================================================== +#include + +#define UIC_LITTLE_ENDIAN + +#define SAFE_DELETE(ptr) \ + if ((ptr) != nullptr) { \ + delete (ptr); \ + (ptr) = nullptr; \ + } +#endif diff --git a/src/Authoring/Studio/_Win/UI/ContextMenu.cpp b/src/Authoring/Studio/_Win/UI/ContextMenu.cpp new file mode 100644 index 00000000..6aedc806 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/ContextMenu.cpp @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2001 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "ContextMenu.h" +#include "StringLoader.h" + +//============================================================================= +/** + * Constructor + */ +CContextMenu::CContextMenu() + : m_SelectedOption(-1) + , m_IndexBase(0) +{ + m_Menu = ::CreatePopupMenu(); +} + +//============================================================================= +/** + * Destructor + */ +CContextMenu::~CContextMenu() +{ + ::DestroyMenu(m_Menu); +} + +//============================================================================= +/** + * Display the popup menu and perform the actions for whatever choice the + * user makes. + * @param inLocation the screen coordinates of the location to display this menu. + * @param inParentWindow the window to attach this menu to. + */ +long CContextMenu::DoPopup(CPt inLocation, HWND inParentWindow) +{ + // Allow derived classes to update the menu state + Update(); + + ::SetCursor(::LoadCursor(nullptr, IDC_ARROW)); + + // Display the menu and get the user's input + unsigned int theCommandID = (unsigned int)::TrackPopupMenuEx( + m_Menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTBUTTON, + inLocation.x, inLocation.y, inParentWindow, nullptr); + + // If an option was selected then get the performer for that option and execute it. + m_SelectedOption = theCommandID - 1; + if (m_SelectedOption >= 0) { + CContextMenuPerformer *thePerformer = GetSelectedMenuPerformer(m_SelectedOption); + if (thePerformer != nullptr) { + thePerformer->OnOptionSelected(); + } + } + + return m_SelectedOption; +} + +//============================================================================= +/** + * Append a separator to the list of items in this menu. + */ +void CContextMenu::AddSeparator() +{ + ::AppendMenu(m_Menu, MF_SEPARATOR, 0, nullptr); +} + +//============================================================================= +/** + * Append the option onto the end of this menu. + * @param inOptionNameStringID ID indicating the display name for the option. + * @param inPerformer the performer to be called if this option is selected. + * @param inIsEnabled false if the option is to be grayed out and disabled. + */ +void CContextMenu::AddOption(int inOptionNameStringID, CContextMenuPerformer *inPerformer, + bool inIsEnabled /* = true */) +{ + Q3DStudio::CString theOptionName(::LoadResourceString(inOptionNameStringID)); + AddOption(theOptionName, inPerformer, inIsEnabled); +} + +//============================================================================= +/** + * Append the option onto the end of this menu. + * @param inOptionName the display name for the option. + * @param inPerformer the performer to be called if this option is selected. + * @param inIsEnabled false if the option is to be grayed out and disabled. + */ +void CContextMenu::AddOption(const Q3DStudio::CString &inOptionName, + CContextMenuPerformer *inPerformer, bool inIsEnabled /*= true */) +{ + size_t theIndex = m_IndexBase; // start from a base, so that submenu items can be distinguished + + long theFlags = MF_STRING; + if (!inIsEnabled) + theFlags |= MF_GRAYED; + + m_Performers.push_back(inPerformer); + m_Options.push_back(inOptionName); + CContextMenu *theSubMenu = (inPerformer ? inPerformer->GetSubMenu() : nullptr); + if (!theSubMenu) + theIndex += m_Performers.size(); + else // if performer has a submenu. + { + theIndex = (UINT)theSubMenu->GetMenuHandle(); + theFlags |= MF_POPUP; + } + + ::AppendMenuW(m_Menu, theFlags, theIndex, inOptionName); +} + +//============================================================================= +/** + * Remove all options from the menu. + */ +void CContextMenu::Clear() +{ + long theCount = ::GetMenuItemCount(m_Menu); + for (long theIndex = theCount - 1; theIndex >= 0; theIndex--) + ::DeleteMenu(m_Menu, theIndex, MF_BYPOSITION); + + m_Performers.clear(); + m_Options.clear(); +} + +//============================================================================= +/** + * Delete all the performers on this object. + * This is an ease of use method for subclasses if they allocated their + * performers on the heap. This just deletes all of them and clears the list. + */ +void CContextMenu::DeletePerformers() +{ + TPerformerList::iterator thePos = m_Performers.begin(); + for (; thePos != m_Performers.end(); ++thePos) { + delete (*thePos); + } + m_Performers.clear(); +} + +//============================================================================= +/** + * Adds or removes a check mark from the specified item. + * @param inIndex Index of context menu item to be edited + * @param inChecked true to set a check, false to remove a check + */ +void CContextMenu::SetCheck(long inIndex, bool inChecked) +{ + long theFlags = MF_BYPOSITION; + theFlags |= inChecked ? MF_CHECKED : MF_UNCHECKED; + + long theActualIndex = inIndex; + for (long thePos = 0; thePos < (long)::GetMenuItemCount(m_Menu) && thePos <= inIndex; + ++thePos) { + // Account for separators that doesn't "contribute" to the number of performers. + MENUITEMINFO theMenuInfo; + ZeroMemory(&theMenuInfo, sizeof(MENUITEMINFO)); + theMenuInfo.cbSize = sizeof(MENUITEMINFO); + theMenuInfo.fMask = MIIM_TYPE; + ::GetMenuItemInfo(m_Menu, thePos, TRUE, &theMenuInfo); + if (theMenuInfo.fType & MFT_SEPARATOR) + ++theActualIndex; + } + ::CheckMenuItem(m_Menu, theActualIndex, theFlags); +} + +//============================================================================= +/** + * Set all the menu items to being unchecked. + * This will uncheck any items that are currently checked. + */ +void CContextMenu::ClearChecked() +{ + for (long thePos = 0; thePos < (long)::GetMenuItemCount(m_Menu); ++thePos) + ::CheckMenuItem(m_Menu, thePos, MF_BYPOSITION | MF_UNCHECKED); +} + +//============================================================================= +/** + * Gets the string located at a certain index in the context menu list. Index + * is zero-based. + * @param inIndex zero-based index of the item whose string you want + * @return the string at the specified index + */ +Q3DStudio::CString CContextMenu::GetStringAt(long inIndex) +{ + Q3DStudio::CString theString; + if (inIndex >= 0 && inIndex < (long)m_Options.size()) + theString = m_Options.at(inIndex); + return theString; +} + +//============================================================================= +/** + * @return the number of items in this context menu + */ +long CContextMenu::GetItemCount() +{ + return (long)m_Options.size(); +} + +//============================================================================= +/** + * Override this to set enable state of options before the menu pops up + */ +void CContextMenu::Update() +{ +} + +static inline long GetEnableMenuItemFlags(bool inEnabledState) +{ + return MF_BYPOSITION | (inEnabledState ? (MF_ENABLED) : (MF_GRAYED)); +} + +void CContextMenu::EnableOptionByIndex(long inIndex, bool inEnabledState /*= true*/) +{ + if (inIndex >= 0 && inIndex < (long)m_Options.size()) + ::EnableMenuItem(m_Menu, inIndex, GetEnableMenuItemFlags(inEnabledState)); +} + +void CContextMenu::EnableOption(const Q3DStudio::CString &inOptionName, bool inEnabledState) +{ + long theCount = (long)m_Options.size(); + for (long theIndex = 0; theIndex < theCount; ++theIndex) { + if (m_Options[theIndex] == inOptionName) { + ::EnableMenuItem(m_Menu, theIndex, GetEnableMenuItemFlags(inEnabledState)); + break; + } + } +} + +void CContextMenu::EnableOption(unsigned int inOptionNameStringID, bool inEnabledState) +{ + Q3DStudio::CString theOptionName(::LoadResourceString(inOptionNameStringID)); + EnableOption(theOptionName, inEnabledState); +} + +//============================================================================= +/** + * Find the menu performer associated with this index, recursing down any submenu if necessary. + * @param inIndex index of the menu performer + */ +CContextMenuPerformer *CContextMenu::GetSelectedMenuPerformer(long inIndex) +{ + if (inIndex - m_IndexBase < static_cast(m_Performers.size())) { + m_SelectedOption = + inIndex - m_IndexBase; // update this for any references to the selected option + return m_Performers.at(m_SelectedOption); + } + // if not found, recurse down submenus + CContextMenuPerformer *theResult = nullptr; + TPerformerList::iterator theIter = m_Performers.begin(); + for (; theIter != m_Performers.end() && !theResult; ++theIter) { + CContextMenu *theSubMenu = (*theIter)->GetSubMenu(); + if (theSubMenu) + theResult = theSubMenu->GetSelectedMenuPerformer(inIndex); + } + return theResult; +} \ No newline at end of file diff --git a/src/Authoring/Studio/_Win/UI/ControlButton.cpp b/src/Authoring/Studio/_Win/UI/ControlButton.cpp new file mode 100644 index 00000000..d99ce639 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/ControlButton.cpp @@ -0,0 +1,471 @@ +/**************************************************************************** +** +** 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 "resource.h" +#include "ControlButton.h" +#include "MemoryDC.h" +#include "WinUtils.h" + +//============================================================================== +/* + * Constructor: Initializes the object. + */ +CControlButton::CControlButton() + : m_ImageUp(nullptr) + , m_ImageDown(nullptr) + , m_ImageDisabled(nullptr) + , m_ImageActive(nullptr) + , m_ImageMouseTrack(nullptr) + , m_ImageLimbo(nullptr) + , m_ActiveFlag(FALSE) + , m_HotTrackFlag(FALSE) + , m_MouseOverFlag(FALSE) + , m_ActiveDepressedFlag(FALSE) + , m_LimboEnabled(FALSE) + , m_LimboFlag(FALSE) + , m_SimpleFrame(TRUE) + , m_DrawFrame(TRUE) + , m_DepressFlag(FALSE) + , m_3DColorsFlag(FALSE) +{ + m_ImageOffset = CPoint(0, 0); + m_FillColor = GetSysColor(COLOR_WINDOW); + m_TransparentColor = RGB(255, 0, 255); + m_FillColor = GetSysColor(COLOR_3DFACE); +} + +//============================================================================== +/** + * Destructor: Releases the object. + */ +CControlButton::~CControlButton() +{ +} + +BEGIN_MESSAGE_MAP(CControlButton, CButton) +//{{AFX_MSG_MAP(CControlButton) +ON_WM_MOUSEMOVE() +ON_WM_ERASEBKGND() +//}}AFX_MSG_MAP +ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) +END_MESSAGE_MAP() + +//============================================================================== +/** + * Method to create the button + * + * @param inStyle Window style for the button + * @param inRect Bounding rectangle for the button + * @param inParentWnd Parent window for the button + * @param inID Child window ID for the button + * @param inDepressFlag + * @param inLimboEnabled Set to TRUE if this is a tri-state button (defaults to false). + *The third state is referred to as "limbo". + * Then use SetLimbo() to enter and leave the limbo state. + * + * @return Returns TRUE if the button was created + */ +BOOL CControlButton::Create(DWORD inStyle, const RECT &inRect, CWnd *inParentWnd, short inID, + BOOL inDepressFlag, BOOL inLimboEnabled) +{ + m_DepressFlag = inDepressFlag; + m_LimboEnabled = inLimboEnabled; + + return CButton::Create(L"", inStyle /*| WS_BORDER*/ | BS_OWNERDRAW, inRect, inParentWnd, inID); +} + +//============================================================================== +/** + * Adds images to the button for the different button states. + * @param inTransparentColor RGB value of the transparency color used within the + *bitmaps. If there is no transparency color, + * set this to a value that does not appear in any of + *the images. + * @param inImageUp Image for the up state + * @param inImageDown Image for the down state + * @param inImageDisabled Image for the disabled state + * @param inImageActive Image for the active state + * @param inImageMouseTrack Image for hot mouse tracking + * @param inImageLimbo Image for "limbo" state (used for tri-state buttons) + */ +void CControlButton::AddImages(COLORREF inTransparentColor, short inImageUp, short inImageDown, + short inImageDisabled, short inImageActive, short inImageMouseTrack, + short inImageLimbo) +{ + if (inImageUp != 0) + m_ImageUp = (HBITMAP)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(inImageUp), + IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); + + // You always need to have at least one valid image for a button + ASSERT(m_ImageUp != nullptr); + + if (inImageDown != 0) + m_ImageDown = (HBITMAP)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(inImageDown), + IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); + + if (inImageDisabled != 0) + m_ImageDisabled = + (HBITMAP)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(inImageDisabled), + IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); + + if (inImageActive != 0) + m_ImageActive = (HBITMAP)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(inImageActive), + IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); + + if (inImageMouseTrack != 0) + m_ImageMouseTrack = + (HBITMAP)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(inImageMouseTrack), + IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); + + if (inImageLimbo != 0) + m_ImageLimbo = (HBITMAP)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(inImageLimbo), + IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); + + m_TransparentColor = inTransparentColor; + + if (IsWindow(m_hWnd)) + this->Redraw(); +} + +//============================================================================== +/** + * SetImageOffset + * + * Sets an image drawing offset + * + * @param inOffset Offset for image from (0,0) + */ +void CControlButton::SetImageOffset(CPoint inOffset) +{ + m_ImageOffset = inOffset; +} + +//============================================================================== +/** + * SetActiveDepressed + * + * Sets the active depressed flag. If TRUE and this control is set to active, + * then the image will be displayed in a depressed state (for toggle items). + * + * @param inActiveDepressedFlag TRUE if the active state should be depressed + */ +void CControlButton::SetActiveDepressed(BOOL inActiveDepressedFlag) +{ + m_ActiveDepressedFlag = inActiveDepressedFlag; +} + +//============================================================================== +/** + * SetActive + * + * Sets the active state for the button + * + * @param inActiveState Active state for the button + */ +void CControlButton::SetActive(BOOL inActiveFlag) +{ + m_ActiveFlag = inActiveFlag; + + if (IsWindow(m_hWnd)) + this->Redraw(); +} + +//============================================================================== +/** + * GetActive + * + * Gets the active state for the button + * + * @param None + * + * @return Active state for the button + */ +BOOL CControlButton::GetActive() +{ + return m_ActiveFlag; +} + +//============================================================================== +/** + * DrawItem + * + * Handle the owner drawn button + * + * @param inDrawItemStruct DRAWITEMSTRUCT structure + */ +void CControlButton::DrawItem(LPDRAWITEMSTRUCT inDrawItemStruct) +{ + CDC *theDC; + CMemoryDC theMemDC; + BOOL theEnabledFlag; + BOOL theDownStateFlag; + HBITMAP theBitmap = m_ImageUp; + CRect theRect; + + theDC = GetDC(); + + // Get the bounding client rectangle + GetClientRect(theRect); + + theMemDC.Create(theDC, theRect); + + theDownStateFlag = (inDrawItemStruct->itemState & ODS_SELECTED); + + // Is this window enabled? + theEnabledFlag = IsWindowEnabled(); + + if (m_ActiveFlag) + theBitmap = m_ImageActive; + + if (m_MouseOverFlag) + if (m_ImageMouseTrack != 0) + theBitmap = m_ImageMouseTrack; + + if (!theEnabledFlag) { + // Disabled + if (m_ImageDisabled != 0) + theBitmap = m_ImageDisabled; + } else { + // Window is enabled + if (theDownStateFlag) + if (m_ImageDown != 0) + theBitmap = m_ImageDown; + } + + // If the button has limbo enabled, and it in limbo state, it overrides any previous button + // settings + if (m_LimboEnabled && m_LimboFlag) + if (m_ImageLimbo != 0) + theBitmap = m_ImageLimbo; + + // Fill the background color + theMemDC.FillSolidRect(theRect, m_FillColor); + + // Draw the bitmap if it exists + if (theBitmap) + CWinUtils::DrawTransparentBitmap( + &theMemDC, m_ImageOffset.x + theDownStateFlag * m_DepressFlag, + m_ImageOffset.y + theDownStateFlag * m_DepressFlag, theBitmap, m_TransparentColor); + + // Hot tracking the mouse over the button? + if (m_HotTrackFlag) { + if (m_DepressFlag) { + if (theDownStateFlag) + DrawButtonFrame((CDC *)&theMemDC, &theRect, TRUE); + else if (m_MouseOverFlag) + DrawButtonFrame((CDC *)&theMemDC, &theRect, FALSE); + } else { + if (m_MouseOverFlag) + DrawButtonFrame((CDC *)&theMemDC, &theRect, FALSE); + } + } else { + // Draw the frame around the button + if (!m_ActiveFlag) + DrawButtonFrame((CDC *)&theMemDC, &theRect, theDownStateFlag * m_DepressFlag); + } + + theMemDC.Release(); + + ReleaseDC(theDC); +} + +//============================================================================== +/** + * DrawButtonFrame + * + * Draw the button frame + * + * @param inDC Device context for drawing + * @param inRect Bounding rectangle for the button frame + * @param inDownFlag If TRUE, the button is down + */ +void CControlButton::DrawButtonFrame(CDC *inDC, CRect *inRect, BOOL inDownFlag) +{ + if (m_DrawFrame) { + COLORREF theShadowColor = GetSysColor(COLOR_3DSHADOW); + COLORREF theHiliteColor = GetSysColor(COLOR_3DHIGHLIGHT); + + if (inDownFlag) { + theShadowColor = GetSysColor(COLOR_3DHIGHLIGHT); + theHiliteColor = GetSysColor(COLOR_3DSHADOW); + } + + CRect theFrameRect; + + theFrameRect.CopyRect(inRect); + + if (m_SimpleFrame) { + inDC->Draw3dRect(&theFrameRect, theHiliteColor, theShadowColor); + } else { + if (inDownFlag) { + theFrameRect.right--; + theFrameRect.bottom--; + + inDC->Draw3dRect(&theFrameRect, theHiliteColor, theShadowColor); + } else { + // the button is up + theFrameRect.right--; + theFrameRect.bottom--; + + inDC->Draw3dRect(&theFrameRect, theHiliteColor, theShadowColor); + + inDC->MoveTo(theFrameRect.right, theFrameRect.top); + inDC->LineTo(theFrameRect.right, theFrameRect.bottom); + inDC->LineTo(theFrameRect.left, theFrameRect.bottom); + } + } + } +} + +//============================================================================== +/** + * SetHotTrack + * + * Set the hot track (mouse over) flag + * + * @param inHotTrackFlag Hot tracking flag + */ +void CControlButton::SetHotTrack(BOOL inHotTrackFlag) +{ + m_HotTrackFlag = inHotTrackFlag; + + if (IsWindow(m_hWnd)) + this->Redraw(); +} + +//============================================================================== +/** + * OnMouseMove + * + * Handle the WM_MOUSEMOVE message + * + * @param inFlags Flags for WM_MOUSEMOVE + * @param inPoint Cursor position in client coordinates + */ +void CControlButton::OnMouseMove(UINT inFlags, CPoint inPoint) +{ + CButton::OnMouseMove(inFlags, inPoint); + + if (!m_MouseOverFlag) { + this->TrackMouse(); + m_MouseOverFlag = TRUE; + + this->Redraw(); + } +} + +//============================================================================== +/** + * OnMouseMove + * + * Handle the WM_MOUSELEAVE message + * + * @param inwParam WPARAM for the WM_MOUSELEAVE message + * @param inlParam LPARAM for the WM_MOUSELEAVE message + * + * @param Return code - returns TRUE if this message is processed. + */ +LRESULT CControlButton::OnMouseLeave(WPARAM inwParam, LPARAM inlParam) +{ + Q_UNUSED(inwParam); + Q_UNUSED(inlParam); + + m_MouseOverFlag = FALSE; + + this->TrackMouse(FALSE); + + this->Redraw(); + + return TRUE; +} + +//============================================================================== +/** + * TrackMouse + * + * Register for the WM_MOUSELEAVE message to determine when + * the mouse leaves this button. + * + * @param inTrackEnableFlag - TRUE/FALSE depending on whether we want to track the mouse + *event state. + */ +void CControlButton::TrackMouse(BOOL inTrackEnableFlag) +{ + TRACKMOUSEEVENT theTrackMouseEvent; + + memset(&theTrackMouseEvent, 0, sizeof(theTrackMouseEvent)); + + theTrackMouseEvent.cbSize = sizeof(theTrackMouseEvent); + theTrackMouseEvent.dwFlags = TME_LEAVE; + if (!inTrackEnableFlag) + theTrackMouseEvent.dwFlags |= TME_CANCEL; + theTrackMouseEvent.hwndTrack = m_hWnd; + + _TrackMouseEvent(&theTrackMouseEvent); +} + +//============================================================================== +/** + * Redraw + * + * Invalidate and update the button + * + * @param None + */ +void CControlButton::Redraw() +{ + // Invalidate and update the window + InvalidateRect(nullptr, TRUE); + UpdateWindow(); +} + +//============================================================================== +/** + * Handles the WM_ERASEBKGND message. This function is overridden so that we + * can prevent the background from being erased. When we draw the button, the + * background is filled in with the appropriate color. Actually erasing the + * background before a draw was producing flickering. + * + * @param pDC Not used. + */ +BOOL CControlButton::OnEraseBkgnd(CDC *pDC) +{ + Q_UNUSED(pDC); + return 1; +} diff --git a/src/Authoring/Studio/_Win/UI/ControlButton.h b/src/Authoring/Studio/_Win/UI/ControlButton.h new file mode 100644 index 00000000..6f168cb2 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/ControlButton.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#if !defined(AFX_CONTROLBUTTON_H__6B61A743_FB7E_11D4_A87A_005004D48D91__INCLUDED_) +#define AFX_CONTROLBUTTON_H__6B61A743_FB7E_11D4_A87A_005004D48D91__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +///////////////////////////////////////////////////////////////////////////// +// CControlButton window + +class CControlButton : public CButton +{ + // Construction +public: + CControlButton(); + + // Attributes +public: +protected: + HBITMAP m_ImageUp, m_ImageDown, m_ImageDisabled, m_ImageActive, m_ImageMouseTrack, + m_ImageLimbo; // resource bitmap values for various button states + BOOL m_DepressFlag, m_3DColorsFlag; // drawing flags + BOOL m_ActiveFlag; // TRUE if the button is active (ie - selected) + BOOL m_ActiveDepressedFlag; // TRUE if the active state should be drawn depressed + CPoint m_ImageOffset; // Image offset from (0,0) + BOOL m_MouseOverFlag; // TRUE if the mouse is currently over this button + BOOL m_HotTrackFlag; // TRUE if the mouse should be hot-tracked + BOOL m_SimpleFrame; // TRUE if the button is a simple frame + BOOL m_DrawFrame; // TRUE if the frame around the button should be drawn + BOOL m_LimboEnabled; ///< TRUE if this button is capable of being in limbo (decided at creation + ///time) + BOOL m_LimboFlag; ///< TRUE if the button is currently in limbo state + COLORREF m_FillColor; + COLORREF m_TransparentColor; + + // Operations +public: + void AddImages(COLORREF inTransparentColor, short inImageUp, short inImageDown = 0, + short inImageDisabled = 0, short inImageActive = 0, short inImageMouseTrack = 0, + short inImageLimbo = 0); + + BOOL Create(DWORD inStyle, const RECT &inRect, CWnd *inParentWnd, short inID, + BOOL inDepressFlag = TRUE, BOOL inTriState = FALSE); + + BOOL GetActive(); + + void SetActive(BOOL inActiveFlag); + void SetActiveDepressed(BOOL inActiveDepressedFlag); + /// Sets the "limbo" state of the button. Usefully for making tri-state buttons. Limbo state + /// only works if the limbo flag was set during creation. + void SetLimbo(BOOL inLimboFlag) { m_LimboFlag = inLimboFlag; } + /// Returns TRUE if the button is in "limbo" state + BOOL GetLimbo() { return m_LimboFlag; } + void SetHotTrack(BOOL inHotTrackFlag); + void SetImageOffset(CPoint inOffset); + void SetDrawFrame(BOOL inDrawFrame) { m_DrawFrame = inDrawFrame; } + /// Use this function to manually set the fill color behind the button. Use this if you notice + /// that the wrong color is showing up. + void SetFillColor(COLORREF inColor) { m_FillColor = inColor; } +protected: + void DrawButtonFrame(CDC *inDC, CRect *inRect, BOOL inDownFlag); + void Redraw(); + void TrackMouse(BOOL inTrackEnableFlag = TRUE); + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CControlButton) +public: + virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); + //}}AFX_VIRTUAL + + // Implementation +public: + virtual ~CControlButton(); + + // Generated message map functions +protected: + //{{AFX_MSG(CControlButton) + afx_msg void OnMouseMove(UINT nFlags, CPoint point); + afx_msg BOOL OnEraseBkgnd(CDC *pDC); + //}}AFX_MSG + afx_msg LRESULT OnMouseLeave(WPARAM inwParam, LPARAM inlParam); + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CONTROLBUTTON_H__6B61A743_FB7E_11D4_A87A_005004D48D91__INCLUDED_) diff --git a/src/Authoring/Studio/_Win/UI/CrashDlg.cpp b/src/Authoring/Studio/_Win/UI/CrashDlg.cpp new file mode 100644 index 00000000..13277385 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/CrashDlg.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** 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 "MainFrm.h" +#include "CrashDlg.h" + +///////////////////////////////////////////////////////////////////////////// +// CCrashDlg dialog + +CCrashDlg::CCrashDlg(CWnd *pParent /*=nullptr*/) + : CDialog(CCrashDlg::IDD, pParent) + , m_Filename(_T("")) +{ + //{{AFX_DATA_INIT(CCrashDlg) + m_Header = _T(""); + //}}AFX_DATA_INIT + + m_MediumFont2.CreatePointFont(88, CString(CStudioPreferences::GetFontFaceName())); + + m_Color_Background = CStudioPreferences::GetDarkBaseColor(); + m_Color_Text = CStudioPreferences::GetMasterColor(); + m_Color_Gray = CStudioPreferences::GetNormalColor(); + m_Color_Dark = CStudioPreferences::GetInactiveColor(); +} + +void CCrashDlg::DoDataExchange(CDataExchange *pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CCrashDlg) + DDX_Control(pDX, IDC_CRASHICON, m_CrashIcon); + DDX_Text(pDX, IDC_HEADER, m_Header); + DDX_Text(pDX, IDC_HEADER2, m_FilenameSaved); + //}}AFX_DATA_MAP +} + +BEGIN_MESSAGE_MAP(CCrashDlg, CDialog) +//{{AFX_MSG_MAP(CCrashDlg) +ON_BN_CLICKED(IDEXIT, OnExit) +//}}AFX_MSG_MAP +// ON_STN_CLICKED(IDC_HEADER, &CCrashDlg::OnStnClickedHeader) +ON_WM_ERASEBKGND() +ON_WM_CTLCOLOR() +ON_WM_DESTROY() +END_MESSAGE_MAP() + +//============================================================================== +/** + * Set the description of the crash. + * @param inErrorMessage the error message. + */ +//============================================================================== +void CCrashDlg::SetErrorMessage(CString inErrorMessage) +{ + m_ErrorMessage = inErrorMessage; +} + +//============================================================================== +/** + * Set the project filename saved + * @param inFilename the filename of the crashed project + */ +//============================================================================== +void CCrashDlg::SetFilename(CString inFilename) +{ + m_Filename = inFilename; +} + +//============================================================================== +/** + * Set the stack trace for the crash. + * @param inStackTrace the stack trace. + */ +//============================================================================== +void CCrashDlg::SetStackTrace(CString inStackTrace) +{ + m_StackTrace = inStackTrace; +} + +///////////////////////////////////////////////////////////////////////////// +// CCrashDlg message handlers + +void CCrashDlg::OnExit() +{ + this->EndDialog(0); + _exit(EXIT_FAILURE); +} + +void CCrashDlg::SplitLongPath(int controlId, CString &text) +{ + + // Get the device context of your control. + CDC *dc = GetDlgItem(controlId)->GetDC(); + CRect filenameTextRect; + GetDlgItem(controlId)->GetClientRect(filenameTextRect); + + HGDIOBJ hOldFont = dc->SelectObject(&m_MediumFont2); + + CRect tmpStringRect(0, 0, 0, 0); + CString workingString = text; + + CString tmpString; + std::vector insertPosition; + int previousOffset = 0; + + for (int i = 0; i < workingString.GetLength(); ++i) { + tmpString = workingString.Mid(previousOffset, i - previousOffset); + dc->DrawText(tmpString, &tmpStringRect, DT_CALCRECT); + if (tmpStringRect.Width() + 5 > filenameTextRect.Width()) { + previousOffset = i; + insertPosition.push_back(i - 1); + } + } + + // adds in all the \n + for (int i = (int)insertPosition.size() - 1; i >= 0; --i) { + text.Insert(insertPosition[i], '\n'); + } + + dc->SelectObject(hOldFont); +} + +BOOL CCrashDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_Brush.CreateSolidBrush(m_Color_Background); + GetDlgItem(IDC_HEADER)->SetFont(&m_MediumFont2); + GetDlgItem(IDC_HEADER2)->SetFont(&m_MediumFont2); + + // m_Header = ::LoadResourceString( IDS_ERROR_MSGPASSING ).GetMulti( ); + m_Header = m_ErrorMessage; + m_FilenameSaved = m_Filename; + + CString theTitle = ::LoadResourceString(IDS_ERROR_MSGTITLE); + this->SetWindowText(theTitle); + + // Show the exclamation point icon + m_CrashIcon.SetIcon(::LoadIcon(nullptr, IDI_ERROR)); + + SplitLongPath(IDC_HEADER2, m_FilenameSaved); + SplitLongPath(IDC_HEADER, m_Header); + + this->UpdateData(FALSE); + + return TRUE; +} + +BOOL CCrashDlg::OnEraseBkgnd(CDC *pDC) +{ + CRect theClientRect; + GetClientRect(&theClientRect); + pDC->FillSolidRect(theClientRect, m_Color_Background); + + return TRUE; +} + +HBRUSH CCrashDlg::OnCtlColor(CDC *pDC, CWnd *pWnd, UINT) +{ + int theCtrlID = pWnd->GetDlgCtrlID(); + if (theCtrlID == IDREPORT || theCtrlID == IDEXIT || theCtrlID == IDC_LINE_CRASHDLG) { + pDC->SetBkMode(TRANSPARENT); // for area just behind the text + pDC->SetTextColor(m_Color_Text); + } else if (theCtrlID == IDC_HEADER || theCtrlID == IDC_HEADER2) { + pDC->SetBkMode(TRANSPARENT); // for area just behind the text + pDC->SetTextColor(m_Color_Gray); + } + + return m_Brush; +} + +void CCrashDlg::OnDestroy() +{ + CDialog::OnDestroy(); + + m_Brush.DeleteObject(); +} diff --git a/src/Authoring/Studio/_Win/UI/CrashDlg.h b/src/Authoring/Studio/_Win/UI/CrashDlg.h new file mode 100644 index 00000000..75f5765c --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/CrashDlg.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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_CRASH_DIALOG_H +#define INCLUDED_CRASH_DIALOG_H +#include "afxwin.h" +#include + +#pragma once + +///////////////////////////////////////////////////////////////////////////// +// CCrashDlg dialog + +class CCrashDlg : public CDialog +{ + // Construction +public: + CCrashDlg(CWnd *pParent = nullptr); // standard constructor + + // Dialog Data + //{{AFX_DATA(CCrashDlg) + enum { IDD = IDD_CRASHDLG }; + CStatic m_CrashIcon; + CString m_Header; + //}}AFX_DATA + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CCrashDlg) +protected: + virtual void DoDataExchange(CDataExchange *pDX); // DDX/DDV support + //}}AFX_VIRTUAL + + // Implementation +public: + void SetErrorMessage(CString inErrorMessage); + void SetFilename(CString inFilename); + void SetStackTrace(CString inStackTrace); + void SplitLongPath(int controlId, CString &text); + +protected: + CString m_ErrorMessage; + CString m_FilenameSaved; + CString m_StackTrace; + + COLORREF m_Color_Background; + COLORREF m_Color_Text; + COLORREF m_Color_Gray; + COLORREF m_Color_Dark; + CBrush m_Brush; + CFont m_MediumFont2; + + // Generated message map functions + //{{AFX_MSG(CCrashDlg) + afx_msg void OnSave(); + afx_msg void OnExit(); + afx_msg void OnDestroy(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +public: + afx_msg BOOL OnEraseBkgnd(CDC *pDC); + afx_msg HBRUSH OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor); + CString m_Filename; +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // INCLUDED_CRASH_DIALOG_H diff --git a/src/Authoring/Studio/_Win/UI/EditCameraBar.cpp b/src/Authoring/Studio/_Win/UI/EditCameraBar.cpp new file mode 100644 index 00000000..7827ee93 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/EditCameraBar.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "EditCameraBar.h" +#include "MainFrm.h" +#include "SceneView.h" +#include "StringLoader.h" +#include "StudioPreferences.h" +#include "StudioApp.h" +#include "IStudioRenderer.h" + +#include +#include + +//============================================================================== +/** + * Constructor + */ +CEditCameraBar::CEditCameraBar(QWidget* parent) + : QToolBar(parent) + , m_SceneView(nullptr) + , m_ActiveCameraIndex(-1) +{ + OnCustomizeToolbar(); + auto activated = static_cast(&QComboBox::activated); + connect(m_CameraSelector, activated, this, &CEditCameraBar::OnCameraChanged); +} + +//============================================================================== +/** + * Destructor + */ +CEditCameraBar::~CEditCameraBar() +{ + delete m_CameraSelector; + delete m_CameraText; +} + +//============================================================================== +/** + * Setup the list of edit cameras into the camera combo box + * @param inCameras the container that holds the edit cameras + */ +void CEditCameraBar::SetupCameras() +{ + m_CameraSelector->clear(); + Q3DStudio::IStudioRenderer &theRenderer = g_StudioApp.GetRenderer(); + QStringList theCameraNames; + theRenderer.GetEditCameraList(theCameraNames); + int idx = 1; + for (const QString &str : qAsConst(theCameraNames)) { + m_CameraSelector->addItem(str, QVariant((int)idx)); + idx++; + } + + m_CameraSelector->addItem("--------------------------"); + m_CameraSelector->setItemData(m_CameraSelector->count() - 1, -1); // set to an invalid pointer + m_CameraSelector->addItem(::LoadResourceString(IDS_SCENE_CAMERA_VIEW).toQString()); + m_CameraSelector->setItemData(m_CameraSelector->count() - 1, 0); + + long thePreferredView = CStudioPreferences::GetPreferredStartupView(); + long theNumItems = m_CameraSelector->count(); + if (thePreferredView == -1) // deployment view + { + m_CameraSelector->setCurrentIndex(theNumItems - 1); + HandleCameraChanged(theNumItems - 1); // set to the last one + } else { + int theIndex; + if (thePreferredView < theNumItems - 2) + theIndex = thePreferredView; + else // possibly from old content where cameras are removed + theIndex = 0; + m_CameraSelector->setCurrentIndex(theIndex); + HandleCameraChanged(theIndex); + } +} + +//============================================================================== +/** + * Callback method when the camera is changed from the camera selection combo box + */ +void CEditCameraBar::OnCameraChanged() +{ + HandleCameraChanged(m_CameraSelector->currentIndex()); +} + +//============================================================================== +/** + * Handle the switching of the current edit camera + * @param inIndex the index of the to-be-activated camera in the combo box + */ +void CEditCameraBar::HandleCameraChanged(int inIndex) +{ + Q3DStudio::IStudioRenderer &theRenderer = g_StudioApp.GetRenderer(); + QStringList theCameraNames; + theRenderer.GetEditCameraList(theCameraNames); + int theNumCameras = theCameraNames.size(); + if (inIndex < theNumCameras) { + theRenderer.SetEditCamera(inIndex); + m_ActiveCameraIndex = inIndex; + if (m_SceneView) + m_SceneView->SetViewMode(CPlayerContainerWnd::VIEW_EDIT); + } else if (inIndex > theNumCameras) { + theRenderer.SetEditCamera(-1); + m_ActiveCameraIndex = inIndex; + if (m_SceneView) + m_SceneView->SetViewMode(CPlayerContainerWnd::VIEW_SCENE); + } else { + m_CameraSelector->setCurrentIndex(m_ActiveCameraIndex); + } + if (m_SceneView) + m_SceneView->OnEditCameraChanged(); + + CMainFrame *theMainFrame = g_StudioApp.m_pMainWnd; + ASSERT(theMainFrame != nullptr); + + // if the current tool is camera rotate and has been switch to 2d camera + // set the tool to camera pan + if (theMainFrame != nullptr) { + long theToolMode = g_StudioApp.GetToolMode(); + if (theRenderer.DoesEditCameraSupportRotation(theRenderer.GetEditCamera()) == false + && theToolMode == STUDIO_TOOLMODE_CAMERA_ROTATE) { + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_PAN); + m_SceneView->SetToolMode(STUDIO_TOOLMODE_CAMERA_PAN); + } + + // Trigger for tool changed. Changing between deployment/edit camera can change the tool + theMainFrame->OnUpdateToolChange(); + } +} + +//============================================================================== +/** + * Set the current scene view. This scene view is notified when there is a camera + * changed. + * @param inSceneView the scene view object + */ +void CEditCameraBar::SetSceneView(CSceneView *inSceneView) +{ + m_SceneView = inSceneView; +} + +//============================================================================== +/** + * Enable/Disable the edit camera selector combo box. + * @param inFlag true to enable the camera selector combo box, false to disable + */ +void CEditCameraBar::Enable(bool inFlag) +{ + m_CameraSelector->setEnabled(inFlag); +} + +//============================================================================== +/** + * When the active camera is changed, the display string needs to be changed. Hence + * find which entry is the one which is modified and update with the new string + * @param inCamera the camera that has been modified + */ +void CEditCameraBar::OnEditCameraChanged() +{ + using qt3ds::QT3DSI32; + QT3DSI32 cameraIndex = g_StudioApp.GetRenderer().GetEditCamera(); + long theNumEntry = m_CameraSelector->count(); + for (long theIndex = 0; theIndex < theNumEntry; ++theIndex) { + if (m_CameraSelector->itemData(theIndex).toInt() == cameraIndex) { + if (theIndex != m_CameraSelector->currentIndex()) { + m_CameraSelector->setCurrentIndex(theIndex); + HandleCameraChanged(theIndex); + } + break; + } + } +} + +//============================================================================== +/** + * Callback while creating the toolbar in MainFrm. This allows the toolbar to add + * other controls to it. For this toolbar, we want to add a descriptor and a camera + * selector dropdown combobox. + */ +//============================================================================== +void CEditCameraBar::OnCustomizeToolbar() +{ + // Create the combo box + addWidget(m_CameraSelector = new QComboBox); + // We need to specify accessibleName and objectName for the combobox, as it's in the toolbar, + // and we want to use a different style for it. + m_CameraSelector->setAccessibleName(QStringLiteral("cameraSelector")); + m_CameraSelector->setObjectName(QStringLiteral("cameraSelector")); + m_CameraSelector->setMinimumWidth(145); +} diff --git a/src/Authoring/Studio/_Win/UI/EditCameraBar.h b/src/Authoring/Studio/_Win/UI/EditCameraBar.h new file mode 100644 index 00000000..bd8427f5 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/EditCameraBar.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_EDIT_CAMERA_BAR +#define INCLUDED_EDIT_CAMERA_BAR 1 + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +//============================================================================== +// Includes +//============================================================================== +#include "DispatchListeners.h" +#include + +#include + +QT_BEGIN_NAMESPACE +class QComboBox; +class QLabel; +QT_END_NAMESPACE + +//============================================================================== +// Forwards +//============================================================================== +class CSceneView; + +//============================================================================== +/** + * @class CEditCameraBar + */ +class CEditCameraBar : public QToolBar, public CEditCameraChangeListener +{ + Q_OBJECT +public: + CEditCameraBar(QWidget* parent = nullptr); // standard constructor + virtual ~CEditCameraBar(); + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CEditCameraBar) + //}}AFX_VIRTUAL + + // Implementation + // Generated message map functions + void OnCameraChanged(); + void OnCustomizeToolbar(); + +public: + void SetupCameras(); + void SetSceneView(CSceneView *inSceneView); + void Enable(bool inFlag); + void HandleCameraChanged(int inIndex); + + // CEditCameraChangeListener + void OnEditCameraChanged() override; + void OnEditCamerasTransformed() override {} // I am not interested in this + void OnAuthorZoomChanged() override {} + +protected: + CSceneView *m_SceneView; ///< The scene view object + long m_ActiveCameraIndex; ///< The index of the active camera in the list + + // UI Controls definition + QLabel* m_CameraText; ///< Static text showing the word "Camera" + QComboBox* m_CameraSelector; ///< Combo box for selecting edit camera +}; + +#endif diff --git a/src/Authoring/Studio/_Win/UI/EditorPane.cpp b/src/Authoring/Studio/_Win/UI/EditorPane.cpp new file mode 100644 index 00000000..ef274392 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/EditorPane.cpp @@ -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 +//============================================================================== +#include "stdafx.h" + +//============================================================================== +// Includes +//============================================================================== +#include "EditorPane.h" + +//============================================================================== +/** + * Constructor: Creates a CEditorPane + */ +CEditorPane::CEditorPane() + : m_EditObject(nullptr) +{ +} + +//============================================================================== +/** + * Destructor: Releases the CEditorPane + */ +CEditorPane::~CEditorPane() +{ +} + +//============================================================================== +/** + * Set the object that this window will edit. + * Recieve and keep the CAsset to be edited. You can override this method + * for each specific editor view class. + * @param inEditObject The CAsset to be represented and edited in this view. + */ +void CEditorPane::SetEditObject(CAsset *inEditObject) +{ + // Retain this object + m_EditObject = inEditObject; +} + +//============================================================================== +/** + * Get the object that this window is editing. + * return The CAsset that is associated with this window + */ +CAsset *CEditorPane::GetEditObject() +{ + // Return the asset + return m_EditObject; +} + +//============================================================================== +/** + * CloseEditor: Close the editor. + * Override to close each individual editor. + * @return false + */ +bool CEditorPane::CloseEditor() +{ + return false; +} \ No newline at end of file diff --git a/src/Authoring/Studio/_Win/UI/EditorPane.h b/src/Authoring/Studio/_Win/UI/EditorPane.h new file mode 100644 index 00000000..9bc91694 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/EditorPane.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** 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_EDITOR_PANE +#define INCLUDED_EDITOR_PANE 1 + +#pragma once + +//============================================================================== +// Forwards +//============================================================================== +class CAsset; + +//============================================================================== +/** + * @class CEditorPane + * @brief Abstract base class for various editor views. + * + * A base class for universally accessing information from editor views. + */ +class CEditorPane +{ + // Fields +protected: + CAsset *m_EditObject; ///< object being edited by this window. + + // Methods +public: + CEditorPane(); + virtual ~CEditorPane(); + virtual void SetEditObject(CAsset *inEditObject); + CAsset *GetEditObject(); + virtual bool CloseEditor(); +}; + +#endif // INCLUDED_EDITOR_PANE \ No newline at end of file diff --git a/src/Authoring/Studio/_Win/UI/FileDialogEX.cpp b/src/Authoring/Studio/_Win/UI/FileDialogEX.cpp new file mode 100644 index 00000000..9183e536 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/FileDialogEX.cpp @@ -0,0 +1,451 @@ +/**************************************************************************** +** +** 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 "Strings.h" +#include +#include "FileDialogEX.h" +#include "resource.h" +#include "windowsx.h" +#include "Userenv.h" +#include "Commdlg.h" +#include "CdErr.h" +#include "Preferences.h" + +static const long SFILELISTBUFFERSIZE = + 2048; // Size of the char buffer used to store selected filenames +// static BOOL IsWin2000(); + +///////////////////////////////////////////////////////////////////////////// +// CFileDialogEx + +IMPLEMENT_DYNAMIC(CFileDialogEx, CFileDialog) + +//============================================================================== +/** + * CFileDialogEx: constructor + */ +//============================================================================== +CFileDialogEx::CFileDialogEx(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName, + DWORD dwFlags, LPCTSTR lpszFilter, CWnd *pParentWnd) + : CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd) + , m_IsSaving(FALSE) + , m_LastFilterIndex(1) + , m_FileListBuffer(nullptr) + , m_WasCreateNewDirectoryChecked(false) + , m_CreateDirectoryCheckboxEnabled(false) + , m_Preferences(CPreferences::GetUserPreferences()) +{ + m_IsSaving = !bOpenFileDialog; // if not openfiledlg, is saving + m_FilterIndex = 0; // init to 0; index starts from 1 + m_ofnEx.pvReserved = nullptr; + m_ofnEx.dwReserved = 0; + m_ofnEx.FlagsEx = 0; + + if (dwFlags & OFN_ALLOWMULTISELECT) { + // Create buffer for multiple selection + m_FileListBuffer = new TCHAR[SFILELISTBUFFERSIZE]; + m_FileListBuffer[0] = '\0'; + + GetOFN().lpstrFile = m_FileListBuffer; + GetOFN().nMaxFile = SFILELISTBUFFERSIZE; + } +} + +CFileDialogEx::~CFileDialogEx() +{ + if (m_FileListBuffer) { + delete[] m_FileListBuffer; + } +} + +BEGIN_MESSAGE_MAP(CFileDialogEx, CFileDialog) +//{{AFX_MSG_MAP(CFileDialogEX) +ON_COMMAND(IDC_CHECK1, OnCreateNewDirectory) +//}}AFX_MSG_MAP +END_MESSAGE_MAP() + +//============================================================================== +/** + * IsWin2000: function to determine if we are on win2k + * + * @return true if we are on win2k + */ +//============================================================================== +// BOOL IsWin2000 () +//{ +// OSVERSIONINFOEX theOsvi; +// BOOL OsVersionInfoEx; +// +// // Try calling GetVersionEx using the OSVERSIONINFOEX structure, +// // which is supported on Windows 2000. +// // +// // If that fails, try using the OSVERSIONINFO structure. +// +// ZeroMemory( &theOsvi, sizeof( OSVERSIONINFOEX ) ); +// theOsvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFOEX ); +// OsVersionInfoEx = GetVersionEx ( ( OSVERSIONINFO* ) &theOsvi ); +// +// if( !OsVersionInfoEx ) +// { +// // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. +// +// theOsvi.dwOSVersionInfoSize = sizeof ( OSVERSIONINFO ); +// if ( !GetVersionEx( ( OSVERSIONINFO* ) &theOsvi) ) +// return FALSE; +// } +// +// switch ( theOsvi.dwPlatformId ) +// { +// case VER_PLATFORM_WIN32_NT: +// +// if ( theOsvi.dwMajorVersion >= 5 ) +// return TRUE; +// +// break; +// } +// return FALSE; +//} + +void CFileDialogEx::EnableCreateDirectoryCheckbox() +{ + m_CreateDirectoryCheckboxEnabled = true; +} + +// http://msdn.microsoft.com/en-us/magazine/cc300434.aspx +struct RegKeyOverrider +{ + const char *getRegKeyName() + { + return "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\ComDlg32\\PlacesBar"; + } + HKEY m_TempKey; + + RegKeyOverrider() + { + memset(&m_TempKey, 0, sizeof(HKEY)); + long newKeyResult = + RegCreateKeyEx(HKEY_CURRENT_USER, L"UIComposer_FileDialog", 0, nullptr, + REG_OPTION_VOLATILE, KEY_ALL_ACCESS, nullptr, &m_TempKey, nullptr); + if (newKeyResult == ERROR_SUCCESS) { + long overrideResult = RegOverridePredefKey(HKEY_CURRENT_USER, m_TempKey); + ASSERT(overrideResult == ERROR_SUCCESS); + if (overrideResult == ERROR_SUCCESS) { + // Customize the places bar now in or overridden key. + HKEY placesKey; + long placesResult = + RegCreateKeyEx(HKEY_CURRENT_USER, CString(getRegKeyName()), 0, nullptr, + REG_OPTION_VOLATILE, KEY_ALL_ACCESS, nullptr, &placesKey, nullptr); + if (placesResult == ERROR_SUCCESS) { + TCHAR szHomeDirBuf[MAX_PATH] = { 0 }; + + HANDLE hToken = 0; + OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken); + + DWORD BufSize = MAX_PATH; + GetUserProfileDirectory(hToken, szHomeDirBuf, &BufSize); + + CloseHandle(hToken); + + wcscat(szHomeDirBuf, L"\\Links"); + + size_t len = wcslen(szHomeDirBuf); + RegSetValueEx(placesKey, L"Place0", 0, REG_SZ, (const BYTE *)szHomeDirBuf, + (DWORD)len); + + TCHAR buffer[32] = { 0 }; + DWORD folderIds[] = { 8, 0, 17, 18 }; + + for (int idx = 0; idx < 4; ++idx) { + swprintf_s(buffer, L"Place%d", idx + 1); + long setKeyResult = + RegSetValueEx(placesKey, buffer, 0, REG_DWORD, + (const BYTE *)(folderIds + idx), sizeof(DWORD)); + ASSERT(setKeyResult == ERROR_SUCCESS); + } + } + RegCloseKey(placesKey); + } + } + } + ~RegKeyOverrider() + { + RegOverridePredefKey(HKEY_CURRENT_USER, nullptr); + RegDeleteKey(m_TempKey, nullptr); + RegCloseKey(m_TempKey); + } +}; +struct SErrorMap +{ + DWORD m_Error; + const char *m_Name; +}; +static SErrorMap g_ErrorMap[] = { +#define MAKE_STRUCT(name) { name, #name }, + MAKE_STRUCT(CDERR_DIALOGFAILURE) MAKE_STRUCT(CDERR_FINDRESFAILURE) + MAKE_STRUCT(CDERR_INITIALIZATION) MAKE_STRUCT(CDERR_LOADRESFAILURE) + MAKE_STRUCT(CDERR_LOADSTRFAILURE) MAKE_STRUCT(CDERR_LOCKRESFAILURE) + MAKE_STRUCT(CDERR_MEMALLOCFAILURE) MAKE_STRUCT(CDERR_MEMLOCKFAILURE) + MAKE_STRUCT(CDERR_NOHINSTANCE) MAKE_STRUCT(CDERR_NOHOOK) + MAKE_STRUCT(CDERR_NOTEMPLATE) MAKE_STRUCT(CDERR_STRUCTSIZE) + MAKE_STRUCT(FNERR_BUFFERTOOSMALL) MAKE_STRUCT(FNERR_INVALIDFILENAME) + MAKE_STRUCT(FNERR_SUBCLASSFAILURE) +#undef MAKE_STRUCT + { 0, nullptr }, +}; +//============================================================================== +/** + * IsWin2000: Overloaded CFileDialog Function + * + * adds extra parameter if the operating system is win2k + * + * @return true for file open... false for file save as + */ +//============================================================================== +INT_PTR CFileDialogEx::DoModal() +{ + ASSERT_VALID(this); + ASSERT(m_ofn.Flags & OFN_ENABLEHOOK); + ASSERT(m_ofn.lpfnHook != nullptr); // can still be a user hook + + // zero out the file buffer for consistent parsing later + ASSERT(AfxIsValidAddress(m_ofn.lpstrFile, m_ofn.nMaxFile)); + DWORD nOffset = (DWORD)_tcslen(m_ofn.lpstrFile) + 1; + ASSERT(nOffset <= m_ofn.nMaxFile); + memset(m_ofn.lpstrFile + nOffset, 0, (m_ofn.nMaxFile - nOffset) * sizeof(TCHAR)); + + if (!m_InitialDir.IsEmpty()) + m_ofn.lpstrInitialDir = m_InitialDir; + + // If the title has been specified, change it from the OS default + if (!m_Title.IsEmpty()) + m_ofn.lpstrTitle = m_Title; + + // If filterIndex has been changed, use it instead of the default + if (m_FilterIndex != 0) + m_ofn.nFilterIndex = m_FilterIndex; + + if (m_CreateDirectoryCheckboxEnabled) { + // Begin customization for the checkbox for new project dialog + m_ofn.hInstance = GetModuleHandle(nullptr); + m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_NEWPROJEXT); + m_ofn.Flags |= OFN_ENABLETEMPLATE; + } + + // WINBUG: This is a special case for the file open/save dialog, + // which sometimes pumps while it is coming up but before it has + // disabled the main window. + HWND hWndFocus = ::GetFocus(); + BOOL bEnableParent = FALSE; + + // OVerride the places bar so that is always shows favorites. + RegKeyOverrider regOverrider; + m_ofn.hwndOwner = PreModal(); + AfxUnhookWindowCreate(); + if (m_ofn.hwndOwner != nullptr && ::IsWindowEnabled(m_ofn.hwndOwner)) { + bEnableParent = TRUE; + ::EnableWindow(m_ofn.hwndOwner, FALSE); + } + + _AFX_THREAD_STATE *pThreadState = AfxGetThreadState(); + ASSERT(pThreadState->m_pAlternateWndInit == nullptr); + + if (m_ofn.Flags & OFN_EXPLORER) + pThreadState->m_pAlternateWndInit = this; + else + AfxHookWindowCreate(this); + + // This is whre is differs for 2000 + ::memset(&m_ofnEx, 0, sizeof(m_ofnEx)); + ::memcpy(&m_ofnEx, &m_ofn, sizeof(m_ofn)); + // if ( IsWin2000() ){ + // m_ofnEx.lStructSize = sizeof( m_ofnEx ); + //} + + int nResult; + if (m_bOpenFileDialog) + nResult = ::GetOpenFileName(&m_ofnEx); + else + nResult = ::GetSaveFileName(&m_ofnEx); + + if (nResult == 0) { + DWORD error = ::CommDlgExtendedError(); + if (error) { + SErrorMap *theError = nullptr; + for (theError = g_ErrorMap; theError->m_Name; ++theError) { + if (theError->m_Error == error) { + OutputDebugStringA("Massive failure in FileDialogEX!!\n"); + OutputDebugStringA(theError->m_Name); + ASSERT(false); + } + } + } + } + + // Copy back m_ofnEx -> m_ofn + ::memcpy(&m_ofn, &m_ofnEx, sizeof(m_ofn)); + m_ofn.lStructSize = sizeof(m_ofn); + + if (nResult) + ASSERT(pThreadState->m_pAlternateWndInit == nullptr); + pThreadState->m_pAlternateWndInit = nullptr; + + // WINBUG: Second part of special case for file open/save dialog. + if (bEnableParent) + ::EnableWindow(m_ofn.hwndOwner, TRUE); + if (::IsWindow(hWndFocus)) + ::SetFocus(hWndFocus); + + PostModal(); + + if (nResult) { + m_LastFilterIndex = GetOFN().nFilterIndex; + } + + return nResult ? nResult : IDCANCEL; +} + +BOOL CFileDialogEx::OnFileNameOK() +{ + CFileStatus theFileStatus; + CString theFilePath = Q3DStudio::CString(GetOFN().lpstrFile); + // CString theFilePath = this->GetPathName(); // Somehow, this does not return the filename + // with extension + BOOL theReturnValue = FALSE; + + if (m_IsSaving && CFile::GetStatus(theFilePath, theFileStatus)) { + if (theFileStatus.m_attribute & CFile::readOnly) { + Q3DStudio::CString theMsgTitle; + Q3DStudio::CString theMsg; + Q3DStudio::CString theFormattedText; + Q3DStudio::CString theFileNameText = GetOFN().lpstrFileTitle; + // Q3DStudio::CString theFileNameText = GetFileName( ); + + theMsgTitle = ::LoadResourceString(IDS_PROJNAME); + theMsg = ::LoadResourceString(IDS_SAVE_READONLY_WARNING); + theFormattedText.Format(theMsg, static_cast(theFileNameText)); + + ::MessageBox(this->GetSafeHwnd(), theFormattedText, theMsgTitle, + MB_OK | MB_ICONEXCLAMATION); + theReturnValue = TRUE; + } + } + + return theReturnValue; +} + +void CFileDialogEx::SetInitialDirectory(const Q3DStudio::CString &inDir) +{ + Q3DStudio::CFilePath thePath(inDir); + if (thePath.IsFile()) + thePath = thePath.GetDirectory(); + m_InitialDir = thePath; +} + +void CFileDialogEx::OnCreateNewDirectory() +{ + m_WasCreateNewDirectoryChecked = !m_WasCreateNewDirectoryChecked; + m_Preferences.SetValue("CreateDirForProject", m_WasCreateNewDirectoryChecked); +} + +//============================================================================= +/** + * Allows the user to set the title of the dialog. By default, the title is + * determined by the first parameter of the constructor (bOpenFileDialog). + * TRUE specifies a file open dialog and FALSE specifies a Save As dialog. + * The title of the window is then generated by the OS. This function enables + * you to set the title to any string you want, overriding the OS value. + * @param inTitle new title for this dialog; if an empty string is specified, + * the OS generated title will be displayed. + */ +void CFileDialogEx::SetWindowTitle(const Q3DStudio::CString &inTitle) +{ + m_Title = inTitle; +} + +//============================================================================= +/** + * Sets the filter to be selected when the dialog is opened, if specified. + * The filter is indexed from 1 to n. + * + * @param inFilterIndex the index of the filter to be applied as the default + * extension to be used when displaying the dialog. + * @author AT May 29 2003 + */ +void CFileDialogEx::SetFilterIndex(const LONG inFilterIndex) +{ + m_FilterIndex = inFilterIndex; +} + +BOOL CFileDialogEx::OnInitDialog() +{ + BOOL retval = CFileDialog::OnInitDialog(); + if (m_CreateDirectoryCheckboxEnabled) { + CWnd *theWnd = GetDlgItem(IDC_CHECK1); + if (theWnd) { + m_WasCreateNewDirectoryChecked = + m_Preferences.GetValue("CreateDirForProject", true) ? 1 : 0; + Button_SetCheck(theWnd->GetSafeHwnd(), m_WasCreateNewDirectoryChecked ? 1 : 0); + } + } + return retval; +} + +//============================================================================= +/** + * Gets the filter index when the dialog is opened. + * The filter is indexed from 1 to n. + * The member was set at the end of DoModal. + * + * @return the filter index, starting from 1 to n + */ +long CFileDialogEx::GetLastFilterIndex() +{ + return m_LastFilterIndex; +} + +//============================================================================= +/** + * Retrieves the list of files selected during multiple selection + * @param outFileList vector to hold filenames + */ +void CFileDialogEx::RetrieveFileList(TFILELIST &outFileList) const +{ + outFileList.clear(); + POSITION theStartPosition = GetStartPosition(); + + Q3DStudio::CString theFileName; + while (nullptr != theStartPosition) { + theFileName = GetNextPathName(theStartPosition); + outFileList.push_back(CUICFile(theFileName)); + } +} diff --git a/src/Authoring/Studio/_Win/UI/FileDialogEX.h b/src/Authoring/Studio/_Win/UI/FileDialogEX.h new file mode 100644 index 00000000..ad82de14 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/FileDialogEX.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** 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 +//============================================================================== +#if !defined(AFX_FILEDIALOGEX_H__4CF114A7_E3C1_44AA_8A73_92CF2480D010__INCLUDED_) +#define AFX_FILEDIALOGEX_H__4CF114A7_E3C1_44AA_8A73_92CF2480D010__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +struct OPENFILENAMEEX : public OPENFILENAME +{ + void *pvReserved; + DWORD dwReserved; + DWORD FlagsEx; +}; + +//============================================================================== +/** + * CFileDialog: Extends the regular CFileDialog for win2k dialog box + */ +//============================================================================== +class CFileDialogEx : public CFileDialog +{ + DECLARE_DYNAMIC(CFileDialogEx) + +public: + typedef std::vector TFILELIST; + OPENFILENAMEEX m_ofnEx; ///< Extra structure passed in for win 2k dialog + + //========================================================================== + // Methods + //========================================================================== + CFileDialogEx(BOOL bOpenFileDialog, // TRUE for FileOpen, FALSE for FileSaveAs + LPCTSTR lpszDefExt = nullptr, LPCTSTR lpszFileName = nullptr, + DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, LPCTSTR lpszFilter = nullptr, + CWnd *pParentWnd = nullptr); + + virtual ~CFileDialogEx(); + + void EnableCreateDirectoryCheckbox(); + virtual void SetInitialDirectory(const Q3DStudio::CString &inDir); + virtual void SetWindowTitle(const Q3DStudio::CString &inTitle); + virtual void SetFilterIndex(const LONG inFilterIndex); + virtual BOOL OnInitDialog(); + long GetLastFilterIndex(); + void RetrieveFileList(TFILELIST &outFileList) const; + + virtual INT_PTR DoModal(); + virtual BOOL OnFileNameOK(); + void IsSaving() { m_IsSaving = TRUE; } + bool WasCreateNewDirectoryChecked() { return m_WasCreateNewDirectoryChecked; } + +protected: + BOOL m_IsSaving; + Q3DStudio::CString m_InitialDir; + Q3DStudio::CString m_Title; + LONG m_FilterIndex; + long m_LastFilterIndex; //< the last filter index for when a file was selected + wchar_t *m_FileListBuffer; + bool m_CreateDirectoryCheckboxEnabled; + bool m_WasCreateNewDirectoryChecked; + // We have to cache a CPreferences here because we reroute the registry during + // doModal in order to make the file dialogue behavior differently. + // see RegKeyOverrider + CPreferences m_Preferences; + + //========================================================================== + // Members + //========================================================================== + + // Generated message map functions + //{{AFX_MSG(CFileDialogEx) + afx_msg void OnCreateNewDirectory(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_FILEDIALOGEX_H__4CF114A7_E3C1_44AA_8A73_92CF2480D010__INCLUDED_) diff --git a/src/Authoring/Studio/_Win/UI/GLVersionDlg.cpp b/src/Authoring/Studio/_Win/UI/GLVersionDlg.cpp new file mode 100644 index 00000000..cb02578b --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/GLVersionDlg.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "GLVersionDlg.h" + +CGLVersionDlg::CGLVersionDlg(CWnd *pParent /*=nullptr*/) + : CDialog(CGLVersionDlg::IDD, pParent) +{ + m_Title = _T(""); + m_Message = _T(""); + m_Icon = nullptr; + m_DontShowAgain = FALSE; +} + +CGLVersionDlg::~CGLVersionDlg() +{ +} + +void CGLVersionDlg::DoDataExchange(CDataExchange *pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_GL_VERSION_ICON, m_WarningIcon); + DDX_Text(pDX, IDC_GL_VERSION_MESSAGE, m_Message); + DDX_Check(pDX, IDC_CHECK1, m_DontShowAgain); +} + +BEGIN_MESSAGE_MAP(CGLVersionDlg, CDialog) +END_MESSAGE_MAP() + +BOOL CGLVersionDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Set the title + this->SetWindowText(m_Title); + + // Set icon + m_WarningIcon.SetIcon(::AfxGetApp()->LoadStandardIcon(m_Icon)); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CGLVersionDlg::Initialize(const Q3DStudio::CString &inTitle, + const Q3DStudio::CString &inMessage, bool inErrorIcon) +{ + // Set title and message + m_Title = CString(inTitle); + m_Message = CString(inMessage); + + // Set which icon to load + if (inErrorIcon) + m_Icon = IDI_ERROR; + else + m_Icon = IDI_WARNING; +} + +BOOL CGLVersionDlg::GetDontShowAgain() +{ + return m_DontShowAgain; +} diff --git a/src/Authoring/Studio/_Win/UI/GLVersionDlg.h b/src/Authoring/Studio/_Win/UI/GLVersionDlg.h new file mode 100644 index 00000000..908a8441 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/GLVersionDlg.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_GL_VERSION_DLG +#define INCLUDED_GL_VERSION_DLG 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "resource.h" + +//============================================================================== +/** + * CGLVersionDlg: Dialog class for showing Open GL Version Warning + */ +//============================================================================== +class CGLVersionDlg : public CDialog +{ +public: + CGLVersionDlg(CWnd *pParent = nullptr); // standard constructor + virtual ~CGLVersionDlg(); + + // Dialog Data + enum { IDD = IDD_GL_VERSION_DLG }; + +protected: + virtual void DoDataExchange(CDataExchange *pDX); // DDX/DDV support + + DECLARE_MESSAGE_MAP() + CStatic m_WarningIcon; // Warning icon + CString m_Title; // Title for the dialog + CString m_Message; // Warning message + BOOL m_DontShowAgain; // Set to true to "Don't show this dialog again" + LPCTSTR m_Icon; // Which icon to load + +public: + virtual BOOL OnInitDialog(); + void Initialize(const Q3DStudio::CString &inTitle, const Q3DStudio::CString &inMessage, + bool inErrorIcon); + BOOL GetDontShowAgain(); +}; + +#endif // INCLUDED_GL_VERSION_DLG diff --git a/src/Authoring/Studio/_Win/UI/InterpolationDlg.cpp b/src/Authoring/Studio/_Win/UI/InterpolationDlg.cpp new file mode 100644 index 00000000..57d6ae1d --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/InterpolationDlg.cpp @@ -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 / Includes +//============================================================================== + +#include "stdafx.h" +#include "InterpolationDlg.h" +#include "ui_InterpolationDlg.h" + +//============================================================================== +/** + * Constructor: Creates a CInterpolationDlg. + * + * @param parent Pointer to the parent of this dialog (defaults to NULL) + */ +//============================================================================== +CInterpolationDlg::CInterpolationDlg(QWidget *parent) + : QDialog(parent) + , m_ui(new Ui::InterpolationDlg) +{ + m_ui->setupUi(this); +} + +CInterpolationDlg::~CInterpolationDlg() +{ + delete m_ui; + m_ui = nullptr; +} + +void CInterpolationDlg::setEaseIn(uint value) +{ + m_ui->easeInSlider->setValue(value); +} + +void CInterpolationDlg::setEaseOut(uint value) +{ + m_ui->easeOutSlider->setValue(value); +} + +int CInterpolationDlg::easeIn() const +{ + return m_ui->easeInSlider->value(); +} + +int CInterpolationDlg::easeOut() const +{ + return m_ui->easeOutSlider->value(); +} + + diff --git a/src/Authoring/Studio/_Win/UI/InterpolationDlg.h b/src/Authoring/Studio/_Win/UI/InterpolationDlg.h new file mode 100644 index 00000000..5f371625 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/InterpolationDlg.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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_INTERPOLATION_DLG +#define INCLUDED_INTERPOLATION_DLG 1 + +#pragma once + +#include + +namespace Ui { +class InterpolationDlg; +} + +//============================================================================== +/** + * CInterpolationDlg: Dialog class for editing the ease-in/ease-out values of keyframes. + */ +//============================================================================== +class CInterpolationDlg : public QDialog +{ + Q_OBJECT +public: + explicit CInterpolationDlg(QWidget *parent = nullptr); // standard constructor + ~CInterpolationDlg(); + + void setEaseIn(uint value); + void setEaseOut(uint value); + int easeIn() const; + int easeOut() const; + +protected: + Ui::InterpolationDlg* m_ui = nullptr; +}; + +#endif // INCLUDED_INTERPOLATION_DLG diff --git a/src/Authoring/Studio/_Win/UI/InterpolationDlg.ui b/src/Authoring/Studio/_Win/UI/InterpolationDlg.ui new file mode 100644 index 00000000..f0a0a759 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/InterpolationDlg.ui @@ -0,0 +1,305 @@ + + + InterpolationDlg + + + + 0 + 0 + 425 + 195 + + + + Set Keyframe Interpolation + + + + + + + + + 0 + 0 + + + + 100 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 10 + + + + + + + + 0 + 0 + + + + Ease In: + + + + + + + + 0 + 0 + + + + Smooth + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + 100 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 10 + + + + + + + + 0 + 0 + + + + Linear + + + + + + + + 0 + 0 + + + + Linear + + + + + + + + 0 + 0 + + + + Smooth + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Ease Out: + + + + + + + + 0 + 0 + + + + QAbstractSpinBox::NoButtons + + + 100 + + + + + + + + 0 + 0 + + + + QAbstractSpinBox::NoButtons + + + 100 + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + InterpolationDlg + accept() + + + 224 + 272 + + + 157 + 274 + + + + + buttonBox + rejected() + InterpolationDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + + easeInSlider + valueChanged(int) + easeInSpinBox + setValue(int) + + + 331 + 21 + + + 542 + 35 + + + + + easeOutSlider + valueChanged(int) + easeOutSpinBox + setValue(int) + + + 210 + 93 + + + 545 + 93 + + + + + easeInSpinBox + valueChanged(int) + easeInSlider + setValue(int) + + + 533 + 24 + + + 408 + 18 + + + + + easeOutSpinBox + valueChanged(int) + easeOutSlider + setValue(int) + + + 546 + 98 + + + 338 + 84 + + + + + diff --git a/src/Authoring/Studio/_Win/UI/MemoryDC.cpp b/src/Authoring/Studio/_Win/UI/MemoryDC.cpp new file mode 100644 index 00000000..a253e89a --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/MemoryDC.cpp @@ -0,0 +1,258 @@ +/**************************************************************************** +** +** 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 "resource.h" +#include "MemoryDC.h" + +///////////////////////////////////////////////////////////////////////////// +// CMemoryDC + +//============================================================================== +/* + * Constructor: Initializes the object. + */ +//============================================================================== +CMemoryDC::CMemoryDC() + : m_ValidFlag(FALSE) + , m_SrcDC(nullptr) + , m_OldBmp(nullptr) +{ +} + +//============================================================================== +/** + * Destructor: Releases the object. + */ +//============================================================================== +CMemoryDC::~CMemoryDC() +{ + // automatically release and draw on exit + Release(); +} + +//============================================================================== +/** + * Create + * + * Creates the memory DC and image bitmap + * + * @param inDC Source device context + * @param inSrcRect CRect containing the source rectangle for drawing + */ +//============================================================================== +void CMemoryDC::Create(CDC *inDC, CRect inSrcRect) +{ + ASSERT(inDC != nullptr); + + if (!m_ValidFlag) { + // create the memory DC + CreateCompatibleDC(inDC); + + // save the source DC + m_SrcDC = inDC; + + // keep track of the destination rectangle + m_SrcRect.CopyRect(inSrcRect); + + // create a bitmap for the memory bitmap image + m_MemBmp.CreateCompatibleBitmap(inDC, inSrcRect.Width(), inSrcRect.Height()); + + // select the memory image into the memory DC + m_OldBmp = SelectObject(&m_MemBmp); + + m_ValidFlag = TRUE; + } +} + +//============================================================================== +/** + * Release + * + * Releases the memory DC and image bitmap and optionally copies the image + * to the source DC. + * + * @param inCopyToSourceFlag If TRUE, copies the memory image to the source DC + */ +//============================================================================== +void CMemoryDC::Release(BOOL inCopyToSourceFlag) +{ + // copy the offscreen buffer to the sourceDC passed in Create() + + if (m_ValidFlag) { + // blit to source DC to the m_SrcRect + if ((inCopyToSourceFlag) && (m_SrcDC != nullptr)) + m_SrcDC->BitBlt(m_SrcRect.left, m_SrcRect.top, m_SrcRect.Width(), m_SrcRect.Height(), + this, 0, 0, SRCCOPY); + + // de-select the memory image from the DC + SelectObject(m_OldBmp); + + // delete the memory bitmap image + m_MemBmp.DeleteObject(); + + // delete the memory DC + DeleteDC(); + + m_ValidFlag = FALSE; + m_OldBmp = nullptr; + } +} + +//============================================================================== +/** + * CopySourceImage + * + * Copies the source image from the m_SrcRect into the memory DC/image. + * + * @param None + */ +//============================================================================== +void CMemoryDC::CopySourceImage() +{ + if (m_ValidFlag) { + // copy the image from the source rectangle to the offscreen image + if (m_SrcDC != nullptr) + this->BitBlt(0, 0, m_SrcRect.Width(), m_SrcRect.Height(), m_SrcDC, m_SrcRect.left, + m_SrcRect.top, SRCCOPY); + } +} + +//============================================================================== +/** + * ConvertRect + * + * Converts a rectangle based on the source coordinates to one based on + * the memory image's coordinates. + * + * @param inDrawRect Source drawing CRect + * + * @return CRect Contains the converted rectangle + */ +//============================================================================== +CRect CMemoryDC::ConvertRect(CRect inDrawRect) +{ + CRect theRect; + + theRect.CopyRect(inDrawRect); + theRect.OffsetRect(-m_SrcRect.left, -m_SrcRect.top); + + return theRect; +} + +//============================================================================== +/** + * ConvertPoint + * + * Converts a point based on the source coordinates to one based on + * the memory image's coordinates. + * + * @param inDrawRect Source drawing CPoint + * + * @return CPoint Contains the converted point + */ +//============================================================================== +CPoint CMemoryDC::ConvertPoint(CPoint inDrawPoint) +{ + CPoint thePoint; + + // convert point relative to this DC + thePoint = inDrawPoint; + thePoint.x -= m_SrcRect.left; + thePoint.y -= m_SrcRect.top; + + return thePoint; +} + +//============================================================================== +/** + * ConvertXPos + * + * Converts an x-position based on the source coordinates to one based on + * the memory image's coordinates. + * + * @param inXValue Source drawing x-position + * + * @return long Contains the converted x-position + */ +//============================================================================== +long CMemoryDC::ConvertXPos(long inXValue) +{ + long theXPos; + + // convert x coordinate relative to this DC + theXPos = (long)inXValue - (long)m_SrcRect.left; + + return theXPos; +} + +//============================================================================== +/** + * ConvertYPos + * + * Converts an y-position based on the source coordinates to one based on + * the memory image's coordinates. + * + * @param inYValue Source drawing y-position + * + * @return long Contains the converted y-position + */ +//============================================================================== +long CMemoryDC::ConvertYPos(long inYValue) +{ + long theYPos; + + // convert y coordinate relative to this DC + theYPos = (long)inYValue - (long)m_SrcRect.top; + + return theYPos; +} + +//============================================================================== +/** + * SetRect + * + * Sets the drawing/output bounding rectangle. + * + * @param inRect Bounding rectangle for drawing + */ +//============================================================================== +void CMemoryDC::SetRect(CRect inRect) +{ + m_SrcRect = inRect; +} diff --git a/src/Authoring/Studio/_Win/UI/MemoryDC.h b/src/Authoring/Studio/_Win/UI/MemoryDC.h new file mode 100644 index 00000000..f72701e0 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/MemoryDC.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** 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_MEMORY_DC_H +#define INCLUDED_MEMORY_DC_H + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +//============================================================================== +/** + * CMemoryDC: Subclassed CDC for drawing offscreen + * + * This is a subclassed CDC so we can control drawing into a DC with offscreen + * buffers to prevent flickering. + */ +//============================================================================== + +class CMemoryDC : public CDC +{ +public: + //========================================================================== + // Fields + //========================================================================== + +protected: + BOOL m_ValidFlag; // TRUE if we can successfully release/copy the offscreen image to the screen + CRect m_SrcRect; // Bounding rectangle for drawing + CBitmap m_MemBmp; // Offscreen bitmap image + CBitmap *m_OldBmp; // Previous bitmap in the offscreen DC + CDC *m_SrcDC; // Source device context for final blit + + //========================================================================== + // Methods + //========================================================================== + +public: + void SetRect(CRect inRect); + + // Construction + + CMemoryDC(); + virtual ~CMemoryDC(); + + // Access + + CPoint ConvertPoint(CPoint inDrawPoint); + CRect ConvertRect(CRect inDrawRect); + long ConvertXPos(long inXValue); + long ConvertYPos(long inYValue); + void CopySourceImage(); + void Create(CDC *inDC, CRect inSrcRect); + + void Release(BOOL inCopyToSourceFlag = TRUE); +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // INCLUDED_MEMORY_DC_H diff --git a/src/Authoring/Studio/_Win/UI/MenuEdit.cpp b/src/Authoring/Studio/_Win/UI/MenuEdit.cpp new file mode 100644 index 00000000..39c82246 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/MenuEdit.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** 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 "MenuEdit.h" +#include "BCMenu.h" +#include "StudioColors.h" + +//============================================================================== +// Message Map +//============================================================================== + +BEGIN_MESSAGE_MAP(CMenuEdit, CEdit) +//{{AFX_MSG_MAP(CMenuEdit) +ON_WM_SETFOCUS() +ON_WM_CONTEXTMENU() +//}}AFX_MSG_MAP +END_MESSAGE_MAP() + +//============================================================================== +// IMPLEMENTATION +//============================================================================== + +//============================================================================== +/** + * Constructor: Creates a CMenuEdit + */ +//============================================================================== +CMenuEdit::CMenuEdit() +{ +} + +//============================================================================== +/** + * OnSetFocus: The message handler for accepting focus. + * + * @param pOldWnd The window that had focus last. + */ +//============================================================================== +void CMenuEdit::OnSetFocus(CWnd *pOldWnd) +{ + // Allow the parent to handle the request. + CEdit::OnSetFocus(pOldWnd); + + // Select the entire text. + this->SetSel(0, -1); +} + +//****************************************************************************** +// DYNAMIC CREATION +//****************************************************************************** + +IMPLEMENT_DYNAMIC(CMenuEdit, CEdit) + +//============================================================================== +/** + * OnContextMenu: WM_CONTEXTMENU handler for the CMenuEdit. + * + * @param inWnd This window. + * @param inPoint Mouse position when the right button was clicked. + */ +//============================================================================== +void CMenuEdit::OnContextMenu(CWnd *inWnd, CPoint inPoint) +{ + Q_UNUSED(inWnd); + + // Added just because Justin has an eye for detail. :) + + BCMenu theMenu; + BCMenu *thePopupMenu = nullptr; + long theMenuCmd; + + if (GetFocus() != this) + this->SetFocus(); + + // Load the context menu + theMenu.LoadMenu(IDR_CONTEXT_EDIT); +#ifdef _USECONTENTMENUIMAGES_ + theMenu.SetBitmapBackground(MENU_IMAGELIST_BACKCOLOR); + theMenu.LoadToolbar(IDC_EDITCONTEXTTOOLBAR); +#endif + + thePopupMenu = (BCMenu *)theMenu.GetSubMenu(0); + + // Enable/disable menu items + if (!this->CanUndo()) + thePopupMenu->EnableMenuItem(IDC_UNDO, MF_BYCOMMAND | MF_GRAYED); + + // Disable the Select All if there is no text in the control + if (this->GetWindowTextLength() == 0) + thePopupMenu->EnableMenuItem(IDC_SELECTALL, MF_BYCOMMAND | MF_GRAYED); + + // Disable paste if there is no CF_TEXT on the clipboard + if (!IsClipboardFormatAvailable(CF_TEXT)) + thePopupMenu->EnableMenuItem(IDC_PASTE, MF_BYCOMMAND | MF_GRAYED); + + // Check if any text is selected + DWORD theSelection = this->GetSel(); + if (LOWORD(theSelection) == HIWORD(theSelection)) { + // Disable cut, copy and delete commands if no text is selected + thePopupMenu->EnableMenuItem(IDC_CUT, MF_BYCOMMAND | MF_GRAYED); + thePopupMenu->EnableMenuItem(IDC_COPY, MF_BYCOMMAND | MF_GRAYED); + thePopupMenu->EnableMenuItem(IDC_DELETE, MF_BYCOMMAND | MF_GRAYED); + } + + // Post the menu and handle the command here. + theMenuCmd = (long)thePopupMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD + | TPM_NONOTIFY, + inPoint.x, inPoint.y, this, nullptr); + switch (theMenuCmd) { + case IDC_UNDO: + this->Undo(); + break; + + case IDC_CUT: + this->Cut(); + break; + + case IDC_COPY: + this->Copy(); + break; + + case IDC_PASTE: + this->Paste(); + break; + + case IDC_DELETE: + // Delete the selected text + this->ReplaceSel(L"", FALSE); + break; + + case IDC_SELECTALL: + // Select the entire text. + this->SetSel(0, -1); + break; + } + + theMenu.DestroyMenu(); +} diff --git a/src/Authoring/Studio/_Win/UI/MenuEdit.h b/src/Authoring/Studio/_Win/UI/MenuEdit.h new file mode 100644 index 00000000..9aae97e2 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/MenuEdit.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 _MENUEDIT_H_ +#define _MENUEDIT_H_ + +//============================================================================== +// Forwards +//============================================================================== + +//============================================================================== +// Class +//============================================================================== + +//============================================================================== +/** + * @class CMenuEdit + * @brief This edit control has a BCMenu context menu. + */ +//============================================================================== +class CMenuEdit : public CEdit +{ + // Fields + +public: + // Methods + +public: + DECLARE_DYNAMIC(CMenuEdit) + CMenuEdit(); + virtual ~CMenuEdit() {} + +protected: + //{{AFX_MSG(CMenuEdit) + afx_msg void OnSetFocus(CWnd *pOldWnd); + afx_msg void OnContextMenu(CWnd *pWnd, CPoint point); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() +}; + +#endif // _MENUEDIT_H_ diff --git a/src/Authoring/Studio/_Win/UI/MenuItem.cpp b/src/Authoring/Studio/_Win/UI/MenuItem.cpp new file mode 100644 index 00000000..beb77d98 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/MenuItem.cpp @@ -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$ +** +****************************************************************************/ + +//============================================================================== +// Includes +//============================================================================== +#include "stdafx.h" +#include "MenuItem.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +//============================================================================== +/** + * CMenuItem: constructor + * + * @param inName name of the file + * @param inPath path to the file + * @param inID ID tag for this handler in the menu + */ +//============================================================================== +CMenuItem::CMenuItem(CString inName, CString inPath, UINT inID) +{ + m_Name = inName; + m_ID = inID; + m_Path = inPath; +} + +CMenuItem::~CMenuItem() +{ +} diff --git a/src/Authoring/Studio/_Win/UI/MenuItem.h b/src/Authoring/Studio/_Win/UI/MenuItem.h new file mode 100644 index 00000000..f8033b81 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/MenuItem.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$ +** +****************************************************************************/ + +#if !defined(AFX_MENUITEM_H__6383095D_C084_44EB_A6D0_04CC1DA1B74F__INCLUDED_) +#define AFX_MENUITEM_H__6383095D_C084_44EB_A6D0_04CC1DA1B74F__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +//============================================================================== +// CMenuItem Class +//============================================================================== + +//============================================================================== +/** + * CMenuItem: Object for creating dynamic menus + */ +//============================================================================== +class CMenuItem : public CObject +{ +public: + CMenuItem(CString inName, CString inPath, UINT inID); + virtual ~CMenuItem(); + UINT GetID() { return m_ID; }; + CString GetPath() { return m_Path; }; + CString GetName() { return m_Name; }; +protected: + CString m_Path; ///< Path to the file + CString m_Name; ///< Name to use in the menu + UINT m_ID; ///< ID of this menu item +}; + +#endif // !defined(AFX_MENUITEM_H__6383095D_C084_44EB_A6D0_04CC1DA1B74F__INCLUDED_) diff --git a/src/Authoring/Studio/_Win/UI/NumericEdit.cpp b/src/Authoring/Studio/_Win/UI/NumericEdit.cpp new file mode 100644 index 00000000..73ff7bc8 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/NumericEdit.cpp @@ -0,0 +1,347 @@ +/**************************************************************************** +** +** 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 "NumericEdit.h" + +#include + +///////////////////////////////////////////////////////////////////////////// +// CNumericEdit class + +//============================================================================== +/** + * Constructor: Initializes the object. + */ +//============================================================================== +CNumericEdit::CNumericEdit() +{ + m_RangeLow = -1; + m_RangeHigh = -1; + + m_WrapFlag = FALSE; +} + +//============================================================================== +/** + * Destructor: Releases the object. + */ +//============================================================================== +CNumericEdit::~CNumericEdit() +{ +} + +//============================================================================= +/** + * Message Map + */ +//============================================================================= +BEGIN_MESSAGE_MAP(CNumericEdit, CEdit) +//{{AFX_MSG_MAP(CNumericEdit) +ON_CONTROL_REFLECT(EN_KILLFOCUS, OnKillFocus) +ON_CONTROL_REFLECT(EN_UPDATE, OnUpdate) +ON_WM_CHAR() +ON_WM_MOUSEWHEEL() +ON_WM_KEYDOWN() +//}}AFX_MSG_MAP +END_MESSAGE_MAP() + +//============================================================================= +/** + * SetRange: Sets the value range for this control. + * + * @param inRangeLow Low range. + * @param inRangeHigh High range + */ +//============================================================================= +void CNumericEdit::SetRange(long inRangeLow, long inRangeHigh) +{ + // Ensure they are in low/high order + m_RangeLow = min(inRangeLow, inRangeHigh); + m_RangeHigh = max(inRangeLow, inRangeHigh); +} + +//============================================================================= +/** + * SetValue: Sets the numeric value for this control. + * + * @param inValue The new value for this control. + */ +//============================================================================= +void CNumericEdit::SetValue(long inValue) +{ + CString theStrValue; + + theStrValue.Format(L"%lu", inValue); + this->SetWindowText(theStrValue); +} + +//============================================================================= +/** + * GetValue: Returns the numeric value for this control. + * + * @param None + * + * @return long The numeric value for this control. + */ +//============================================================================= +long CNumericEdit::GetValue() +{ + CString theStrValue; + + // Get the current control value. + this->GetWindowText(theStrValue); + + // Convert to long and return. + return atol((char *)LPCTSTR(theStrValue)); +} + +///////////////////////////////////////////////////////////////////////////// +// CNumericEdit message handlers + +//============================================================================= +/** + * OnKillFocus: Handle the EN_KILLFOCUS and validate data. + * + * @param None + */ +//============================================================================= +void CNumericEdit::OnKillFocus() +{ + this->ValidateData(); +} + +//============================================================================= +/** + * OnUpdate: Handle the EN_UPDATE and handle validation before the control is updated. + * + * @param None + */ +//============================================================================= +void CNumericEdit::OnUpdate() +{ + // TODO: If this is a RICHEDIT control, the control will not + // send this notification unless you override the CEdit::OnInitDialog() + // function to send the EM_SETEVENTMASK message to the control + // with the ENM_UPDATE flag ORed into the lParam mask. + + // TODO: Add your control notification handler code here + + this->ValidateData(); +} + +//============================================================================= +/** + * OnChar: Handle the WM_CHAR and validate the key that was pressed. + * + * @param inChar + * @param inRepCnt + * @param inFlags + */ +//============================================================================= +void CNumericEdit::OnChar(UINT inChar, UINT inRepCnt, UINT inFlags) +{ + if (IsNumeric(inChar) || IsEditKey(inChar)) { + CEdit::OnChar(inChar, inRepCnt, inFlags); + } +} + +//============================================================================= +/** + * OnKeyDown: Handle the WM_KEYDOWN and validate the key that was pressed. + * + * @param inChar + * @param inRepCnt + * @param inFlags + */ +//============================================================================= +void CNumericEdit::OnKeyDown(UINT inChar, UINT inRepCnt, UINT inFlags) +{ + if (inChar == VK_UP) { + this->IncrementValue(+1); + this->SetSel(0, -1); + } else if (inChar == VK_DOWN) { + this->IncrementValue(-1); + this->SetSel(0, -1); + } else { + CEdit::OnKeyDown(inChar, inRepCnt, inFlags); + } +} + +//============================================================================= +/** + * IsEditKey: Determine if the pressed key was an edit key. + * + * @param inChar Key character value. + * + * @return TRUE if an editing key + */ +//============================================================================= +BOOL CNumericEdit::IsEditKey(UINT inChar) +{ + BOOL theEditKeyFlag = FALSE; + + if (inChar == VK_DELETE || inChar == VK_BACK || inChar == VK_LEFT || inChar == VK_RIGHT + || inChar == VK_HOME || inChar == VK_END || inChar == VK_UP || inChar == VK_DOWN) + theEditKeyFlag = TRUE; + + return theEditKeyFlag; +} + +//============================================================================= +/** + * IsNumeric: Determine if the pressed key was a numeric key. + * + * @param inChar Key character value. + * + * @return TRUE if a numeric key + */ +//============================================================================= +BOOL CNumericEdit::IsNumeric(UINT inChar) +{ + CString theNumericCheck = L"0123456789"; + BOOL theNumericFlag = FALSE; + + // Determine if the character is a numeric value. + if (theNumericCheck.Find((TCHAR)inChar) != -1) { + theNumericFlag = TRUE; + } + + return theNumericFlag; +} + +//============================================================================= +/** + * ValidateData: Validates the value in the control to keep within range. + * + * @param None + */ +//============================================================================= +void CNumericEdit::ValidateData() +{ + CString theStrValue; + long theValue = 0; + BOOL theChangeFlag = FALSE; + + // Get the current text in the control. + this->GetWindowText(theStrValue); + if (theStrValue.GetLength() == 0) { + theValue = 0; + theChangeFlag = TRUE; + } else + // Check to see that a range has been set + if (m_RangeLow != -1 && m_RangeHigh != -1) { + theValue = this->GetValue(); + + // Check against the low and high range + if (theValue < m_RangeLow) { + theValue = m_RangeLow; + theChangeFlag = TRUE; + } else if (theValue > m_RangeHigh) { + theValue = m_RangeHigh; + theChangeFlag = TRUE; + } + } + + // Has the value changed? + if (theChangeFlag) { + // Update the control's value. + this->SetValue(theValue); + this->SetSel(0, -1); + } +} + +//============================================================================= +/** + * IncrementValue: Increments the current value by inAmount + * + * @param inAmount Amount to change the current control value. + */ +//============================================================================= +void CNumericEdit::IncrementValue(long inAmount) +{ + long theValue; + + // Get the current value + theValue = this->GetValue(); + + // Change theValue + theValue += inAmount; + + // Has a range been set? + if (m_RangeLow != -1 && m_RangeHigh != -1) { + if (theValue < m_RangeLow) { + theValue = m_RangeLow; + + if (m_WrapFlag) + theValue = m_RangeHigh; + } else if (theValue > m_RangeHigh) { + theValue = m_RangeHigh; + + if (m_WrapFlag) + theValue = m_RangeLow; + } + } + + this->SetValue(theValue); +} + +//============================================================================= +/** + * OnMouseWheel: Handle the WM_MOUSEWHEEL message. + * + * @param inFlags + * @param inzDelta + * @param inPoint + * + * @return TRUE if processed. + */ +//============================================================================= +BOOL CNumericEdit::OnMouseWheel(UINT inFlags, short inzDelta, CPoint inPoint) +{ + long theWheelDelta = 0; + + if (inzDelta != 0) + theWheelDelta = inzDelta / abs(inzDelta); + + this->IncrementValue(theWheelDelta); + + this->SetSel(0, -1); + + return CEdit::OnMouseWheel(inFlags, inzDelta, inPoint); +} diff --git a/src/Authoring/Studio/_Win/UI/NumericEdit.h b/src/Authoring/Studio/_Win/UI/NumericEdit.h new file mode 100644 index 00000000..61a4017a --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/NumericEdit.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#if !defined(AFX_NUMERICEDIT_H__F08CC602_8CD7_4A27_AC46_48A80A7D8FD0__INCLUDED_) +#define AFX_NUMERICEDIT_H__F08CC602_8CD7_4A27_AC46_48A80A7D8FD0__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +//============================================================================== +// Includes +//============================================================================== + +#include "MenuEdit.h" + +///////////////////////////////////////////////////////////////////////////// +// CNumericEdit window + +class CNumericEdit : public CMenuEdit +{ + // Construction +public: + CNumericEdit(); + + // Attributes +public: + void SetAllowWrap(BOOL inWrapFlag) { m_WrapFlag = inWrapFlag; } + +protected: + long m_RangeLow, m_RangeHigh; + BOOL m_WrapFlag; + + // Operations +public: + long GetValue(); + + void SetRange(long inRangeLow, long inRangeHigh); + void SetValue(long inValue); + +protected: + void IncrementValue(long inAmount); + BOOL IsEditKey(UINT inChar); + BOOL IsNumeric(UINT inChar); + + void ValidateData(); + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CNumericEdit) + //}}AFX_VIRTUAL + + // Implementation +public: + virtual ~CNumericEdit(); + + // Generated message map functions +protected: + //{{AFX_MSG(CNumericEdit) + afx_msg void OnKillFocus(); + afx_msg void OnUpdate(); + afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); + afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); + afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_NUMERICEDIT_H__F08CC602_8CD7_4A27_AC46_48A80A7D8FD0__INCLUDED_) diff --git a/src/Authoring/Studio/_Win/UI/PlayerContainerWnd.cpp b/src/Authoring/Studio/_Win/UI/PlayerContainerWnd.cpp new file mode 100644 index 00000000..64d7e2f0 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/PlayerContainerWnd.cpp @@ -0,0 +1,510 @@ +/**************************************************************************** +** +** 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 "UICOptions.h" +#include "SceneView.h" +#include "Doc.h" +#include "StudioProjectSettings.h" +#include "Dispatch.h" +#include "HotKeys.h" +#include "MasterP.h" +#include "StudioApp.h" +#include "IStudioRenderer.h" + +//============================================================================== +// Includes +//============================================================================== + +#include "PlatformStrings.h" +#include "PlayerContainerWnd.h" +#include "UICDMStudioSystem.h" +#include "Core.h" +#include "MainFrm.h" +#include "StudioUtils.h" + +#include +#include + +//============================================================================== +// Class CPlayerContainerWnd +//============================================================================== + +//============================================================================== +/** + * Constructor: Initializes the object. + */ +//============================================================================== +CPlayerContainerWnd::CPlayerContainerWnd(CSceneView *inSceneView) + : QAbstractScrollArea(inSceneView) + , m_SceneView(inSceneView) + , m_PlayerWnd(NULL) + , m_IsMouseDown(false) + , m_IsMiddleMouseDown(false) + , m_ViewMode(VIEW_SCENE) +{ + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); +} + +//============================================================================== +/** + * Destructor: Releases the object. + */ +//============================================================================== +CPlayerContainerWnd::~CPlayerContainerWnd() +{ +} + +bool CPlayerContainerWnd::ShouldHideScrollBars() +{ + return m_ViewMode == VIEW_EDIT || g_StudioApp.IsAuthorZoom(); +} + +//============================================================================== +/** + * SetPlayerWndPosition: Sets the position of the child player window + * + * Called when the view is scrolled to position the child player window + * @param outLeftPresentationEdge the left edge of the presentation, with the scroll position + *taken into consideration + * @param outTopPresentionEdge the top edge of the presentation, with the scroll + *position taken into consideration + * + */ +//============================================================================== +void CPlayerContainerWnd::SetPlayerWndPosition(long &outLeftPresentationEdge, + long &outTopPresentionEdge) +{ + long theHScrollPosition, theVScrollPosition; + // Negate to adjust actual client positions + theHScrollPosition = -horizontalScrollBar()->value(); + theVScrollPosition = -verticalScrollBar()->value(); + + QRect theClientRect = rect(); + + // Horizontal scrollbar does not exist + if (m_ClientRect.width() < theClientRect.width()) { + theHScrollPosition = + theClientRect.left() + (theClientRect.width() / 2) - (m_ClientRect.width() / 2); + outLeftPresentationEdge = theHScrollPosition; + } else // This stays a negated value + outLeftPresentationEdge = theHScrollPosition; + + // Vertical scrollbar does not exist + if (m_ClientRect.height() < theClientRect.height()) { + theVScrollPosition = + theClientRect.top() + (theClientRect.height() / 2) - (m_ClientRect.height() / 2); + outTopPresentionEdge = theVScrollPosition; + } else // This stays a negated value + outTopPresentionEdge = theVScrollPosition; + + // Move the child player window + m_PlayerWnd->setGeometry(QRect(QPoint(theHScrollPosition, theVScrollPosition), m_ClientRect.size())); +} + +//============================================================================== +/** + * SetScrollRanges: Sets the scroll ranges when the view is being resized + */ +//============================================================================== +void CPlayerContainerWnd::SetScrollRanges() +{ + + long theScrollWidth = 0; + long theScrollHeight = 0; + +#ifdef INCLUDE_EDIT_CAMERA + if (ShouldHideScrollBars()) { + horizontalScrollBar()->setRange(0, 0); + verticalScrollBar()->setRange(0, 0); + horizontalScrollBar()->setValue(0); + verticalScrollBar()->setValue(0); + } else +#endif + { + QSize theSize = GetEffectivePresentationSize(); + + theScrollWidth = theSize.width(); + theScrollHeight = theSize.height(); + + + // Set scrollbar ranges + horizontalScrollBar()->setRange(0, theScrollWidth - width()); + verticalScrollBar()->setRange(0, theScrollHeight - height()); + horizontalScrollBar()->setPageStep(width()); + verticalScrollBar()->setPageStep(height()); + horizontalScrollBar()->setVisible(true); + verticalScrollBar()->setVisible(true); + } +} + +//============================================================================== +/** + * OnRulerGuideToggled: + * Handle scrollbar position when ruler, guide has been toggled + * + */ +//============================================================================== +void CPlayerContainerWnd::OnRulerGuideToggled() +{ + int scrollAmount = g_StudioApp.GetRenderer().AreGuidesEnabled() ? 16 : -16; + bool hasHorz = horizontalScrollBar()->isVisible(); + bool hasVert = verticalScrollBar()->isVisible(); + int hscrollPos = 0, vscrollPos = 0; + if (hasHorz) { + hscrollPos = qMax(horizontalScrollBar()->value() + scrollAmount, 0); + } + if (hasVert) { + vscrollPos = qMax(verticalScrollBar()->value() + scrollAmount, 0); + } + horizontalScrollBar()->setValue(hscrollPos); + verticalScrollBar()->setValue(vscrollPos); + m_PlayerWnd->update(); +} + +//============================================================================== +/** + * RecenterClient: Recenters the Client rect in the View's client area. + */ +//============================================================================== +void CPlayerContainerWnd::RecenterClient() +{ + QRect theViewClientRect = rect(); + QSize theClientSize; + m_ClientRect = theViewClientRect; + +#ifdef INCLUDE_EDIT_CAMERA + if (ShouldHideScrollBars()) { + } else +#endif + { + theClientSize = GetEffectivePresentationSize(); + + // Only center if we need to scroll + if (theClientSize.width() > theViewClientRect.width()) { + // compute the size of the client rectangle to display + m_ClientRect.setLeft( + (theViewClientRect.width() / 2) - (theClientSize.width() / 2) - (theClientSize.width() % 2)); + m_ClientRect.setRight((theViewClientRect.width() / 2) + (theClientSize.width() / 2)); + } + + if (theClientSize.height() > theViewClientRect.height()) { + m_ClientRect.setTop( + (theViewClientRect.height() / 2) - (theClientSize.height() / 2) - (theClientSize.height() % 2)); + m_ClientRect.setBottom((theViewClientRect.height() / 2) + (theClientSize.height() / 2)); + } + } + + QRect glRect = m_ClientRect; + glRect.setWidth(int(devicePixelRatio() * m_ClientRect.width())); + glRect.setHeight(int(devicePixelRatio() * m_ClientRect.height())); + g_StudioApp.GetRenderer().SetViewRect(glRect); +} + +//============================================================================== +/** + * OnLButtonDown: Called whenever the user left clicks in the view. + * This processes the WM_LBUTTONDOWN message. This message is generated whenever + * the user left clicks in the view. Since this could involve selection of an item + * in the scene, it may (if the click is in the Client rect) call ProcessMouseClick() + * on the Document to perform the selection. + * @param inFlags the flags passed in from the message call + * @param inPoint the point where the event takes place + */ +void CPlayerContainerWnd::mousePressEvent(QMouseEvent *event) +{ + if ((event->button() == Qt::LeftButton) || (event->button() == Qt::RightButton)) { + long theToolMode = g_StudioApp.GetToolMode(); + g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseDown(SceneDragSenderType::Matte, event->pos(), + theToolMode); + m_IsMouseDown = true; + } else if (event->button() == Qt::MiddleButton) { +#ifdef INCLUDE_EDIT_CAMERA + const bool theCtrlKeyIsDown = event->modifiers() & Qt::ControlModifier; + const bool theAltKeyIsDown = event->modifiers() & Qt::AltModifier; + + bool theToolChanged = false; + if (rect().contains(event->pos()) && !IsDeploymentView()) { + // If both the control key and the Alt key is not down + if (!theCtrlKeyIsDown && !theAltKeyIsDown) { + // press Scroll Wheel Click + // Do Camera Pan + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_PAN); + theToolChanged = true; + } else if ((theAltKeyIsDown) && (!theCtrlKeyIsDown)) { + // press Alt-Scroll Wheel Click + // Do Camera Rotate if we are in 3D Camera + if (g_StudioApp.GetRenderer().DoesEditCameraSupportRotation( + g_StudioApp.GetRenderer().GetEditCamera())) { + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_ROTATE); + theToolChanged = true; + } + } + } + + if (theToolChanged) { + Q_EMIT toolChanged(); + m_SceneView->SetViewCursor(); + + long theToolMode = g_StudioApp.GetToolMode(); + g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseDown(SceneDragSenderType::Matte, + event->pos(), theToolMode); + m_IsMouseDown = true; + m_IsMiddleMouseDown = true; + } +#else + Q_UNUSED(inFlags); + Q_UNUSED(inPoint); +#endif + } +} + +//============================================================================== +/** + * OnLButtonUp: Called whenever the user releases the left mouse button. + * + * This processes the WM_LBUTTONUP message. This message is generated whenever + * the left mouse button. We release the mouse capture to stop dragging. + * + * @param inFlags The flags passed in from the message call + * @param inPoint The point where the event takes place + */ +//============================================================================== +void CPlayerContainerWnd::mouseReleaseEvent(QMouseEvent *event) +{ + if ((event->button() == Qt::LeftButton) || (event->button() == Qt::RightButton)) { + // Need to commit the current command when we have a mouse up. :) + g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseUp(SceneDragSenderType::Matte); + g_StudioApp.GetCore()->CommitCurrentCommand(); + m_IsMouseDown = false; + } else if (event->button() == Qt::MiddleButton) { + #ifdef INCLUDE_EDIT_CAMERA + g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseUp(SceneDragSenderType::Matte); + g_StudioApp.GetCore()->CommitCurrentCommand(); + if (m_IsMiddleMouseDown) { + m_IsMouseDown = false; + m_IsMiddleMouseDown = false; + + const bool theCtrlKeyIsDown = event->modifiers() & Qt::ControlModifier; + const bool theAltKeyIsDown = event->modifiers() & Qt::AltModifier; + + if (!IsDeploymentView()) { + if (!theCtrlKeyIsDown && !theAltKeyIsDown) { + // none of the modifier key is pressed... reset to previous tool + m_SceneView->RestorePreviousTool(); + } else if (theCtrlKeyIsDown && theAltKeyIsDown) { + // since both modifier is down... let the ctrl has priority + m_SceneView->SetToolOnCtrl(); + } + m_SceneView->SetViewCursor(); + Q_EMIT toolChanged(); + } + } + #endif + } +} + +//============================================================================== +/** + * OnMouseMove: Called whenever the user moves the mouse in the window. + * + * This processes the WM_MOUSEMOVE message. This message is generated whenever + * the user moves the mouse in the view. This tells lets the document process it + * as well since the user could be dragging an object. + * + * @param inFlags The flags passed in from the message call + * @param inPoint The point where the event takes place + */ +//============================================================================== +void CPlayerContainerWnd::mouseMoveEvent(QMouseEvent* event) +{ + if (m_IsMouseDown) { + UICPROFILE(OnMouseMove); + + long theModifierKeys = 0; + if (event->buttons() & Qt::LeftButton) + theModifierKeys = CHotKeys::MOUSE_LBUTTON | CHotKeys::GetCurrentKeyModifiers(); + else if (event->buttons() & Qt::RightButton) + theModifierKeys = CHotKeys::MOUSE_RBUTTON | CHotKeys::GetCurrentKeyModifiers(); + + long theToolMode = g_StudioApp.GetToolMode(); + g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseDrag( + SceneDragSenderType::Matte, event->pos(), theToolMode, theModifierKeys); + } +} + +//============================================================================== +/** + * OnMouseWheel: Called whenever the mouse wheel. + * + * This processes the WM_MOUSEWHEEL message. + * + * @param inFlags the flags passed in from the message call + * @param inPoint the point where the event takes place + */ +//============================================================================== +void CPlayerContainerWnd::wheelEvent(QWheelEvent* event) +{ +#ifdef INCLUDE_EDIT_CAMERA + // Note : Mouse wheel is a special animal of the scene drag tool. We dont change the tool + // so as not to affect the toolbar button and the view cursor. This will just do the zoom + // and the cursor is not changed. + + const bool theCtrlKeyIsDown = event->modifiers() & Qt::ControlModifier; + const bool theAltKeyIsDown = event->modifiers() & Qt::AltModifier; + + // Keeping these codes here, till we finalized the behavior and confirm these not needed + // long theToolMode = g_StudioApp.GetToolMode( ); + //// If both the control key and the Alt key is not down + // if ( !theCtrlKeyIsDown && !theAltKeyIsDown && !IsDeploymentView( ) ) + //{ + // if ( theToolMode != STUDIO_TOOLMODE_CAMERA_ZOOM ) + // { + // g_StudioApp.SetToolMode( STUDIO_TOOLMODE_CAMERA_ZOOM ); + // theToolMode = STUDIO_TOOLMODE_CAMERA_ZOOM; + // m_MouseWheeling = true; + + // Q_EMIT toolChanged(); + // SetViewCursor( ); + // } + //} + + // Mouse Wheel + // Do Camera Zoom + if (!theCtrlKeyIsDown && !theAltKeyIsDown && !IsDeploymentView()) + g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseWheel( + SceneDragSenderType::Matte, event->delta(), STUDIO_TOOLMODE_CAMERA_ZOOM); +#else + Q_UNUSED(event); +#endif +} + +void CPlayerContainerWnd::scrollContentsBy(int, int) +{ + long x, y; + SetPlayerWndPosition(x, y); +} + +//============================================================================== +/** + * Set the view mode of the current scene view, whether we are in editing mode + * or deployment mode. For editing mode, we want to use the full scene area without + * any matte area. + * @param inViewMode the view mode of this scene + */ +void CPlayerContainerWnd::SetViewMode(EViewMode inViewMode) +{ + m_ViewMode = inViewMode; + m_SceneView->RecheckSizingMode(); + if (m_ViewMode == VIEW_SCENE) { + // switching from edit mode to deployment mode, release the edit camera tool and set it to + // object move + long theCurrentToolSettings = g_StudioApp.GetToolMode(); + bool theIsCameraTool = (theCurrentToolSettings & STUDIO_CAMERATOOL_MASK ? true : false); + if (theIsCameraTool) { + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_MOVE); + m_SceneView->SetToolMode(STUDIO_TOOLMODE_MOVE); + } + } +} + +//============================================================================== +/** + * return the view mode of the current scene view, whether we are in editing mode + * or deployment mode. For editing mode, we want to use the full scene area without + * any matte area. + * @return the current view mode + */ +CPlayerContainerWnd::EViewMode CPlayerContainerWnd::GetViewMode() +{ + return m_ViewMode; +} + +//============================================================================== +/** + * Checks whether we are in deployment view mode. + * @return true if is in deployment view mode, else false + */ +bool CPlayerContainerWnd::IsDeploymentView() +{ + return m_ViewMode == VIEW_SCENE ? true : false; +} + +QSize CPlayerContainerWnd::GetEffectivePresentationSize() const +{ + CPt cSize = g_StudioApp.GetCore()->GetStudioProjectSettings()->GetPresentationSize(); + QSize theSize(cSize.x, cSize.y); + + // If we have guides, resize the window with enough space for the guides as well as the + // presentation + // This is a very dirty hack because we are of course hardcoding the size of the guides. + // If the size of the guides never changes, the bet paid off. + if (g_StudioApp.GetRenderer().AreGuidesEnabled()) { + theSize += QSize(32, 32); + } + + return theSize / devicePixelRatio(); +} + +//============================================================================== + +void CPlayerContainerWnd::SetPlayerWnd(CPlayerWnd *inPlayerWnd) +{ + m_PlayerWnd = inPlayerWnd; + viewport()->setBackgroundRole(QPalette::Dark); + m_PlayerWnd->SetContainerWnd(this); + m_PlayerWnd->setParent(viewport()); + m_PlayerWnd->setVisible(true); + m_PlayerWnd->resize(m_PlayerWnd->sizeHint()); +} + +//============================================================================== +/** + * OnSize: Handles the WM_SIZE message + * + * Recenters the Client and recaluclates the matte when a resize message is + * generated. + * + * @param nType Specifies the type of resizing requested. + * @param cx Specifies the new width of the client area. + * @param cy Specifies the new height of the client area. + */ +//============================================================================== +void CPlayerContainerWnd::resizeEvent(QResizeEvent* event) +{ + QAbstractScrollArea::resizeEvent(event); + +#ifdef INCLUDE_EDIT_CAMERA + SetScrollRanges(); +#endif +} diff --git a/src/Authoring/Studio/_Win/UI/PlayerContainerWnd.h b/src/Authoring/Studio/_Win/UI/PlayerContainerWnd.h new file mode 100644 index 00000000..d4ac3cf5 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/PlayerContainerWnd.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** 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_PLAYER_CONTAINER_WND_H +#define INCLUDED_PLAYER_CONTAINER_WND_H 1 + +#pragma once + +#include + +class CSceneView; +class CStudioApp; +class CPlayerWnd; +class CWGLRenderContext; + +//============================================================================== +// Class CPlayerContainerWnd +//============================================================================== + +class CPlayerContainerWnd : public QAbstractScrollArea +{ + Q_OBJECT + //============================================================================== + // Typedefs + //============================================================================== +public: + typedef enum { + VIEW_EDIT = 0, ///< Edit View + VIEW_SCENE, ///< Scene View + } EViewMode; + +public: + CPlayerContainerWnd(CSceneView *inSceneView); + virtual ~CPlayerContainerWnd(); + + void SetPlayerWnd(CPlayerWnd *inPlayerWnd); + void SetPlayerWndPosition(long &outLeftPresentationEdge, long &outTopPresentionEdge); + void SetScrollRanges(); + void RecenterClient(); + void OnRulerGuideToggled(); + + void SetViewMode(EViewMode inViewMode); + EViewMode GetViewMode(); + bool IsDeploymentView(); + + QRect GetDisplayedClientRect() const { return m_ClientRect; } + bool IsMouseDown() const { return m_IsMouseDown; } + bool IsMiddleMouseDown() const { return m_IsMiddleMouseDown; } + + QSize GetEffectivePresentationSize() const; + +Q_SIGNALS: + void toolChanged(); + +protected: + void resizeEvent(QResizeEvent *) override; + void mousePressEvent(QMouseEvent *) override; + void mouseReleaseEvent(QMouseEvent *) override; + void mouseMoveEvent(QMouseEvent *) override; + void wheelEvent(QWheelEvent *) override; + + void scrollContentsBy(int, int) override; + +private: + CPlayerContainerWnd() {} + bool ShouldHideScrollBars(); + +protected: + CSceneView *m_SceneView; ///< Pointer to the SceneView for rulers manipulation + CPlayerWnd *m_PlayerWnd; ///< Pointer to the window control that contains client + QRect m_ClientRect; ///< The rect where the client is drawn + bool m_IsMouseDown; ///< true if the mouse (any button) is down + bool m_IsMiddleMouseDown; ///< true if the middle mouse ( or scroll wheel ) is down + EViewMode m_ViewMode; +}; + +#endif // INCLUDED_PLAYER_CONTAINER_WND_H diff --git a/src/Authoring/Studio/_Win/UI/PlayerWnd.cpp b/src/Authoring/Studio/_Win/UI/PlayerWnd.cpp new file mode 100644 index 00000000..ca9c7c51 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/PlayerWnd.cpp @@ -0,0 +1,278 @@ +/**************************************************************************** +** +** 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 "PlayerWnd.h" +#include "MainFrm.h" +#include "SceneView.h" +#include "Dispatch.h" +#include "MasterP.h" +#include "HotKeys.h" +#include "StudioApp.h" +#include "Doc.h" +#include "Dispatch.h" +#include "HotKeys.h" +#include "MouseCursor.h" +#include "ResourceCache.h" +#include "SceneDropTarget.h" +#include "Core.h" +#include "IDragable.h" +#include "WGLRenderContext.h" +#include "IStudioRenderer.h" + +#include + +//============================================================================== +// Class CPlayerWnd +//============================================================================== + +CPlayerWnd::CPlayerWnd(QWidget *parent) + : QOpenGLWidget(parent) + , m_ContainerWnd(nullptr) + , m_IsMouseDown(false) + , m_PreviousToolMode(0) + , m_FitClientToWindow(false) +{ + m_LastKnownMousePosition = QPoint(-1, -1); + + setAcceptDrops(true); + RegiserForDnd(this); + AddMainFlavor(EUIC_FLAVOR_FILE); + AddMainFlavor(EUIC_FLAVOR_ASSET_UICFILE); + AddMainFlavor(EUIC_FLAVOR_ASSET_LIB); + AddMainFlavor(EUIC_FLAVOR_BASIC_OBJECTS); + + setFormat(CWGLRenderContext::selectSurfaceFormat(this)); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); +} + +//============================================================================== +/** + * Destructor: Releases the object. + */ +//============================================================================== +CPlayerWnd::~CPlayerWnd() +{ +} + +//============================================================================== +/** + * OnMouseMove: Handle the WM_MOUSEMOVE message + * + * @param inFlags flags passed in with th mouse move message + * @param inPoint where the mouse is + */ +//============================================================================== +void CPlayerWnd::mouseMoveEvent(QMouseEvent *event) +{ + if (event->buttons() & Qt::MiddleButton) { + // Middle button events are handled by the parent CPlayerContainerWnd + event->ignore(); + } else { + if (m_IsMouseDown) { + long theModifierKeys = 0; + if (event->buttons() & Qt::LeftButton) + theModifierKeys = CHotKeys::MOUSE_LBUTTON | CHotKeys::GetCurrentKeyModifiers(); + else if (event->buttons() & Qt::RightButton) + theModifierKeys = CHotKeys::MOUSE_RBUTTON | CHotKeys::GetCurrentKeyModifiers(); + + long theToolMode = g_StudioApp.GetToolMode(); + g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseDrag( + SceneDragSenderType::SceneWindow, event->pos(), theToolMode, theModifierKeys); + } else { + g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseMove( + SceneDragSenderType::SceneWindow, event->pos()); + } + } +} + +//============================================================================== +/** + * OnSize: Handle the WM_SIZE message + * + * @param nType Passed to the base class + * @param cx change in x window size + * @param cy change in y window size + */ +//============================================================================== +void CPlayerWnd::resizeEvent(QResizeEvent *event) +{ + QOpenGLWidget::resizeEvent(event); +#ifdef KDAB_TEMPORARILY_REMOVED + CWnd *theChildWnd = this->GetWindow(GW_CHILD); + + if (theChildWnd != nullptr) { + CRect theWndRect; + + // Set the child window at the same position as the parent + this->GetWindowRect(&theWndRect); + + theChildWnd->ScreenToClient(&theWndRect); + theChildWnd->MoveWindow(&theWndRect, FALSE); + } +#endif + update(); +} + +//============================================================================== +/** + * OnLButtonDown: Handle the WM_LBUTTONDOWN message + * + * @param inFlags Flags passed in from the message + * @param inPoint The point wher the button was clicked + */ +//============================================================================== +void CPlayerWnd::mousePressEvent(QMouseEvent *event) +{ + const Qt::MouseButton btn = event->button(); + if ((btn == Qt::LeftButton) || (btn == Qt::RightButton)) { + long theToolMode = g_StudioApp.GetToolMode(); + g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseDown(SceneDragSenderType::SceneWindow, + event->pos(), theToolMode); + m_IsMouseDown = true; + } else if (btn == Qt::MiddleButton) { + event->ignore(); + } +} + +//============================================================================== +/** + * OnLButtonUp: Called whenever the user releases the left mouse button. + * + * This processes the WM_LBUTTONUP message. This message is generated whenever + * the left mouse button. We release the mouse capture to stop dragging. + * + * @param inFlags the flags passed in from the message call + * @param the point where the lbutton up takes place + */ +//============================================================================== +void CPlayerWnd::mouseReleaseEvent(QMouseEvent *event) +{ + const Qt::MouseButton btn = event->button(); + if ((btn == Qt::LeftButton) || (btn == Qt::RightButton)) { + g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseUp(SceneDragSenderType::SceneWindow); + g_StudioApp.GetCore()->CommitCurrentCommand(); + m_IsMouseDown = false; + } else if (btn == Qt::MiddleButton) { + event->ignore(); + } +} + +void CPlayerWnd::mouseDoubleClickEvent(QMouseEvent *event) +{ + g_StudioApp.GetCore()->GetDispatch()->FireSceneMouseDblClick( + SceneDragSenderType::SceneWindow, event->pos()); +} + + +bool CPlayerWnd::OnDragWithin(CDropSource &inSource) +{ + CSceneViewDropTarget theTarget; + return theTarget.Accept(inSource); +} +bool CPlayerWnd::OnDragReceive(CDropSource &inSource) +{ + CSceneViewDropTarget theTarget; + Q_EMIT dropReceived(); + return theTarget.Drop(inSource); +} +void CPlayerWnd::OnDragLeave() +{ +} + +//============================================================================== +/** + * SetContainerWnd: keep track of a pointer to the containing window + * + * @param inContainerWnd pointer to what the containing window will be set to + */ +//============================================================================== +void CPlayerWnd::SetContainerWnd(CPlayerContainerWnd *inContainerWnd) +{ + m_ContainerWnd = inContainerWnd; + updateGeometry(); +} + +QSize CPlayerWnd::sizeHint() const +{ + if (m_ContainerWnd) + return m_ContainerWnd->GetEffectivePresentationSize(); + else + return QOpenGLWidget::sizeHint(); +} + +void CPlayerWnd::initializeGL() +{ + Q3DStudio::IStudioRenderer &theRenderer(g_StudioApp.GetRenderer()); + if (theRenderer.IsInitialized() == false) { + try { + theRenderer.Initialize(this); + } catch (...) { +#ifdef KDAB_TEMPORARILY_REMOVED + + wchar_t theBufferString[MAX_ENTRY_LENGTH]; + + _aswprintf(theBufferString, MAX_ENTRY_LENGTH - 1, + L"Unable to initialize OpenGL.\nThis may be because your graphic device is " + L"not sufficient, or simply because your driver is too old.\n\nPlease try " + L"upgrading your graphics driver and try again."); + ::wcsncat(theBufferString, L"\r\n\r\n", MAX_ENTRY_LENGTH - 1); + + ::MessageBoxW(nullptr, theBufferString, L"Fatal Error", + MB_OK | MB_ICONSTOP | MB_DEFBUTTON1); +#endif + exit(1); + } + } +} + +void CPlayerWnd::paintGL() +{ + Q3DStudio::IStudioRenderer &theRenderer(g_StudioApp.GetRenderer()); + // don't use request render here, this has to be + // synchronous inside paintGL + theRenderer.RenderNow(); +} + +void CPlayerWnd::resizeGL(int width, int height) +{ + // this also passes the new FBO to the CWGLContext + Q3DStudio::IStudioRenderer &theRenderer(g_StudioApp.GetRenderer()); + theRenderer.SetViewRect(QRect(0, 0, width * devicePixelRatio(), + height * devicePixelRatio())); +} diff --git a/src/Authoring/Studio/_Win/UI/PlayerWnd.h b/src/Authoring/Studio/_Win/UI/PlayerWnd.h new file mode 100644 index 00000000..25dfd949 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/PlayerWnd.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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_PLAYERWND_H +#define INCLUDED_PLAYERWND_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "DropContainer.h" +#include "PlayerContainerWnd.h" + +#include + +//============================================================================== +// Forwards +//============================================================================== +class CPlayerContainerWnd; +class CStudioApp; +class CMouseCursor; +class CHotkeys; + +//============================================================================== +// Class CPlayerWnd +//============================================================================== + +class CPlayerWnd : public QOpenGLWidget, public CWinDropContainer +{ + Q_OBJECT +public: + explicit CPlayerWnd(QWidget *parent = nullptr); + ~CPlayerWnd(); + + void SetContainerWnd(CPlayerContainerWnd *inSceneView); + + QSize sizeHint() const override; + + bool OnDragWithin(CDropSource &inSource) override; + bool OnDragReceive(CDropSource &inSource) override; + void OnDragLeave() override; + void OnReflectMouse(CPt &inPoint, Qt::KeyboardModifiers inFlags) override {} + +protected: + + CPlayerContainerWnd *m_ContainerWnd; + bool m_IsMouseDown; + long m_PreviousToolMode; ///< The previous tool mode (used when toggling with hotkeys to switch + ///back to previous mode on release) + bool m_FitClientToWindow; ///< True if we are in Fit to Window Mode + + QPoint m_LastKnownMousePosition; + +Q_SIGNALS: + void dropReceived(); + +protected: + void mouseMoveEvent(QMouseEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + + void initializeGL() override; + void paintGL() override; + void resizeGL(int width, int height) override; +}; + +#endif // INCLUDED_PLAYERWND_H diff --git a/src/Authoring/Studio/_Win/UI/PopupWnd.cpp b/src/Authoring/Studio/_Win/UI/PopupWnd.cpp new file mode 100644 index 00000000..f0b5d2cd --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/PopupWnd.cpp @@ -0,0 +1,248 @@ +/**************************************************************************** +** +** 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 "PopupWnd.h" +#include "AppFonts.h" + +#include "StudioPreferences.h" + +//============================================================================== +/** + * Constructor: Initialize the object. + * + * Creates default fonts, colors, etc. + */ +CPopupWnd::CPopupWnd() + : m_CenterPt(0, 0) + , m_IsStationary(false) +{ + // get the proper font from appfonts + m_Font = CAppFonts::GetInstance()->GetNormalFont(); + + // Set the default colors (use default system tooltip colors) + m_TextColor = ::GetSysColor(COLOR_INFOTEXT); + m_BkColor = ::GetSysColor(COLOR_INFOBK); + ::CColor theBGColor(CStudioPreferences::GetTooltipBackgroundColor()); + m_BkColor = theBGColor.GetRGBColor(); + m_BkBrush = new CBrush(); + m_BkBrush->CreateSolidBrush(m_BkColor); +} + +//============================================================================== +/** + * Destructor: Destroys the object and releases associated memory. + */ +CPopupWnd::~CPopupWnd() +{ + // Clean up GDI objects + + // m_Font.DeleteObject(); + + if (m_BkBrush) { + DeleteObject(m_BkBrush); + delete m_BkBrush; + } +} + +//============================================================================== +// Message Map +//============================================================================== +BEGIN_MESSAGE_MAP(CPopupWnd, CWnd) +//{{AFX_MSG_MAP(CPopupWnd) +ON_WM_PAINT() +ON_WM_ERASEBKGND() +//}}AFX_MSG_MAP +END_MESSAGE_MAP() + +//============================================================================== +/** + * OnPaint: Handles the WM_PAINT windows message. + * + * Calls GetWindowText() and draws the text to the screen. + */ +void CPopupWnd::OnPaint() +{ + CPaintDC theDC(this); // device context for painting + CString theText; + + GetWindowText(theText); + if (theText.GetLength() > 0) { + + // Change the font + CFont *theOldFont = theDC.SelectObject(m_Font); + theDC.SetTextColor(m_TextColor); + theDC.SetBkColor(m_BkColor); + + // Paint the text + CRect theClientRect; + this->GetClientRect(theClientRect); + theDC.DrawText(theText, theClientRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + + // Restore original font + theDC.SelectObject(theOldFont); + } +} + +//============================================================================== +/** + * SetWindowText: Sets the text for this window. + * + * Overridden from parent so that we can calculate how big we need to make the + * pop-up window so that the text fits. Automatically adjusts the window + * size/position to fit the new text string. + */ +void CPopupWnd::SetWindowText(LPCTSTR lpszString) +{ + CString theNewText; + theNewText.Format(L" %s ", lpszString); + + // Set the window text + CWnd::SetWindowText(theNewText); + + // Calculate the new window rect with the specified text + CDC *theDC = GetDC(); + CRect theRect(0, 0, 1, 1); + CFont *theOldFont = theDC->SelectObject(m_Font); + + theDC->DrawText(theNewText, theRect, DT_CALCRECT); + theDC->SelectObject(theOldFont); + ::AdjustWindowRect(theRect, this->GetStyle(), FALSE); + CPoint theTopLeft = theRect.TopLeft(); + CPoint theBottomRight = theRect.BottomRight(); + ::ClientToScreen(this->GetParent()->GetSafeHwnd(), &theTopLeft); + ::ClientToScreen(this->GetParent()->GetSafeHwnd(), &theBottomRight); + CRect theAdjustedRect(theTopLeft, theBottomRight); + int theX = abs((int)(theAdjustedRect.Width() / 2) - m_CenterPt.x); + int theY = abs((int)(theAdjustedRect.Height() / 2) - m_CenterPt.y); + + ReleaseDC(theDC); + + // Move the window to the new position, with the new size, still centered at m_CenterPt + this->SetWindowPos(nullptr, theX, theY, theAdjustedRect.Width(), theAdjustedRect.Height(), + SWP_NOZORDER | SWP_NOACTIVATE); +} + +//============================================================================== +/** + * SetCenterPoint: Changes the center of this window. + * + * Use this function to specify where you want the center of the pop-up window + * to appear. The window is automatically moved to the new center position. + */ +void CPopupWnd::SetCenterPoint(CPoint inPoint) +{ + if ((m_IsStationary && !IsWindowVisible()) || !m_IsStationary) { + // Store the center point + m_CenterPt = inPoint; + + // Calculate the new window position so that it is centered at the new point + CRect theWindowRect; + this->GetWindowRect(theWindowRect); + CPoint theTopLeft = theWindowRect.TopLeft(); + CPoint theBottomRight = theWindowRect.BottomRight(); + ::ClientToScreen(this->GetParent()->GetSafeHwnd(), &theTopLeft); + ::ClientToScreen(this->GetParent()->GetSafeHwnd(), &theBottomRight); + CRect theAdjustedRect(theTopLeft, theBottomRight); + int theX = abs((int)(theAdjustedRect.Width() / 2) - m_CenterPt.x); + int theY = abs((int)(theAdjustedRect.Height() / 2) - m_CenterPt.y); + + // Move the window + SetWindowPos(nullptr, theX, theY, theAdjustedRect.Width(), theAdjustedRect.Height(), + SWP_NOZORDER | SWP_NOACTIVATE); + } +} + +//============================================================================== +/** + * SetBkColor: Changes the background color of this window. + * + * Defaults to COLOR_INFOBK (tooltip background color). Creates a brush used + * in OnEraseBkgnd() of the specified color. + * + * @param inColor The new background color. + */ +void CPopupWnd::SetBkColor(COLORREF inColor) +{ + m_BkColor = inColor; + + // If we already have a background brush + if (m_BkBrush) { + // Kill it + DeleteObject(m_BkBrush); + delete m_BkBrush; + } + + // Make a brush of the specified color + m_BkBrush = new CBrush(); + m_BkBrush->CreateSolidBrush(m_BkColor); +} + +//============================================================================== +/** + * OnEraseBkgnd: Handles the WM_ERASEBKGND windows message. + * Redraws the client rect using the current background brush. + * + * @param pDC Pointer to a display context for drawing. + * @return TRUE. + */ +BOOL CPopupWnd::OnEraseBkgnd(CDC *pDC) +{ + // Erase the client rect using the background brush so it's the right color + CRect theClientRect; + this->GetClientRect(theClientRect); + pDC->FillRect(theClientRect, m_BkBrush); + return TRUE; +} + +//============================================================================== +/** + * UpdateToolTip: Allows you to change multiple properties on this window at once. + * + * @param inCenter New center point of the popup window + * @param inText New window text for the window + * @param inShowWindow true to show the window, false to hide the window + */ +void CPopupWnd::UpdateToolTip(CPoint inCenter, CString inText, bool inShowWindow) +{ + int theShowFlag = (inShowWindow) ? SW_SHOWNA : SW_HIDE; + + this->SetCenterPoint(inCenter); + this->SetWindowText(inText); + this->ShowWindow(theShowFlag); + this->Invalidate(FALSE); + this->UpdateWindow(); +} diff --git a/src/Authoring/Studio/_Win/UI/PopupWnd.h b/src/Authoring/Studio/_Win/UI/PopupWnd.h new file mode 100644 index 00000000..da58c9b1 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/PopupWnd.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** 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_POP_UP_WND +#define INCLUDED_POP_UP_WND 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +//============================================================================== +/** + * CPopupWnd: Class for making pop-up windows (a replacement for tooltips). + * + * To use, just create a CPopupWnd, set the text that you want displayed, then + * call ShowWindow() to toggle the window on and off. Default color scheme of + * this window mimics the system settings for tooltips. + */ +class CPopupWnd : public CWnd +{ +public: + CPopupWnd(); + + virtual ~CPopupWnd(); + + /// Sets the text to display in this window + void SetWindowText(LPCTSTR lpszString); + + /// Sets the center point of this window in screen coordinates + void SetCenterPoint(CPoint inPoint); + + /// Sets the center point of this window from an x,y pair (screen coordinates) + void SetCenterPoint(int inX, int inY) { SetCenterPoint(CPoint(inX, inY)); } + + /// Retrieves the center point of this window (screen coordinates) + CPoint GetCenterPoint() { return m_CenterPt; } + + /// Sets the color of the text + void SetTextColor(COLORREF inColor) { m_TextColor = inColor; } + + /// Sets the background color of the window + void SetBkColor(COLORREF inColor); + + /// Returns a pointer to the CFont object used to draw the text. You can make changes to the + /// font using the pointer that's returned, + /// just don't delete it. The default font is set in the constructor as Arial 13. + CFont *GetFont() { return m_Font; } + + /// Allows you to change multiple properties on this window at once. + void UpdateToolTip(CPoint inCenter, CString inText, bool inShowWindow); + + /// + void SetStationary(bool inIsStationary) { m_IsStationary = inIsStationary; } + +protected: + CPoint m_CenterPt; ///< Center of this window in screen coordinates + CFont *m_Font; ///< Font for the window text + COLORREF m_TextColor; ///< Color of the text + COLORREF m_BkColor; ///< Background color of the window + CBrush *m_BkBrush; ///< Brush used for paiting the background of the window + bool m_IsStationary; ///< If the window is stationary, then it can only be moved while it is not + ///showing + + // Generated message map functions +protected: + //{{AFX_MSG(CPopupWnd) + afx_msg void OnPaint(); + afx_msg BOOL OnEraseBkgnd(CDC *pDC); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +#endif // INCLUDED_POP_UP_WND diff --git a/src/Authoring/Studio/_Win/UI/PreviewOutputDlg.cpp b/src/Authoring/Studio/_Win/UI/PreviewOutputDlg.cpp new file mode 100644 index 00000000..649efa8c --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/PreviewOutputDlg.cpp @@ -0,0 +1,366 @@ +/**************************************************************************** +** +** 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" + +#pragma warning(disable : 4127) + +//============================================================================== +// Includes +//============================================================================== +#include "PreviewOutputDlg.h" +#include "StudioClipboard.h" +#include "UICFileTools.h" +#include "StudioApp.h" +#include "Doc.h" +#include "Mainfrm.h" +#include "Dialogs.h" +#include "Strings.h" +#include "Resource.h" +#include "Core.h" + +// CPreviewOutput dialog + +IMPLEMENT_DYNAMIC(CPreviewOutputDlg, CDialog) + +CPreviewOutputDlg::CPreviewOutputDlg(const Q3DStudio::CString &inCmd, + const Q3DStudio::CString &inExportedFile, + CPreviewHelper::EExecMode inViewMode) + : CDialog(CPreviewOutputDlg::IDD, nullptr) + , m_Cmd(inCmd) + , m_ExportedFile(inExportedFile) + , m_ViewMode(inViewMode) + , m_ReadThreadHandle(nullptr) + , m_PreviewProcessHandle(nullptr) +{ + m_OutputReadThreadParam.m_ReadHandle = nullptr; + m_OutputReadThreadParam.m_Context = nullptr; +} + +CPreviewOutputDlg::~CPreviewOutputDlg() +{ + if (m_ReadThreadHandle) { + TerminateThread(m_ReadThreadHandle, 0); + m_ReadThreadHandle = nullptr; + } + + if (m_OutputReadThreadParam.m_ReadHandle) { + CloseHandle(m_OutputReadThreadParam.m_ReadHandle); + m_OutputReadThreadParam.m_ReadHandle = nullptr; + } +} + +void CPreviewOutputDlg::DoDataExchange(CDataExchange *pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_LIST_PREVIEW_STATUS, m_ListCtrl); +} + +//============================================================================= +/** + * Message Handler when dialog is initially opened. + */ +//============================================================================= +BOOL CPreviewOutputDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + // Set the dialog header + Q3DStudio::CString theFile = g_StudioApp.GetCore()->GetDoc()->GetDocumentPath().GetName(); + if (theFile == "") + theFile = ::LoadResourceString(IDS_UNTITLED_DOCUMENT_TITLE); + Q3DStudio::CString theDlgHeader; + Q3DStudio::CString theOperation; + switch (m_ViewMode) { + case CPreviewHelper::EXECMODE_PREVIEW: + theOperation = ::LoadResourceString(IDS_CONFIG_EXPORT_PREVIEW); + break; + + case CPreviewHelper::EXECMODE_DEPLOY: + theOperation = ::LoadResourceString(IDS_CONFIG_EXPORT_DEPLOY); + break; + } + theDlgHeader.Format(::LoadResourceString(IDS_CONFIG_PREVIEW_TITLE), + static_cast(theOperation), + static_cast(theFile)); + SetWindowText(theDlgHeader); + + // Prepare the list control + COLORREF theColor = 0x00C0C0C0; + m_ListCtrl.SetBkColor(theColor); + m_ListCtrl.SetTextBkColor(theColor); + CRect theRect; + m_ListCtrl.GetClientRect(theRect); + m_ListCtrl.InsertColumn(0, L"", LVCFMT_LEFT, + theRect.Width() * 2); // Double the width to see more + + // Start the preview + if (!ExecutePreview()) { + CUICFile thePreviewerFile(CUICFile::GetApplicationDirectory(), m_ExportedFile); + Q3DStudio::CString theMessage; + theMessage.Format(::LoadResourceString(IDS_CONFIG_PREVIEW_ERROR_MSG), + static_cast(thePreviewerFile.GetAbsolutePosixPath())); + g_StudioApp.GetDialogs()->DisplayMessageBox( + ::LoadResourceString(IDS_CONFIG_PREVIEW_ERROR_TITLE), theMessage, + CUICMessageBox::ICON_ERROR, false); + } + + return TRUE; +} + +//============================================================================= +/** + * Handler for copying + */ +//============================================================================= +void CPreviewOutputDlg::OnCopyText() +{ + try { + Q3DStudio::CString theText = ""; + int theNumEntry = m_ListCtrl.GetItemCount(); + for (int theIndex = 0; theIndex < theNumEntry; ++theIndex) { + theText += m_ListCtrl.GetItemText(theIndex, 0); + theText += "\r\n"; + } + CStudioClipboard::CopyTextToClipboard(theText); + } catch (...) { + } +} + +//============================================================================= +/** + * Handler for OK Button + */ +//============================================================================= +void CPreviewOutputDlg::OnOK() +{ + TerminateThread(m_ReadThreadHandle, 0); + CDialog::OnOK(); + m_ReadThreadHandle = nullptr; +} + +BEGIN_MESSAGE_MAP(CPreviewOutputDlg, CDialog) +ON_BN_CLICKED(IDC_BUTTON_COPY_TEXT, OnCopyText) +END_MESSAGE_MAP() + +//============================================================================== +/** + * Spawn the process to execute the preview operation and redirect it's output + * to the list control + */ +//============================================================================== +BOOL CPreviewOutputDlg::ExecutePreview() +{ + HANDLE theOutputReadHandleTmp; + HANDLE theOutputReadHandle; + HANDLE theOutputWriteHandle; + + // Set up the security attributes struct. + SECURITY_ATTRIBUTES theSecurityAttr; + theSecurityAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + theSecurityAttr.lpSecurityDescriptor = nullptr; + theSecurityAttr.bInheritHandle = TRUE; + + // Create the child output pipe. + if (!CreatePipe(&theOutputReadHandleTmp, &theOutputWriteHandle, &theSecurityAttr, 0)) + return FALSE; + + // Create new output read handle. Set the Properties to FALSE. + // Otherwise, the child inherits the properties and, as a result, + // non-closeable handles to the pipes are created. + if (!DuplicateHandle(GetCurrentProcess(), theOutputReadHandleTmp, GetCurrentProcess(), + &theOutputReadHandle, // Address of new handle. + 0, FALSE, // Make it uninheritable. + DUPLICATE_SAME_ACCESS)) + return FALSE; + + // Close inheritable copies of the handles you do not want to be inherited. + CloseHandle(theOutputReadHandleTmp); + + LaunchPreviewProcess(theOutputWriteHandle, m_Cmd); + + // Close pipe handles (do not continue to modify the parent). + // You need to make sure that no handles to the write end of the + // output pipe are maintained in this process or else the pipe will + // not close when the child process exits and the ReadFile will hang. + CloseHandle(theOutputWriteHandle); + + // Spawn a thread to busy read the preivew process output. + DWORD theThreadId; + m_OutputReadThreadParam.m_Context = this; + m_OutputReadThreadParam.m_ReadHandle = theOutputReadHandle; + m_ReadThreadHandle = CreateThread(nullptr, 0, CPreviewOutputDlg::ReadOutputThread, + (LPVOID)&m_OutputReadThreadParam, 0, &theThreadId); + return TRUE; +} + +//============================================================================== +/** + * Callback when the preview operation has completed. + */ +//============================================================================== +void CPreviewOutputDlg::PreviewProcessTerminated() +{ + DWORD theExitCode; + GetExitCodeProcess(m_PreviewProcessHandle, &theExitCode); + if (theExitCode == 0) + PostMessage(WM_CLOSE); // close the window + else { + Q3DStudio::CString theOperation; + switch (m_ViewMode) { + case CPreviewHelper::EXECMODE_PREVIEW: + theOperation = ::LoadResourceString(IDS_CONFIG_EXPORT_PREVIEW); + break; + + case CPreviewHelper::EXECMODE_DEPLOY: + theOperation = ::LoadResourceString(IDS_CONFIG_EXPORT_DEPLOY); + break; + } + Q3DStudio::CString theMessage; + theMessage.Format(::LoadResourceString(IDS_CONFIG_PREVIEW_ERROR_TEXT), + static_cast(theOperation)); + DisplayOutput(theMessage); + } +} + +//============================================================================== +/** + * Write the string into the list control. + * @param inString the string to display + */ +//============================================================================== +void CPreviewOutputDlg::DisplayOutput(CString inStr) +{ + const wchar_t *DELIMITERS = L"\r\t\n"; + + wchar_t theBuffer[512] = { 0 }; + ::wcscpy(theBuffer, inStr); + + wchar_t *theToken = ::wcstok(theBuffer, DELIMITERS); + while (theToken) { + m_ListCtrl.InsertItem(m_ListCtrl.GetItemCount(), theToken); + theToken = ::wcstok(nullptr, DELIMITERS); + } + + m_ListCtrl.EnsureVisible(m_ListCtrl.GetItemCount() - 1, FALSE); +} + +//============================================================================== +/** + * Spawn the process to execute the preview operation + * @param inStdOutput the handle to write the output to + * @param inCmd the command to execute + * @return true is spawned successfully, else false + */ +//============================================================================== +BOOL CPreviewOutputDlg::LaunchPreviewProcess(HANDLE inStdOutput, Q3DStudio::CString &inCmd) +{ + // Further usability hax, you love them. + DisplayOutput(L"Checking for .NET Framework install:"); + HKEY theHKey; + if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Microsoft\\NET Framework Setup\\NDP", 0, + KEY_QUERY_VALUE, &theHKey)) { + DisplayOutput(L" - OK: .NET Framework present."); + } else { + DisplayOutput(L" - WARNING: .NET Framework Missing?"); + } + + // Launch the process with the working directory set to the parent directory of current document + CUICFile theDocument = g_StudioApp.GetCore()->GetDoc()->GetDocumentPath(); + + Q3DStudio::CString theWorkingPath; + if (theDocument.Exists()) + theWorkingPath = theDocument.GetAbsolutePath(); + else + theWorkingPath = m_ExportedFile; + + CUICFile thePreviewerFile(CUICFile::GetApplicationDirectory(), theWorkingPath); + Q3DStudio::CFilePath theWorkingDirectory(thePreviewerFile.GetAbsolutePosixPath()); + + PROCESS_INFORMATION theProcessInfo; + STARTUPINFO theStartupInfo; + + // Set up the start up info struct. + ZeroMemory(&theStartupInfo, sizeof(STARTUPINFO)); + theStartupInfo.cb = sizeof(STARTUPINFO); + theStartupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + theStartupInfo.hStdOutput = inStdOutput; + theStartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE) /*hChildStdIn*/; + theStartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + theStartupInfo.wShowWindow = SW_HIDE; + + if (!CreateProcess(nullptr, const_cast(inCmd.c_str()), nullptr, nullptr, TRUE, 0, nullptr, + theWorkingDirectory.GetDirectory(), &theStartupInfo, &theProcessInfo)) + return FALSE; + + // Close any unnecessary handles. + CloseHandle(theProcessInfo.hThread); + m_PreviewProcessHandle = theProcessInfo.hProcess; + return TRUE; +} + +//============================================================================== +/** + * Spawn the thread to busy read the output and write to the list control + * @param inThreadParam the parameter used by this thread + * @return 1 + */ +//============================================================================== +DWORD WINAPI CPreviewOutputDlg::ReadOutputThread(LPVOID inThreadParam) +{ + char theBuffer[512]; + DWORD theBytesRead; + SThreadParam *theParam = (SThreadParam *)inThreadParam; + HANDLE thePipeRead = theParam->m_ReadHandle; + CPreviewOutputDlg *theDlg = (CPreviewOutputDlg *)(theParam->m_Context); + + while (TRUE) { + if (!ReadFile(thePipeRead, theBuffer, sizeof(theBuffer) - sizeof(char), &theBytesRead, nullptr) + || !theBytesRead) { + if (GetLastError() == ERROR_BROKEN_PIPE) { + theDlg->PreviewProcessTerminated(); + CloseHandle(thePipeRead); + theParam->m_ReadHandle = nullptr; + break; // pipe done - normal exit path. + } else + theDlg->DisplayOutput(::LoadResourceString( + IDS_CONFIG_PREVIEW_REDIRECT_ERROR)); // Something bad happened. + } else { + if (theBytesRead) { + theBuffer[theBytesRead] = '\0'; // Follow input with a nullptr. + theDlg->DisplayOutput(CString(theBuffer)); + } + } + } + return 1; +} diff --git a/src/Authoring/Studio/_Win/UI/PreviewOutputDlg.h b/src/Authoring/Studio/_Win/UI/PreviewOutputDlg.h new file mode 100644 index 00000000..19361d3d --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/PreviewOutputDlg.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** 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_PREVIEW_OUTPUT_DIALOG_H +#define INCLUDED_PREVIEW_OUTPUT_DIALOG_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include "resource.h" +#include "PreviewHelper.h" + +//============================================================================== +// Forwards +//============================================================================== +namespace Q3DStudio { +class CFilePath; +} + +class CPreviewOutputDlg : public CDialog +{ + DECLARE_DYNAMIC(CPreviewOutputDlg) + +protected: + struct SThreadParam + { + void *m_Context; + HANDLE m_ReadHandle; + }; + +public: + CPreviewOutputDlg(const Q3DStudio::CString &inCmd, const Q3DStudio::CString &inExportedFile, + CPreviewHelper::EExecMode inViewMode); + virtual ~CPreviewOutputDlg(); + + // Dialog Data + enum { IDD = IDD_DIALOG_PREVIEW_STATUS }; + CListCtrl m_ListCtrl; + +protected: + virtual void DoDataExchange(CDataExchange *pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual void OnCopyText(); + virtual void OnOK(); + DECLARE_MESSAGE_MAP() + +protected: + BOOL ExecutePreview(); + BOOL LaunchPreviewProcess(HANDLE inStdOutput, Q3DStudio::CString &inCmd); + static DWORD WINAPI ReadOutputThread(LPVOID lpvThreadParam); + void DisplayOutput(CString inStr); + void PreviewProcessTerminated(); + +protected: + Q3DStudio::CString m_Cmd; + Q3DStudio::CString m_ExportedFile; + SThreadParam m_OutputReadThreadParam; + HANDLE m_PreviewProcessHandle; + HANDLE m_ReadThreadHandle; + CPreviewHelper::EExecMode m_ViewMode; +}; + +#endif // INCLUDED_PREVIEW_OUTPUT_DIALOG_H diff --git a/src/Authoring/Studio/_Win/UI/RecentItems.cpp b/src/Authoring/Studio/_Win/UI/RecentItems.cpp new file mode 100644 index 00000000..b229ff29 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/RecentItems.cpp @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** 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 "RecentItems.h" +#include "Preferences.h" + +#include + +// using namespace Q3DStudio; <-- Do not do this here because it will conflict with CList and make +// the template generator go blah + +const Q3DStudio::CString CRecentItems::RECENTITEM_KEY = "RecentItem"; +const Q3DStudio::CString CRecentItems::RECENTIMPORT_KEY = "RecentImport"; +const Q3DStudio::CString CRecentItems::RECENTITEM_VALID = "RecentValid"; + +CRecentItems::CRecentItems(QMenu *inMenuID, long inCommandID, Q3DStudio::CString inPreferenceKey) +{ + Q_UNUSED(inCommandID) + + m_Menu = inMenuID; + m_ValidItems = 10; + m_PreferenceKey = inPreferenceKey; + + ReconstructList(); +} + +CRecentItems::~CRecentItems() +{ +} + +void CRecentItems::AddRecentItem(const CUICFile &inItem) +{ + RemoveRecentItem(inItem); + + m_RecentItems.insert(m_RecentItems.begin(), inItem); + + while (m_RecentItems.size() > 10) + m_RecentItems.pop_back(); + + RebuildList(); +} + +void CRecentItems::RemoveRecentItem(const CUICFile &inItem) +{ + TFileList::iterator thePos = m_RecentItems.begin(); + for (; thePos != m_RecentItems.end(); ++thePos) { + if ((*thePos) == inItem) { + m_RecentItems.erase(thePos); + break; + } + } + + RebuildList(); +} + +void CRecentItems::ReconstructList() +{ + ClearMenu(); + m_RecentItems.clear(); + + CPreferences thePrefs = CPreferences::GetUserPreferences(); + + m_ValidItems = thePrefs.GetLongValue(RECENTITEM_VALID, m_ValidItems); + + for (long theIndex = 0; theIndex < (m_ValidItems > 10 ? 10 : m_ValidItems); ++theIndex) { + Q3DStudio::CString theKey; + theKey.Format(_UIC("%ls%d"), static_cast(m_PreferenceKey), theIndex); + + Q3DStudio::CString theFilename = thePrefs.GetStringValue(theKey, ""); + if (theFilename != "") { + CUICFile theFile(theFilename); + + QAction *act = m_Menu->addAction(theFile.GetName().toQString(), + this, &CRecentItems::onTriggerRecent); + act->setData(static_cast(m_RecentItems.size())); + m_RecentItems.push_back(theFile); + } + } +} + +void CRecentItems::RebuildList() +{ + ClearMenu(); + + CPreferences thePrefs = CPreferences::GetUserPreferences(); + thePrefs.SetLongValue(RECENTITEM_VALID, GetItemCount()); + TFileList::iterator thePos = m_RecentItems.begin(); + for (long theIndex = 0; thePos != m_RecentItems.end(); ++thePos, ++theIndex) { + Q3DStudio::CString theFilename = (*thePos).GetName(); + + QAction *act = m_Menu->addAction(theFilename.toQString(), + this, &CRecentItems::onTriggerRecent); + act->setData(static_cast(theIndex)); + + Q3DStudio::CString theKey; + theKey.Format(_UIC("%ls%d"), static_cast(m_PreferenceKey), theIndex); + + thePrefs.SetStringValue(theKey, (*thePos).GetAbsolutePath()); + } +} + +void CRecentItems::ClearMenu() +{ + m_Menu->clear(); +} + +CUICFile CRecentItems::GetItem(long inIndex) +{ + return m_RecentItems.at(inIndex); +} + +void CRecentItems::onTriggerRecent() +{ + const int index = qobject_cast(sender())->data().toInt(); + Q_EMIT openRecent(index); +} + diff --git a/src/Authoring/Studio/_Win/UI/RecentItems.h b/src/Authoring/Studio/_Win/UI/RecentItems.h new file mode 100644 index 00000000..bc295079 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/RecentItems.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_RECENT_ITEMS_H +#define INCLUDED_RECENT_ITEMS_H 1 + +#pragma once + +#include + +#include "UICString.h" +#include "UICFile.h" + +#include + +class CUICFile; + +QT_BEGIN_NAMESPACE +class QMenu; +QT_END_NAMESPACE + +class CRecentItems : public QObject +{ + Q_OBJECT + + typedef std::vector TFileList; + +public: + static const Q3DStudio::CString RECENTITEM_KEY; + static const Q3DStudio::CString RECENTIMPORT_KEY; + static const Q3DStudio::CString RECENTITEM_VALID; + +Q_SIGNALS: + void openRecent(int index); +public: + CRecentItems(QMenu *inMenu, long inCommandID, + Q3DStudio::CString inPreferenceKey = RECENTITEM_KEY); + virtual ~CRecentItems(); + + void AddRecentItem(const CUICFile &inItem); + void RemoveRecentItem(const CUICFile &inItem); + + CUICFile GetItem(long inIndex); + long GetItemCount() const { return (long)m_RecentItems.size(); } + +protected: + void ClearMenu(); + void ReconstructList(); + void RebuildList(); + void SaveRecentList(); + + TFileList m_RecentItems; + + long m_CommandID; + long m_ValidItems; + QMenu *m_Menu; + Q3DStudio::CString m_PreferenceKey; + +private Q_SLOTS: + void onTriggerRecent(); +}; +#endif // INCLUDED_RECENT_ITEMS_H diff --git a/src/Authoring/Studio/_Win/UI/ReportDlg.cpp b/src/Authoring/Studio/_Win/UI/ReportDlg.cpp new file mode 100644 index 00000000..2563a4c1 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/ReportDlg.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// ReportDlg.cpp : implementation file +// + +#include "stdafx.h" +#include "Strings.h" + +#include "ReportDlg.h" +#include "CrashInfo.h" + +#include "CompConfig.h" + +#include "StudioInstance.h" +#include + +extern char g_DumpPath[MAX_PATH]; +///////////////////////////////////////////////////////////////////////////// +// CReportDlg dialog + +CReportDlg::CReportDlg(CWnd *pParent /*=nullptr*/) + : CDialog(CReportDlg::IDD, pParent) + , m_SysInfoText(_T("")) +{ + //{{AFX_DATA_INIT(CReportDlg) + m_Info = _T(""); + m_DescHeader = _T(""); + m_EmailAddress = _T(""); + m_EmailHeader = _T(""); + //}}AFX_DATA_INIT + + m_MediumFont2.CreatePointFont(88, CString(CStudioPreferences::GetFontFaceName())); + + m_Color_Background = CStudioPreferences::GetDarkBaseColor(); + m_Color_Text = CStudioPreferences::GetMasterColor(); + m_Color_Gray = CStudioPreferences::GetNormalColor(); + m_Color_Dark = CStudioPreferences::GetInactiveColor(); +} + +void CReportDlg::DoDataExchange(CDataExchange *pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CReportDlg) + DDX_Control(pDX, IDC_REPORTDLG_SYSINFO, m_SendSysInfo); + DDX_Control(pDX, IDC_REPORTDLG_DESC, m_Description); + DDX_Text(pDX, IDC_REPORTDLG_INFO, m_Info); + DDX_Text(pDX, IDC_REPORTDLG_DESCHEADER, m_DescHeader); + DDX_Text(pDX, IDC_REPORTDLG_EMAILADDR, m_EmailAddress); + DDX_Text(pDX, IDC_REPORTDLG_EMAILHEADER, m_EmailHeader); + //}}AFX_DATA_MAP + DDX_Text(pDX, IDC_CRASHDLG_SYSINFO_TEXT, m_SysInfoText); +} + +BEGIN_MESSAGE_MAP(CReportDlg, CDialog) +//{{AFX_MSG_MAP(CReportDlg) +ON_BN_CLICKED(IDSUBMIT, OnSubmit) +//}}AFX_MSG_MAP +ON_WM_CTLCOLOR() +ON_WM_ERASEBKGND() +// ON_STN_CLICKED(IDC_REPORTDLG__SYSINFO_TEXT, &CReportDlg::OnStnClickedReportdlg) +ON_STN_CLICKED(IDC_REPORTDLG__SYSINFO_TEXT, &CReportDlg::OnStnClickedReportdlg) +END_MESSAGE_MAP() + +//============================================================================== +/** + * Set the description of the crash. + * @param inErrorMessage the error message. + */ +//============================================================================== +void CReportDlg::SetErrorMessage(CString inErrorMessage) +{ + m_ErrorMessage = inErrorMessage; +} + +//============================================================================== +/** + * Set the stack trace for the crash. + * @param inStackTrace the stack trace. + */ +//============================================================================== +void CReportDlg::SetStackTrace(CString inStackTrace) +{ + m_StackTrace = inStackTrace; +} + +///////////////////////////////////////////////////////////////////////////// +// CReportDlg message handlers + +void CReportDlg::OnSubmit() +{ + CWaitCursor theWaitCursor; + + this->UpdateData(TRUE); + + // Actual reporting functionality missing + + this->EndDialog(TRUE); + exit(1); +} + +void CReportDlg::OnCancel() +{ + this->EndDialog(FALSE); +} + +BOOL CReportDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_Info = ::LoadResourceString(IDS_REPORTDLG_INFO).GetMulti(); + m_DescHeader = ::LoadResourceString(IDS_REPORTDLG_DESCHEADER).GetMulti(); + m_EmailHeader = ::LoadResourceString(IDS_REPORTDLG_EMAILHEADER).GetMulti(); + + CString theSysInfoText; + theSysInfoText = ""; //::LoadResourceString( IDS_REPORTDLG_SYSINFOHEADER ).GetMulti( ); + // this is done this way, as i had problem changing the color of the text of the checkbox. + // it is now a seperate checkbox and a static text + // Made a workaround where the static text has notify flag on and would toggle the checkbox + // control on and off + // when clicked + m_SysInfoText = ::LoadResourceString(IDS_REPORTDLG_SYSINFOHEADER).GetMulti(); + + m_SendSysInfo.SetWindowText(theSysInfoText); + m_SendSysInfo.SetFont(&m_MediumFont2); + m_SendSysInfo.SetCheck(BST_CHECKED); + + m_Brush.CreateSolidBrush(m_Color_Background); + GetDlgItem(IDC_REPORTDLG_INFO)->SetFont(&m_MediumFont2); + GetDlgItem(IDC_REPORTDLG_DESCHEADER)->SetFont(&m_MediumFont2); + GetDlgItem(IDC_REPORTDLG_EMAILADDR)->SetFont(&m_MediumFont2); + GetDlgItem(IDC_REPORTDLG_EMAILHEADER)->SetFont(&m_MediumFont2); + GetDlgItem(IDC_REPORTDLG__SYSINFO_TEXT)->SetFont(&m_MediumFont2); + + this->UpdateData(FALSE); + + return TRUE; +} + +HBRUSH CReportDlg::OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor) +{ + Q_UNUSED(nCtlColor); + + int theCtrlID = pWnd->GetDlgCtrlID(); + if (theCtrlID == IDSUBMIT || theCtrlID == IDCANCEL || theCtrlID == IDC_REPORTDLG_SEPERATOR + || theCtrlID == IDC_REPORTDLG_SYSINFO || theCtrlID == IDC_REPORTDLG__SYSINFO_TEXT + || theCtrlID == IDC_REPORTDLG_INFO || theCtrlID == IDC_REPORTDLG_DESCHEADER + || theCtrlID == IDC_REPORTDLG_EMAILHEADER) { + pDC->SetBkMode(TRANSPARENT); // for area just behind the text + pDC->SetTextColor(m_Color_Gray); + } else if (theCtrlID == IDC_REPORTDLG_DESC || theCtrlID == IDC_REPORTDLG_EMAILADDR) { + pDC->SetBkColor(m_Color_Background); + pDC->SetBkMode(OPAQUE); // for area just behind the text + pDC->SetTextColor(m_Color_Text); + } + + return m_Brush; +} + +BOOL CReportDlg::OnEraseBkgnd(CDC *pDC) +{ + CRect theClientRect; + GetClientRect(&theClientRect); + pDC->FillSolidRect(theClientRect, m_Color_Background); + + return TRUE; +} + +void CReportDlg::OnStnClickedReportdlg() +{ + m_SendSysInfo.SetCheck(!m_SendSysInfo.GetCheck()); +} diff --git a/src/Authoring/Studio/_Win/UI/ReportDlg.h b/src/Authoring/Studio/_Win/UI/ReportDlg.h new file mode 100644 index 00000000..c54743da --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/ReportDlg.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#if !defined(AFX_REPORTDLG_H__B8564DEF_2599_4419_9E15_4AF38BE7066C__INCLUDED_) +#define AFX_REPORTDLG_H__B8564DEF_2599_4419_9E15_4AF38BE7066C__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// ReportDlg.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CReportDlg dialog + +class CReportDlg : public CDialog +{ + // Construction +public: + CReportDlg(CWnd *pParent = nullptr); // standard constructor + + COLORREF m_Color_Background; + COLORREF m_Color_Text; + COLORREF m_Color_Gray; + COLORREF m_Color_Dark; + CBrush m_Brush; + CFont m_MediumFont2; + + // Dialog Data + //{{AFX_DATA(CReportDlg) + enum { IDD = IDD_REPORTDLG }; + CButton m_SendSysInfo; + CEdit m_Description; + CString m_Info; + CString m_DescHeader; + CString m_EmailAddress; + CString m_EmailHeader; + //}}AFX_DATA + + void SetErrorMessage(CString inErrorMessage); + void SetStackTrace(CString inStackTrace); + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CReportDlg) +protected: + virtual void DoDataExchange(CDataExchange *pDX); // DDX/DDV support + //}}AFX_VIRTUAL + + // Implementation +protected: + // Generated message map functions + //{{AFX_MSG(CReportDlg) + afx_msg void OnSubmit(); + virtual void OnCancel(); + virtual BOOL OnInitDialog(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + + CString m_ErrorMessage; + CString m_StackTrace; + +public: + afx_msg HBRUSH OnCtlColor(CDC *pDC, CWnd *pWnd, UINT nCtlColor); + afx_msg BOOL OnEraseBkgnd(CDC *pDC); + CString m_SysInfoText; + // afx_msg void OnStnClickedReportdlg(); + afx_msg void OnStnClickedReportdlg(); +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_REPORTDLG_H__B8564DEF_2599_4419_9E15_4AF38BE7066C__INCLUDED_) diff --git a/src/Authoring/Studio/_Win/UI/ResetKeyframeValuesDlg.cpp b/src/Authoring/Studio/_Win/UI/ResetKeyframeValuesDlg.cpp new file mode 100644 index 00000000..2eaa293a --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/ResetKeyframeValuesDlg.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "ResetKeyframeValuesDlg.h" +#include ".\resetkeyframevaluesdlg.h" + +IMPLEMENT_DYNAMIC(CResetKeyframeValuesDlg, CDialog) +CResetKeyframeValuesDlg::CResetKeyframeValuesDlg(CWnd *pParent /*=nullptr*/) + : CDialog(CResetKeyframeValuesDlg::IDD, pParent) +{ +} + +CResetKeyframeValuesDlg::~CResetKeyframeValuesDlg() +{ +} + +void CResetKeyframeValuesDlg::DoDataExchange(CDataExchange *pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_RESETKEYFRAMEVALUES_DLG_ICON, m_WarningIcon); + DDX_Control(pDX, IDCANCEL, m_CancelButton); +} + +BEGIN_MESSAGE_MAP(CResetKeyframeValuesDlg, CDialog) +END_MESSAGE_MAP() + +BOOL CResetKeyframeValuesDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_WarningIcon.SetIcon(::AfxGetApp()->LoadStandardIcon(IDI_WARNING)); + m_CancelButton.SetButtonStyle(BS_DEFPUSHBUTTON); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} diff --git a/src/Authoring/Studio/_Win/UI/ResetKeyframeValuesDlg.h b/src/Authoring/Studio/_Win/UI/ResetKeyframeValuesDlg.h new file mode 100644 index 00000000..d0a883d1 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/ResetKeyframeValuesDlg.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 +//============================================================================== +#pragma once +#include "Resource.h" +#include "afxwin.h" + +class CResetKeyframeValuesDlg : public CDialog +{ + DECLARE_DYNAMIC(CResetKeyframeValuesDlg) + +public: + CResetKeyframeValuesDlg(CWnd *pParent = nullptr); // standard constructor + virtual ~CResetKeyframeValuesDlg(); + + // Dialog Data + enum { IDD = IDD_RESETKEYFRAMEVALUES_DLG }; + +protected: + virtual void DoDataExchange(CDataExchange *pDX); // DDX/DDV support + + DECLARE_MESSAGE_MAP() + CStatic m_WarningIcon; + +public: + virtual BOOL OnInitDialog(); + CButton m_CancelButton; +}; diff --git a/src/Authoring/Studio/_Win/UI/SceneView.cpp b/src/Authoring/Studio/_Win/UI/SceneView.cpp new file mode 100644 index 00000000..6fcbc6d0 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/SceneView.cpp @@ -0,0 +1,861 @@ +/**************************************************************************** +** +** 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" +#ifdef _WIN32 +#pragma warning(disable : 4100) // unreferenced formal parameter +#endif +//============================================================================== +// Includes +//============================================================================== +#include "UICOptions.h" +#include "SceneView.h" +//#include "InterpolationDlg.h" +#include "MainFrm.h" +#include "StudioProjectSettings.h" +#include "StudioInstance.h" +#include "StudioPreferences.h" +#include "HotKeys.h" +#include "StudioApp.h" +#include "Doc.h" +#include "Dispatch.h" +#include "MouseCursor.h" +#include "ResourceCache.h" +#ifdef KDAB_TEMPORARILY_REMOVED +#include "WndControl.h" +#endif +#include "Core.h" +#include "UICDMStudioSystem.h" +#include "IStudioRenderer.h" +#include "ClientDataModelBridge.h" + +#include +#include +#include + +//============================================================================== +/** + * Constructor: Initializes the object. + */ +//============================================================================== + +CSceneView::CSceneView(CStudioApp *inStudioApp, QWidget *parent) + : QWidget(parent) +{ + Q_UNUSED(inStudioApp) + m_PreviousToolMode = g_StudioApp.GetToolMode(); + m_PreviousSelectMode = g_StudioApp.GetSelectMode(); + + m_PlayerContainerWnd = new CPlayerContainerWnd(this); + connect(m_PlayerContainerWnd, &CPlayerContainerWnd::toolChanged, this, &CSceneView::toolChanged); +#ifdef KDAB_TEMPORARILY_REMOVED + // Create the player container window + CPt theSize = CStudioPreferences::GetDefaultClientSize(); + + // Note that creating with WS_CLIPCHILDREN prevents flickering when SceneView is being + // resized. + m_PlayerContainerWnd->CreateEx(0, AfxRegisterWndClass(0, LoadCursor(NULL, IDC_ARROW), + (HBRUSH)GetStockObject(BLACK_BRUSH)), + L"player_container_wnd", + WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, + CRect(0, 0, theSize.x, theSize.y), this, 1000); +#endif + + m_PlayerWnd = new CPlayerWnd(m_PlayerContainerWnd); + connect(m_PlayerWnd, &CPlayerWnd::dropReceived, this, &CSceneView::onDropReceived); +#ifdef KDAB_TEMPORARILY_REMOVED + + // Create the player frame child window + m_PlayerWnd.Create(AfxRegisterWndClass(0, LoadCursor(NULL, IDC_ARROW), + (HBRUSH)GetStockObject(WHITE_BRUSH)), + L"player_wnd", WS_CHILD | WS_VISIBLE, CRect(0, 0, theSize.x, theSize.y), + m_PlayerContainerWnd, 1001); +#endif + m_PlayerContainerWnd->SetPlayerWnd(m_PlayerWnd); + + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); +} + +CSceneView::CSceneView() +{ + m_PreviousToolMode = g_StudioApp.GetToolMode(); + m_PreviousSelectMode = g_StudioApp.GetSelectMode(); +} + +void CSceneView::onDropReceived() +{ + setFocus(); +} + +//============================================================================== +/** + * Destructor: Releases the object. + */ +CSceneView::~CSceneView() +{ + CDispatch *theDispatch = g_StudioApp.GetCore()->GetDispatch(); + // Stop listening for selection change events + theDispatch->RemoveSelectedNodePropChangeListener(this); + theDispatch->RemoveClientPlayChangeListener(this); +#ifdef INCLUDE_EDIT_CAMERA + theDispatch->RemoveEditCameraChangeListener(this); +#endif +} + +QSize CSceneView::sizeHint() const +{ + CPt theSize = CStudioPreferences::GetDefaultClientSize(); + return QSize(theSize.x, theSize.y); +} + +//====================================================m========================== +/** + * Called by the framework after the view is first attached + * to the document, but before the view is initially displayed. + * Notifies the Main Frame that the palettes need to be shown, and destroys the + * splash screen. + */ +void CSceneView::showEvent(QShowEvent *event) +{ + QWidget::showEvent(event); + +#ifdef KDAB_TEMPORARILY_REMOVED + + // Modify the style for WS_CLIPCHILDREN + ModifyStyle(0, WS_CLIPCHILDREN); +#endif + + m_PlayerContainerWnd->RecenterClient(); + + // Set the scroll information. + m_PlayerContainerWnd->SetScrollRanges(); + + // Create the cursors + m_ArrowCursor = CResourceCache::GetInstance()->GetCursor(CMouseCursor::CURSOR_ARROW); + m_CursorGroupMove = CResourceCache::GetInstance()->GetCursor(CMouseCursor::CURSOR_GROUP_MOVE); + m_CursorGroupRotate = + CResourceCache::GetInstance()->GetCursor(CMouseCursor::CURSOR_GROUP_ROTATE); + m_CursorGroupScale = CResourceCache::GetInstance()->GetCursor(CMouseCursor::CURSOR_GROUP_SCALE); + m_CursorItemMove = CResourceCache::GetInstance()->GetCursor(CMouseCursor::CURSOR_ITEM_MOVE); + m_CursorItemRotate = CResourceCache::GetInstance()->GetCursor(CMouseCursor::CURSOR_ITEM_ROTATE); + m_CursorItemScale = CResourceCache::GetInstance()->GetCursor(CMouseCursor::CURSOR_ITEM_SCALE); + m_CursorEditCameraPan = + CResourceCache::GetInstance()->GetCursor(CMouseCursor::CURSOR_EDIT_CAMERA_PAN); + m_CursorEditCameraRotate = + CResourceCache::GetInstance()->GetCursor(CMouseCursor::CURSOR_EDIT_CAMERA_ROTATE); + m_CursorEditCameraZoom = + CResourceCache::GetInstance()->GetCursor(CMouseCursor::CURSOR_EDIT_CAMERA_ZOOM); + +#ifdef INCLUDE_EDIT_CAMERA + g_StudioApp.GetCore()->GetDispatch()->AddEditCameraChangeListener(this); +#endif + + // Set the default cursor + OnSetCursor(); +} + +void CSceneView::keyPressEvent(QKeyEvent *event) +{ + /*switch (event->key()) + { + case Qt::Key_Control: + case Qt::Key_Alt: + case Qt::Key_Shift: + case Qt::Key_Meta: + HandleModifierDown(event->key(), event->isAutoRepeat() ? 2 : 1, event->modifiers()); + break; + default: + break; + }*/ +} + +//============================================================================== +/** + * OnToolGroupSelection: Called when the Group Selection button is pressed. + * Sets the current tool mode and changes the cursor. + */ +void CSceneView::OnToolGroupSelection() +{ + m_PreviousSelectMode = g_StudioApp.GetSelectMode(); + g_StudioApp.SetSelectMode(STUDIO_SELECTMODE_GROUP); + OnSetCursor(); + Q_EMIT toolChanged(); +} + +//============================================================================== +/** + * OnToolItemSelection: Called when the Item Selection button is pressed. + * Sets the current tool mode and changes the cursor. + */ +void CSceneView::OnToolItemSelection() +{ + m_PreviousSelectMode = g_StudioApp.GetSelectMode(); + g_StudioApp.SetSelectMode(STUDIO_SELECTMODE_ENTITY); + OnSetCursor(); + Q_EMIT toolChanged(); +} + + +//============================================================================== +/** + * SetViewCursor: Sets the cursor for the view according to the current Client Tool. + * + * Changes the cursor depending on the current tool mode. Each time the Tool mode + * changes, you should call this function. If you add extra tool modes, you + * will need to adjust this function. + */ +void CSceneView::SetViewCursor() +{ + long theCurrentToolSettings = g_StudioApp.GetToolMode(); + long theCurrentSelectSettings = g_StudioApp.GetSelectMode(); + + // See what tool mode we are in + switch (theCurrentToolSettings) { + case STUDIO_TOOLMODE_MOVE: + switch (theCurrentSelectSettings) { + case STUDIO_SELECTMODE_ENTITY: + m_PlayerWnd->setCursor(m_CursorItemMove); + break; + case STUDIO_SELECTMODE_GROUP: + m_PlayerWnd->setCursor(m_CursorGroupMove); + break; + // Default - shouldn't happen + default: + m_PlayerWnd->setCursor(m_CursorItemMove); + break; + } + break; + + case STUDIO_TOOLMODE_ROTATE: + switch (theCurrentSelectSettings) { + case STUDIO_SELECTMODE_ENTITY: + m_PlayerWnd->setCursor(m_CursorItemRotate); + break; + case STUDIO_SELECTMODE_GROUP: + m_PlayerWnd->setCursor(m_CursorGroupRotate); + break; + // Default - shouldn't happen + default: + m_PlayerWnd->setCursor(m_CursorItemRotate); + break; + } + break; + + case STUDIO_TOOLMODE_SCALE: + switch (theCurrentSelectSettings) { + case STUDIO_SELECTMODE_ENTITY: + m_PlayerWnd->setCursor(m_CursorItemScale); + break; + case STUDIO_SELECTMODE_GROUP: + m_PlayerWnd->setCursor(m_CursorGroupScale); + break; + // Default - shouldn't happen + default: + m_PlayerWnd->setCursor(m_CursorItemScale); + break; + } + break; + +#ifdef INCLUDE_EDIT_CAMERA + case STUDIO_TOOLMODE_CAMERA_PAN: + m_PlayerWnd->setCursor(m_CursorEditCameraPan); + break; + + case STUDIO_TOOLMODE_CAMERA_ZOOM: + m_PlayerWnd->setCursor(m_CursorEditCameraZoom); + break; + + case STUDIO_TOOLMODE_CAMERA_ROTATE: + m_PlayerWnd->setCursor(m_CursorEditCameraRotate); + break; +#endif + // Default - shouldn't happen + default: + m_PlayerWnd->setCursor(m_CursorItemMove); + break; + } +} + +//============================================================================== +/** + * RecalcMatte: Recalculates the matte around the Client based on the settings. + * + * This will recalculate the matting around the Client based on the Client's + * current size. If the Client is a "Fit To Window" mode, then the matte region + * is cleared. + */ +//============================================================================== +void CSceneView::RecalcMatte() +{ + long theXOffset = 0; + long theYOffset = 0; + QRect theClientRect = rect(); + + // Adjust the client area based if rulers are visible + if (m_PlayerContainerWnd) { + m_PlayerContainerWnd->setGeometry(theXOffset, theYOffset, + theClientRect.width() - theXOffset, + theClientRect.height() - theYOffset); + + // Recenter the Client rect + m_PlayerContainerWnd->RecenterClient(); + } +} + +//============================================================================== +/** + * PtInClientRect: Returns true if the point lies in the client rect, false otherwise. + * + * @param inPoint The point to check. + */ +//============================================================================== +bool CSceneView::PtInClientRect(const QPoint& inPoint) +{ + return m_PlayerContainerWnd && m_PlayerContainerWnd->geometry().contains(inPoint); +} + +//============================================================================== +/** + * HandleModifierDown: Called when a modifier key (ctrl or alt) is pressed and held. + * + * Changes tool modes and saves the previous mode. + * + * @param inChar Contains the character code value of the key. + * @param inRepCnt Contains the repeat count, the number of times the keystroke + *is repeated when user holds down the key. + * @param inFlags Contains the scan code, key-transition code, previous + *key state, and context code. + */ +//============================================================================== +bool CSceneView::HandleModifierDown(int inChar, int inRepCnt, Qt::KeyboardModifiers modifiers) +{ + bool theHandledFlag = false; + + UNREFERENCED_PARAMETER(inRepCnt); + + // Get the position of the mouse and the rectangle containing the scene view + QPoint theCursorPosition = mapFromGlobal(QCursor::pos()); + QRect theWindowRect = rect(); + + // If we are currently dragging an object or the cursor is over the scene + if (((theWindowRect.contains(theCursorPosition)) + || (m_PlayerContainerWnd && m_PlayerContainerWnd->IsMouseDown()))) { + bool theCtrlKeyIsDown = modifiers & Qt::ControlModifier; + bool theAltKeyIsDown = modifiers & Qt::AltModifier; + + // If the control key is being pressed and the Alt key is not down + if ((inChar == Qt::Key_Control) && (!theAltKeyIsDown)) { + // If this is the first press, toggle tool modes + m_RegisteredKeyDown = true; + +#ifdef INCLUDE_EDIT_CAMERA + if (m_PlayerContainerWnd->IsMiddleMouseDown() && !IsDeploymentView()) { + // Do nothing, do not let it switch to other tool when middle mouse is down + } else +#endif + { + // See what tool mode we are in and change modes accordingly + SetToolOnCtrl(); + theHandledFlag = true; + } + } + // If the alt key is being pressed and the control key is not down + else if ((inChar == Qt::Key_Alt) && (!theCtrlKeyIsDown)) { + m_RegisteredKeyDown = true; + +#ifdef INCLUDE_EDIT_CAMERA + if (m_PlayerContainerWnd->IsMiddleMouseDown() && !IsDeploymentView()) { + // press Alt-Scroll Wheel Click + // Do Camera Rotate if we are in 3D Camera + if (g_StudioApp.GetRenderer().DoesEditCameraSupportRotation( + g_StudioApp.GetRenderer().GetEditCamera())) { + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_ROTATE); + theHandledFlag = true; + } + } else +#endif + { + // See what tool mode we are in and change modes accordingly + SetToolOnAlt(); + theHandledFlag = true; + } + } + OnSetCursor(); + Q_EMIT toolChanged(); + } + + return theHandledFlag; +} + +//============================================================================== +/** + * HandleModifierUp: Handles the release of a modifier key (ctrl or alt). + * + * Changes tool modes back to the original tool mode. + * + * @param inChar Contains the character code value of the key. + * @param inRepCnt Contains the repeat count, the number of times the keystroke is + *repeated when user holds down the key. + * @param inFlags Contains the scan code, key-transition code, previous key + *state, and context code. + */ +//============================================================================== +bool CSceneView::HandleModifierUp(int inChar, int inRepCnt, Qt::KeyboardModifiers modifiers) +{ + UNREFERENCED_PARAMETER(inRepCnt); + + bool theHandledFlag = false; + + // Get the position of the mouse and the rectangle containing the scene view + QPoint theCursorPosition = mapFromGlobal(QCursor::pos()); + QRect theWindowRect = rect(); + + // If we are currently dragging an object or the cursor is over the scene + if (((theWindowRect.contains(theCursorPosition)) + || (m_PlayerContainerWnd && m_PlayerContainerWnd->IsMouseDown()))) { + bool theCtrlKeyIsDown = modifiers & Qt::ControlModifier; + bool theAltKeyIsDown = modifiers & Qt::AltModifier; + + // If the control key or alt key is released (and the opposite key is not down) revert back + // to the original tool mode + if (((inChar == Qt::Key_Control) && (!theAltKeyIsDown)) + || ((inChar == Qt::Key_Alt) && (!theCtrlKeyIsDown))) { +#ifdef INCLUDE_EDIT_CAMERA + if (m_PlayerContainerWnd->IsMiddleMouseDown()) + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_PAN); + else +#endif + { + RestorePreviousTool(); + } + + OnSetCursor(); + Q_EMIT toolChanged(); + + theHandledFlag = true; + } + // m_RegisteredKeyDown = false; + } + + return theHandledFlag; +} + +//============================================================================== +/** + * resizeEvent: Handles the WM_SIZE message + * + * Recenters the Client and recaluclates the matte when a resize message is + * generated. + * + * @param nType Specifies the type of resizing requested. + * @param cx Specifies the new width of the client area. + * @param cy Specifies the new height of the client area. + */ +//============================================================================== +void CSceneView::resizeEvent(QResizeEvent* event) +{ + QWidget::resizeEvent(event); + if (m_PlayerContainerWnd) { + RecalcMatte(); + SetPlayerWndPosition(); + g_StudioApp.GetCore()->GetDoc( )->GetSceneGraph()->RequestRender(); + } +} + +//============================================================================== +/** + * SetPlayerWndPosition: Sets the position of the child player window + * + * Called when the view is scrolled to position the child player window + * + */ +//============================================================================== +void CSceneView::SetPlayerWndPosition() +{ + // Move the child player window to coincide with the scrollbars + if (m_PlayerContainerWnd) { + long theLeft, theTop; + // Retrieve the left and top edge of the presentation currently in view + m_PlayerContainerWnd->SetPlayerWndPosition(theLeft, theTop); + + m_PlayerContainerWnd->update(); + } +} + +//============================================================================== +/** + * GetPlayerHwnd: Gets the window handle for the player object. + * + * @return Window handle for the player window + */ +//============================================================================== + +#ifdef KDAB_TEMPORARILY_REMOVED + +HWND CSceneView::GetPlayerHwnd() +{ + HWND thePlayerWnd; + + thePlayerWnd = this->GetSafeHwnd(); + + if (IsWindow(m_PlayerWnd.GetSafeHwnd())) + thePlayerWnd = m_PlayerWnd.GetSafeHwnd(); + + return thePlayerWnd; +} +#endif +//============================================================================== +/** + * SetRegisteredKey: Sets the staus to true or false + * + * If we've already processesed an alt or tab, then set the flag + */ +//============================================================================== +void CSceneView::SetRegisteredKey(bool inStatus) +{ + m_RegisteredKeyDown = inStatus; +} + +//============================================================================== +/** + * GetKeyStatus: get the staus + * + * check to see if the flag is true or false + */ +//============================================================================== +bool CSceneView::GetKeyStatus() +{ + return m_RegisteredKeyDown; +} + +//============================================================================= +/** + * 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 CSceneView::RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler) +{ + inShortcutHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CSceneView::OnToolGroupSelection), 0, Qt::Key_A); + inShortcutHandler->RegisterKeyEvent( + new CDynHotKeyConsumer(this, &CSceneView::OnToolItemSelection), 0, Qt::Key_V); + inShortcutHandler->RegisterKeyDownEvent( + new CDynHotKeyConsumer(this, &CSceneView::HandleModifierDown), + Qt::ControlModifier, Qt::Key_Control); + inShortcutHandler->RegisterKeyDownEvent( + new CDynHotKeyConsumer(this, &CSceneView::HandleModifierDown), + Qt::AltModifier, Qt::Key_Alt); + inShortcutHandler->RegisterKeyUpEvent( + new CDynHotKeyConsumer(this, &CSceneView::HandleModifierUp), 0, + Qt::Key_Control); + inShortcutHandler->RegisterKeyUpEvent( + new CDynHotKeyConsumer(this, &CSceneView::HandleModifierUp), 0, + Qt::Key_Alt); +} + +//============================================================================== +/** + * OnSetCursor: Handles the WM_SETCURSOR Windows message. + * + * Changes the cursor depending on the current tool mode. + * + * @param inWnd Specifies a pointer to the window that contains the cursor. + * @param inHitTest Specifies the hit-test area code. The hit test determines the cursor�s + *location. + * @param inMessage Specifies the mouse message number. + * + * @return true if the cursor was set + */ +void CSceneView::OnSetCursor() +{ + SetViewCursor(); +} + +//============================================================================== +/** + * Called when the tool mode changes, scene view maintains its own mode so it can + * return to that mode when modifiers are pressed + * @param inMode the mode to which to change + */ +void CSceneView::SetToolMode(long inMode) +{ + m_PreviousToolMode = inMode; + SetViewCursor(); +} + +//============================================================================== +/** + * Resets its scroll ranges and recenters client in the window. This is called when + * an outside source needs to tell the scene view that size ranges have changed such + * as the preferences telling the sceneview that the size changed. + */ +void CSceneView::RecheckSizingMode() +{ + if (m_PlayerContainerWnd) { + m_PlayerContainerWnd->SetScrollRanges(); + } +} + +//============================================================================= +/** + * Called a selected node property has changed. + * @param inPropertyName name of the property changed + */ +void CSceneView::OnPropValueChanged(const Q3DStudio::CString &inPropertyName) +{ +} + +//============================================================================= +/** + * Called a selected node property has its property changed via a mouse drag + * @param inConstrainXAxis true if dragging is constrained along the X-Axis + * @param inConstrainYAxis true if dragging is constrained along the Y-Axis + */ +void CSceneView::OnMouseDragged(bool inConstrainXAxis, bool inConstrainYAxis) +{ + // If not constraining to Y-Axis, snap horizontally + // If not constraining to X-Axis, snap vertically + // true to update tranform, as this is called from a mouse drag and the global transform may be + // outdated. + // false to not update the scene, since this is a result of a mouse drag which is already doing + // the updating +} + +//========================================================================== +/** + * Called when the presentation time changes. + * When animating an object, the markers must be updated with the selected object + */ +void CSceneView::OnTimeChanged(long inTime) +{ + UNREFERENCED_PARAMETER(inTime); +} + +//============================================================================== +/** + * Restore to the previous tool mode. This is called when the modifier is released + */ +//============================================================================== +void CSceneView::RestorePreviousTool() +{ + // What was the original tool mode? + switch (m_PreviousToolMode) { + case STUDIO_TOOLMODE_MOVE: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_MOVE); + break; + + case STUDIO_TOOLMODE_ROTATE: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_ROTATE); + break; + + case STUDIO_TOOLMODE_SCALE: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_SCALE); + break; + +#ifdef INCLUDE_EDIT_CAMERA + case STUDIO_TOOLMODE_CAMERA_PAN: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_PAN); + break; + + case STUDIO_TOOLMODE_CAMERA_ROTATE: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_ROTATE); + break; + + case STUDIO_TOOLMODE_CAMERA_ZOOM: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_ZOOM); + break; +#endif + } +} + +//============================================================================== +/** + * Change the tool when the Ctrl Key is pressed + */ +//============================================================================== +void CSceneView::SetToolOnCtrl() +{ + switch (m_PreviousToolMode) { + // If we are in move mode, switch to rotate + case STUDIO_TOOLMODE_MOVE: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_ROTATE); + break; + + // If we are in rotate mode, switch to move + case STUDIO_TOOLMODE_ROTATE: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_MOVE); + break; + + // If we are in scale mode, switch to move + case STUDIO_TOOLMODE_SCALE: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_MOVE); + break; + +#ifdef INCLUDE_EDIT_CAMERA + // If we are in camera pan mode, switch to camera orbit + case STUDIO_TOOLMODE_CAMERA_PAN: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_ROTATE); + break; + + // If we are in camera orbit mode, switch to camera pan + case STUDIO_TOOLMODE_CAMERA_ROTATE: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_PAN); + break; + + // If we are in camera zoom mode, switch to camera pan + case STUDIO_TOOLMODE_CAMERA_ZOOM: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_PAN); + break; +#endif + } +} + +//============================================================================== +/** + * Change the tool when the Alt Key is pressed + */ +//============================================================================== +void CSceneView::SetToolOnAlt() +{ + switch (m_PreviousToolMode) { + // If we are in move mode, switch to rotate + case STUDIO_TOOLMODE_MOVE: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_SCALE); + break; + + // If we are in rotate mode, switch to move + case STUDIO_TOOLMODE_ROTATE: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_SCALE); + break; + + // If we are in scale mode, switch to move + case STUDIO_TOOLMODE_SCALE: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_ROTATE); + break; + +#ifdef INCLUDE_EDIT_CAMERA + // If we are in camera pan mode, switch to camera zoom + case STUDIO_TOOLMODE_CAMERA_PAN: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_ZOOM); + break; + + // If we are in camera orbit mode, switch to camera zoom + case STUDIO_TOOLMODE_CAMERA_ROTATE: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_ZOOM); + break; + + // If we are in camera zoom mode, switch to camera orbit + case STUDIO_TOOLMODE_CAMERA_ZOOM: + g_StudioApp.SetToolMode(STUDIO_TOOLMODE_CAMERA_ROTATE); + break; +#endif + } +} + +//============================================================================== +/** + * Redirect to PlayerContainerWnd to check whether we are in deployment view mode. + * @return true if is in deployment view mode, else false + */ +bool CSceneView::IsDeploymentView() +{ + // default mode is SCENE_VIEW so if playercontainerwnd does not exist ( should only happen on + // startup ), + // it is deployment view + bool theStatus = true; + if (m_PlayerContainerWnd) + theStatus = m_PlayerContainerWnd->IsDeploymentView(); + + return theStatus; +} + +//============================================================================== +/** + * Redirect to PlayerContainerWnd to set the view mode of the current scene view, + * whether we are in editing mode or deployment mode. For editing mode, we want to + * use the full scene area without any matte area. + * @param inViewMode the view mode of this scene + */ +void CSceneView::SetViewMode(CPlayerContainerWnd::EViewMode inViewMode) +{ + if (m_PlayerContainerWnd) { + m_PlayerContainerWnd->SetViewMode(inViewMode); + } +} + +//============================================================================== +/** + * When the active camera is changed, the display string needs to be changed. Hence + * find which entry is the one which is modified and update with the new string + * @param inCamera the camera that has been modified + */ +void CSceneView::OnEditCameraChanged() +{ + // reset any scrolling and recalculate the window position. + if (m_PlayerContainerWnd) { + m_PlayerContainerWnd->SetScrollRanges(); + RecalcMatte(); + SetPlayerWndPosition(); + } + + // update the view mode accordingly + SetViewMode(g_StudioApp.GetRenderer().GetEditCamera() >= 0 ? CPlayerContainerWnd::VIEW_EDIT + : CPlayerContainerWnd::VIEW_SCENE); + // redraw the scene so that markers can be calculated correctly + // g_StudioApp.GetCore()->GetDoc( )->UpdateClientScene( false ); + m_PlayerWnd->update(); +} + +//============================================================================== +/** + * When the active camera is changed, the display string needs to be changed. Hence + * find which entry is the one which is modified and update with the new string + * @param inCamera the camera that has been modified + */ +void CSceneView::OnEditCamerasTransformed() +{ +} + +void CSceneView::OnAuthorZoomChanged() +{ + OnEditCameraChanged(); +} + +void CSceneView::OnRulerGuideToggled() +{ + m_PlayerContainerWnd->OnRulerGuideToggled(); +} diff --git a/src/Authoring/Studio/_Win/UI/SceneView.h b/src/Authoring/Studio/_Win/UI/SceneView.h new file mode 100644 index 00000000..12a58c6a --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/SceneView.h @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** 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_SCENE_VIEW_H +#define INCLUDED_SCENE_VIEW_H 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +#include +#include + +#include "EditorPane.h" +#include "PlayerWnd.h" +#include "PlayerContainerWnd.h" +#include "DispatchListeners.h" + +class CStudioApp; +class CHotKeys; +class CMouseCursor; +class CWndControl; + +//============================================================================== +// Forwards +//============================================================================== + +//============================================================================== +// Class CSceneView +//============================================================================== + +//============================================================================== +/** + * CSceneView: Scene View. + * + * Provides the view of the scene and displays the 3D Client window. + */ +//============================================================================== +class CSceneView : public QWidget, + public CEditorPane, + public CSelectedNodePropChangeListener, + public CClientPlayChangeListener, + public CEditCameraChangeListener +{ + Q_OBJECT + //========================================================================== + // Protected Properties + //========================================================================== +protected: + bool m_FitClientToWindow = false; ///< True if user selected fit to window in prefrences + bool m_RegisteredKeyDown = false; ///< True if a key is down + CPlayerContainerWnd *m_PlayerContainerWnd = nullptr; ///< first-level child + CPlayerWnd *m_PlayerWnd = nullptr; ///< second-level child (grandchild) + QCursor m_ArrowCursor; ///< A pointer to the current cursor (changes according to mode) + QCursor m_CursorGroupMove; ///< The move group cursor + QCursor m_CursorGroupRotate; ///< The rotate group cursor + QCursor m_CursorGroupScale; ///< The scale group cursor + QCursor m_CursorItemMove; ///< The move item cursor + QCursor m_CursorItemRotate; ///< The rotate item cursor + QCursor m_CursorItemScale; ///< The scale item cursor + QCursor m_CursorEditCameraPan; ///< The edit camera pan cursor + QCursor m_CursorEditCameraRotate; ///< The edit camera rotate cursor + QCursor m_CursorEditCameraZoom; ///< The edit camera zoom cursor + + long m_PreviousToolMode; ///< The previous tool mode (used when toggling with hotkeys to switch + ///back to previous mode on release) + long m_PreviousSelectMode; ///< The previous select mode + + //========================================================================== + // Protected Methods + //========================================================================== +protected: // create from serialization only + + //========================================================================== + // Public Methods + //========================================================================== +public: + CSceneView(CStudioApp *inStudioApp, QWidget *parent = nullptr); + CSceneView(); // used for serialization only! + virtual ~CSceneView(); + + bool HandleModifierUp(int inChar, int inRepCnt, Qt::KeyboardModifiers modifiers); + bool HandleModifierDown(int inChar, int inRepCnt, Qt::KeyboardModifiers modifiers); + bool PtInClientRect(const QPoint& inPoint); + void SetViewCursor(); + void SetToolMode(long inMode); + void RecheckSizingMode(); + + void SetRegisteredKey(bool inStatus); + void RegisterGlobalKeyboardShortcuts(CHotKeys *inShortcutHandler); + bool GetKeyStatus(); + + void SetPlayerWndPosition(); + + // redirect to/from PlayerContainerWnd + bool IsDeploymentView(); + void SetViewMode(CPlayerContainerWnd::EViewMode inViewMode); + + // Tool helper methods + void RestorePreviousTool(); + void SetToolOnCtrl(); + void SetToolOnAlt(); + + void OnRulerGuideToggled(); + + // CSelectedNodePropChangeListener + void OnPropValueChanged(const Q3DStudio::CString &inPropertyName) override; + void OnMouseDragged(bool inConstrainXAxis, bool inConstrainYAxis) override; + + // CClientPlayChangeListener + void OnTimeChanged(long inTime) override; + + // CEditCameraChangeListener + + void OnEditCameraChanged() override; + void OnEditCamerasTransformed() override; + void OnAuthorZoomChanged() override; + + QSize sizeHint() const override; + + void OnToolGroupSelection(); + void OnToolItemSelection(); +public: + + void resizeEvent(QResizeEvent *event) override; + +Q_SIGNALS: + void toolChanged(); + +protected: + void RecalcMatte(); + + // Generated message map functions +protected: + void OnSetCursor(); + void showEvent(QShowEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; +private: + void onDropReceived(); +}; + +///////////////////////////////////////////////////////////////////////////// + +#endif // INCLUDED_SCENE_VIEW_H diff --git a/src/Authoring/Studio/_Win/UI/StartupDlg.cpp b/src/Authoring/Studio/_Win/UI/StartupDlg.cpp new file mode 100644 index 00000000..286d94e3 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StartupDlg.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "StudioDefs.h" +#include "Strings.h" +#include "StringLoader.h" + +//============================================================================== +// Includes +//============================================================================== + +#include "StartupDlg.h" + +#include "StudioPreferences.h" +#include "ui_StartupDlg.h" + +#include +#include +#include +#include + +// CStartupDlg dialog + +CStartupDlg::CStartupDlg(QWidget *pParent) + : QDialog(pParent, Qt::MSWindowsFixedSizeDialogHint | Qt::FramelessWindowHint) + , m_Choice(EStartupChoice_Invalid) + , m_RecentDocSelected("") + , m_ui(new Ui::StartupDlg) + , m_palette(nullptr) +{ + m_ui->setupUi(this); +} + +CStartupDlg::~CStartupDlg() +{ + delete m_palette; +} + +static QString GetFileTimeReadable(const CUICFile &inFile) +{ + QFileInfo finfo(inFile.GetAbsolutePath().toQString()); + if (!finfo.exists()) + return {}; + + return finfo.lastModified().toString("MM/dd/yyyy"); +} + +void CStartupDlg::showEvent(QShowEvent *ev) +{ + OnInitDialog(); + QDialog::showEvent(ev); +} + +void CStartupDlg::OnInitDialog() +{ + connect(m_ui->newDocument, &QPushButton::clicked, this, &CStartupDlg::OnNewDocClicked); + connect(m_ui->openDocument, &QPushButton::clicked, this, &CStartupDlg::OnOpenDocClicked); + + // Load the product version + m_ProductVersionStr.Format( + ::LoadResourceString(IDS_UIC_STUDIO_VERSION), + static_cast(CStudioPreferences::GetVersionString())); + m_ui->versionStr->setText(m_ProductVersionStr.toQString()); + + // Populate the recent document list + for (uint theIndex = 0; theIndex < RECENT_COUNT; ++theIndex) { + ClickableLabel *recent + = findChild(QStringLiteral("recent%1").arg(theIndex)); + connect(recent, &ClickableLabel::clicked, this, &CStartupDlg::OnStnClickedStartupRecent); + + recent->setProperty("recentIndex", theIndex); + + if (m_RecentDocs.size() > theIndex) { + // Set the name + recent->setText(m_RecentDocs[theIndex].GetName().toQString()); + // Set path and date to tooltip + QFileInfo thePath(m_RecentDocs[theIndex].GetAbsolutePath().toQString()); + QString toolTip = thePath.absoluteDir().path(); + toolTip.append(QStringLiteral("\n")); + toolTip.append(GetFileTimeReadable(m_RecentDocs[theIndex])); + recent->setToolTip(toolTip); + } else { + recent->hide(); + } + } +} + +void CStartupDlg::AddRecentItem(const CUICFile &inRecentItem) +{ + m_RecentDocs.push_back(inRecentItem); +} + +CStartupDlg::EStartupChoice CStartupDlg::GetChoice() +{ + return m_Choice; +} + +CUICFile CStartupDlg::GetRecentDoc() const +{ + return m_RecentDocSelected; +} + +void CStartupDlg::OnNewDocClicked() +{ + m_Choice = EStartupChoice_NewDoc; + QDialog::accept(); +} + +void CStartupDlg::OnOpenDocClicked() +{ + m_Choice = EStartupChoice_OpenDoc; + QDialog::accept(); +} + +void CStartupDlg::OnStnClickedStartupRecent() +{ + const int index = sender()->property("recentIndex").toInt(); + OpenRecent(index); +} + +void CStartupDlg::OpenRecent(size_t inIndex) +{ + if (inIndex < m_RecentDocs.size()) { + m_RecentDocSelected = m_RecentDocs[inIndex]; + m_Choice = EStartupChoice_OpenRecent; + QDialog::accept(); + } +} + +void CStartupDlg::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event) + if (m_palette) + return; + + delete m_palette; + m_palette = new QPalette; + QPixmap pic = QPixmap(":/startup/open_dialog.png"); + pic.setDevicePixelRatio(devicePixelRatio()); + m_palette->setBrush(QPalette::Window, pic); + setPalette(*m_palette); + resize(pic.size()); + setFixedSize(size()); +} diff --git a/src/Authoring/Studio/_Win/UI/StartupDlg.h b/src/Authoring/Studio/_Win/UI/StartupDlg.h new file mode 100644 index 00000000..6fbd0a2a --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StartupDlg.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2006 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_STARTUP_DLG +#define INCLUDED_STARTUP_DLG 1 + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +#include + +#include "UICString.h" +#include "UICFile.h" + +#ifdef QT_NAMESPACE +using namespace QT_NAMESPACE; +#endif + +QT_BEGIN_NAMESPACE +namespace Ui { + class StartupDlg; +} +QT_END_NAMESPACE + +//============================================================================== +/** + * CGLVersionDlg: Dialog class for showing what user can do upon startup + */ +//============================================================================== +class CStartupDlg : public QDialog +{ + Q_OBJECT +public: + enum EStartupChoice { + EStartupChoice_Invalid = -1, + EStartupChoice_NewDoc, + EStartupChoice_OpenDoc, + EStartupChoice_OpenRecent, + EStartupChoice_Exit + }; + +public: + CStartupDlg(QWidget *pParent = nullptr); // standard constructor + virtual ~CStartupDlg(); + +protected: + const static int RECENT_COUNT = 5; + + void paintEvent(QPaintEvent *event) override; + void showEvent(QShowEvent *) override; + +protected Q_SLOTS: + void OnNewDocClicked(); + void OnOpenDocClicked(); + void OnStnClickedStartupRecent(); + void OpenRecent(size_t inIndex); + +private: + // Dialog background + QPalette *m_palette; + + // Product version string + Q3DStudio::CString m_ProductVersionStr; + + // Choice + EStartupChoice m_Choice = EStartupChoice_Invalid; + + // Recent Docs + std::vector m_RecentDocs; + CUICFile m_RecentDocSelected; + +public: + void OnInitDialog(); + void AddRecentItem(const CUICFile &inRecentItem); + EStartupChoice GetChoice(); + CUICFile GetRecentDoc() const; + +private: + QScopedPointer m_ui; +}; + +#endif // INCLUDED_STARTUP_DLG diff --git a/src/Authoring/Studio/_Win/UI/StartupDlg.ui b/src/Authoring/Studio/_Win/UI/StartupDlg.ui new file mode 100644 index 00000000..619c857a --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StartupDlg.ui @@ -0,0 +1,171 @@ + + + StartupDlg + + + + 0 + 0 + 442 + 650 + + + + + + 20 + 250 + 411 + 29 + + + + RECENT FILES + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + 30 + 290 + 401 + 341 + + + + + + + Recent0.uip + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 0 + + + + + + + Recent1.uip + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 1 + + + + + + + Recent2.uip + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + Recent3.uip + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 3 + + + + + + + Recent3.uip + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 3 + + + + + + + + + 0 + 130 + 161 + 101 + + + + + + + Create Project... + + + + :/res/Toolbar-00.png:/res/Toolbar-00.png + + + true + + + + + + + Open Project... + + + + :/res/Toolbar-01.png:/res/Toolbar-01.png + + + true + + + + + + + + + 290 + 90 + 141 + 20 + + + + Qt 3D Studio version string + + + + + + ClickableLabel + QLabel +
ClickableLabel.h
+
+
+ + + + +
diff --git a/src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.cpp b/src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.cpp new file mode 100644 index 00000000..bde792eb --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.cpp @@ -0,0 +1,590 @@ +/**************************************************************************** +** +** 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 "ui_StudioAppPrefsPage.h" + +//============================================================================== +// Includes +//============================================================================== +#include "UICOptions.h" +#include "Doc.h" +#include "StudioAppPrefsPage.h" +#include "StudioConst.h" +#include "StudioProjectSettings.h" +#include "StudioPreferences.h" +#include "StudioApp.h" +#include "StudioPreferences.h" +#include "StringLoader.h" +#include "CommonConstants.h" +#include "Views.h" +#include "UICDMStudioSystem.h" +#include "ClientDataModelBridge.h" +#include "Core.h" +#include "IStudioRenderer.h" + +#include +#include + +#define WM_PREVIEW_DYNAMIC_CONTROLS WM_USER + 1200 +const long MIN_PAGESIZE = 380; + +///////////////////////////////////////////////////////////////////////////// +// CStudioAppPrefsPage property page + +//============================================================================== +/** + * Constructor: Initializes the object. + */ +//============================================================================== +CStudioAppPrefsPage::CStudioAppPrefsPage(QWidget *parent) + : CStudioPreferencesPropPage(parent) + , m_nudgeValue(0.0) + , m_TimebarShowTime(FALSE) + , m_InterpolationIsSmooth(FALSE) + , m_ui(new Ui::StudioAppPrefsPage) +{ + m_Font = QFont(CStudioPreferences::GetFontFaceName()); + m_Font.setPixelSize(CStudioPreferences::fontSize()); + + // Create a bold font for the group box text + m_BoldFont = m_Font; + m_BoldFont.setBold(true); + + OnInitDialog(); +} + +//============================================================================== +/** + * Destructor: Releases the object. + */ +//============================================================================== +CStudioAppPrefsPage::~CStudioAppPrefsPage() +{ +} + +///////////////////////////////////////////////////////////////////////////// +// CStudioAppPrefsPage message handlers + +void CStudioAppPrefsPage::OnInitDialog() +{ + m_ui->setupUi(this); + m_ui->m_editNudgeAmount->setValidator(new QDoubleValidator(this)); + + // Add tool tips for controls + m_ui->m_editNudgeAmount->setToolTip(::LoadResourceString(IDS_PREFS_NUDGEAMOUNT).toQString()); + m_ui->m_DefaultInterpolation->setToolTip(::LoadResourceString(IDS_PREFS_INTERPOLATIONDEFAULT).toQString()); + m_ui->m_checkTimelineAbsoluteSnapping->setToolTip( + ::LoadResourceString(IDS_PREFS_TIMELINEGRIDSNAPPING).toQString()); + m_ui->m_SnapRangeCombo->setToolTip(::LoadResourceString(IDS_PREFS_TIMELINEGRIDRESOLUTION).toQString()); + m_ui->m_buttonRestoreDefaults->setToolTip(::LoadResourceString(IDS_PREFS_RESTOREDEFAULTS).toQString()); + m_ui->m_EditViewBGColor->setAutoFillBackground(true); + + // Set fonts for child windows. + for (auto w : findChildren()) + w->setFont(m_Font); + + // Make the group text bold + for (auto w : findChildren()) + w->setFont(m_BoldFont); + +#ifndef INCLUDE_EDIT_CAMERA + ASSERT(0); + // This won't work as all the controls have to move accordingly. Don't think INCLUDE_EDIT_CAMERA + // will be undefined + // Hide controls related to Edit Camera + m_ui->m_groupBoxEditingView->setVisible(false); +#endif + + // Load the settings for the controls + LoadSettings(); + + auto activated = static_cast(&QComboBox::activated); + connect(m_ui->m_buttonRestoreDefaults, &QPushButton::clicked, this, &CStudioAppPrefsPage::OnButtonRestoreDefaults); + connect(m_ui->m_DefaultInterpolation, activated, this, &CStudioAppPrefsPage::OnSelChangeInterpolationDefault); + connect(m_ui->m_SnapRangeCombo, activated, this, &CStudioAppPrefsPage::OnSelChangeSnapRange); + connect(m_ui->m_checkTimelineAbsoluteSnapping, &QCheckBox::clicked, this, &CStudioAppPrefsPage::OnCheckTimelineAbsoluteSnapping); + connect(m_ui->m_EditViewBGColor, &QPushButton::clicked, this, &CStudioAppPrefsPage::OnBgColorButtonClicked); + connect(m_ui->m_editNudgeAmount, &QLineEdit::textEdited, this, &CStudioAppPrefsPage::OnChangeEditNudgeAmount); + connect(m_ui->m_EditViewStartupView, activated, this, &CStudioAppPrefsPage::OnSelChangeStartupView); + connect(m_ui->m_PreviewSelector, activated, this, &CStudioAppPrefsPage::OnChangePreviewConfiguration); +} + +//============================================================================== +/** + * LoadSettings: Load the settings from the CDoc and set the control values. + * + * @param None + */ +//============================================================================== +void CStudioAppPrefsPage::LoadSettings() +{ + m_nudgeValue = CStudioPreferences::GetNudgeAmount(); + + // Get the Interpolation Preference + Q3DStudio::CString theComboItem; + theComboItem = ::LoadResourceString(IDS_PREF_INTERPOLATION_1); + m_ui->m_DefaultInterpolation->addItem(theComboItem.toQString()); + theComboItem = ::LoadResourceString(IDS_PREF_INTERPOLATION_2); + m_ui->m_DefaultInterpolation->addItem(theComboItem.toQString()); + + long theInterpolationPref = 0; + if (CStudioPreferences::GetInterpolation()) + theInterpolationPref = 0; + else + theInterpolationPref = 1; + m_ui->m_DefaultInterpolation->setCurrentIndex(theInterpolationPref); + + // Timeline snapping grid + m_ui->m_checkTimelineAbsoluteSnapping->setChecked( + CStudioPreferences::IsTimelineSnappingGridActive()); + + // Load the combo boxes with values from the string table so that they are localizable. + // The scale mode + (void)theComboItem; + theComboItem = ::LoadResourceString(IDS_PREF_SNAPRANGE_1); + m_ui->m_SnapRangeCombo->addItem(theComboItem.toQString()); + theComboItem = ::LoadResourceString(IDS_PREF_SNAPRANGE_2); + m_ui->m_SnapRangeCombo->addItem(theComboItem.toQString()); + theComboItem = ::LoadResourceString(IDS_PREF_SNAPRANGE_3); + m_ui->m_SnapRangeCombo->addItem(theComboItem.toQString()); + long theResolution = (long)CStudioPreferences::GetTimelineSnappingGridResolution(); + m_ui->m_SnapRangeCombo->setCurrentIndex(theResolution); + +#ifdef INCLUDE_EDIT_CAMERA + // Edit View Background color + // TODO: Visualize selected color on the bg color change button + InitEditStartViewCombo(); +#endif + + EnableOptions(); + + LoadPreviewSelections(); + + m_ui->m_editNudgeAmount->setText(QString::number(m_nudgeValue)); + m_bgColor = CStudioPreferences::GetEditViewBackgroundColor(); + updateColorButton(); +} + +void CStudioAppPrefsPage::updateColorButton() +{ + QPalette pal = m_ui->m_EditViewBGColor->palette(); + pal.setColor(QPalette::Button, m_bgColor); + m_ui->m_EditViewBGColor->setPalette(pal); +} + +//============================================================================== +/** + * SaveSettings: Save the settings from the controls to the CDoc + * + * @param None + */ +//============================================================================== +void CStudioAppPrefsPage::SaveSettings() +{ + // Nudge amount + CStudioPreferences::SetNudgeAmount(m_nudgeValue); + + // Default interpolation + g_StudioApp.GetCore()->GetDoc()->SetDefaultKeyframeInterpolation( + m_ui->m_DefaultInterpolation->currentIndex() == 0); + + // Timeline snapping grid + CStudioPreferences::SetTimelineSnappingGridActive( + m_ui->m_checkTimelineAbsoluteSnapping->isChecked()); + long theCurrentSelection = m_ui->m_SnapRangeCombo->currentIndex(); + CStudioPreferences::SetTimelineSnappingGridResolution((ESnapGridResolution)theCurrentSelection); + +#ifdef INCLUDE_EDIT_CAMERA + // Edit View Background Color + CStudioPreferences::SetEditViewBackgroundColor(m_bgColor); + // + // g_StudioApp.GetCore()->GetDoc( )->SetEditViewBackgroundColor( theColor ); + + // Preferred Startup View + long theSel = m_ui->m_EditViewStartupView->currentIndex(); + long theNumItems = m_ui->m_EditViewStartupView->count(); + CStudioPreferences::SetPreferredStartupView( + (theSel == theNumItems - 1) ? -1 : theSel); // -1 for deployment view +// g_StudioApp.GetCore()->GetDoc( )->UpdateClientScene( false ); +#endif + + SavePreviewSettings(); +} + +//============================================================================== +/** + * OnApply: Handler for the Apply button + * + * @param None + */ +//============================================================================== +bool CStudioAppPrefsPage::OnApply() +{ + // Apply was clicked - save settings and disabled the Apply button + this->SaveSettings(); + + this->SetModified(FALSE); + + // Request that the renderer refreshes as settings may have changed + g_StudioApp.GetRenderer().RequestRender(); + + return CStudioPreferencesPropPage::OnApply(); +} + +//============================================================================== +/** + * OnOK: Handler for the OK button + * + * @param None + */ +//============================================================================== +void CStudioAppPrefsPage::OnOK() +{ + CStudioPreferencesPropPage::OnOK(); +} + +//============================================================================== +/** + * OnCancel: Handler for the Cancel button + * + * @param None + */ +//============================================================================== +void CStudioAppPrefsPage::OnCancel() +{ +#ifdef INCLUDE_EDIT_CAMERA + // if the edit view background color was changed, reset it back to the original + // value + CColor theOrigColor = CStudioPreferences::GetEditViewBackgroundColor(); + if (m_bgColor != theOrigColor) { + // g_StudioApp.GetCore()->GetDoc( )->SetEditViewBackgroundColor( theOrigColor ); + // g_StudioApp.GetCore()->GetDoc( )->UpdateClientScene( false ); + } +#endif + CStudioPreferencesPropPage::OnCancel(); +} + +//============================================================================== +/** + * OnButtonRestoreDefaults: Restore the defaults and exit the preferences. + * + * @param None + */ +//============================================================================== +void CStudioAppPrefsPage::OnButtonRestoreDefaults() +{ + Q3DStudio::CString theMessage; + Q3DStudio::CString theTitle; + int theChoice = 0; + + // Load the text strings for the message box + theTitle = ::LoadResourceString(IDS_PREF_RESTOREDEFAULT_TITLE); + theMessage = ::LoadResourceString(IDS_PREF_RESTOREDEFAULT_TEXT); + + // Ask the user if she really wants to do this + theChoice = QMessageBox::question(this, theTitle.toQString(), theMessage.toQString()); + + // If the "yes" button was selected + if (theChoice == QMessageBox::Yes) { + // Restore default preferences by passing PREFS_RESET_DEFAULTS back + // to the CStudioDocPreferences (that called this preferences sheet) + CStudioPreferencesPropPage::EndDialog(PREFS_RESET_DEFAULTS); + } +} + +//============================================================================== +/** + * OnSelChangeInterpolationDefault: CBN_SELCHANGE handler for the + * IDC_INTERPOLATION_DEFAULT combo + *box. + * + * @param None + */ +//============================================================================== +void CStudioAppPrefsPage::OnSelChangeInterpolationDefault() +{ + this->SetModified(TRUE); +} + +//============================================================================== +/** + * OnChangeEditNudgeAmount: EN_UPDATE handler for the IDC_EDIT_NUDGE + * + * @param None + */ +//============================================================================== +void CStudioAppPrefsPage::OnChangeEditNudgeAmount() +{ + QString editStr = m_ui->m_editNudgeAmount->text(); + m_nudgeValue = editStr.toDouble(); + this->SetModified(true); +} + +//============================================================================== +/** + * OnSelChangeSnapRange: CBN_SELCHANGE handler for the IDC_SNAPRANGE combo box. + * + * @param None + */ +//============================================================================== +void CStudioAppPrefsPage::OnSelChangeSnapRange() +{ + this->SetModified(true); +} + +//============================================================================== +/** + * OnCheckTimelineAbsoluteSnapping: Handler for the IDC_CHECK_TIMELINEABSOLUTESNAPPING + *checkbox. + * + * @param None + */ +//============================================================================== +void CStudioAppPrefsPage::OnCheckTimelineAbsoluteSnapping() +{ + this->SetModified(true); + this->EnableOptions(); +} + +//============================================================================== +/** + * EnableOptions: Enable/disable options. + * + * @param None + */ +//============================================================================== +void CStudioAppPrefsPage::EnableOptions() +{ + m_ui->m_SnapRangeCombo->setEnabled(m_ui->m_checkTimelineAbsoluteSnapping->isChecked()); +} + +//============================================================================== +/** + * OnSelChangeStartupView: CBN_SELCHANGE handler for the IDC_COMBO_EDIT_STARTUP_VIEW + * Combo box + */ +void CStudioAppPrefsPage::OnSelChangeStartupView() +{ + this->SetModified(true); +} + +//============================================================================== +/** + * Initialise the combo box that displays the preferred startup view. + * Set the initial selection to that saved to the preferences + */ +//============================================================================== +void CStudioAppPrefsPage::InitEditStartViewCombo() +{ + Q3DStudio::IStudioRenderer &theRenderer = g_StudioApp.GetRenderer(); + QStringList theCameraNames; + theRenderer.GetEditCameraList(theCameraNames); + for (size_t idx = 0, end = theCameraNames.size(); idx < end; ++idx) { + m_ui->m_EditViewStartupView->addItem( + theCameraNames.at(idx)); + m_ui->m_EditViewStartupView->setItemData(m_ui->m_EditViewStartupView->count() - 1, QVariant((int)idx + 1)); + } + + m_ui->m_EditViewStartupView->addItem("--------------------------"); + m_ui->m_EditViewStartupView->setItemData(m_ui->m_EditViewStartupView->count() - 1, -1); // set to an invalid pointer + // add the deployment view as the last selection + m_ui->m_EditViewStartupView->addItem(::LoadResourceString(IDS_SCENE_CAMERA_VIEW).toQString()); + m_ui->m_EditViewStartupView->setItemData(m_ui->m_EditViewStartupView->count() - 1, 0); + + long thePreferredView = CStudioPreferences::GetPreferredStartupView(); + long theNumItems = m_ui->m_EditViewStartupView->count(); + if (thePreferredView == -1) // deployment view + m_ui->m_EditViewStartupView->setCurrentIndex(theNumItems - 1); // set to the last one + else if (thePreferredView < theNumItems - 1) + m_ui->m_EditViewStartupView->setCurrentIndex(thePreferredView); + else // possibly from old content where cameras are removed + m_ui->m_EditViewStartupView->setCurrentIndex(0); +} + +void CStudioAppPrefsPage::LoadPreviewSelections() +{ + // Load the configurations from all the .build files + Q3DStudio::CBuildConfigurations &theConfig = g_StudioApp.GetCore()->GetBuildConfigurations(); + Q3DStudio::CBuildConfigurations::TBuildConfigurations theConfigurations = + theConfig.GetConfigurations(); + Q3DStudio::CBuildConfigurations::TBuildConfigurations::iterator theIter; + for (theIter = theConfigurations.begin(); theIter != theConfigurations.end(); ++theIter) { + const Q3DStudio::CString &theConfig = theIter->first; + m_ui->m_PreviewSelector->addItem(theConfig.toQString()); + m_ui->m_PreviewSelector->setItemData(m_ui->m_PreviewSelector->count() - 1, + QVariant::fromValue(theIter->second)); + } + + int thePreviewSelected = m_ui->m_PreviewSelector->findText(CStudioPreferences::GetPreviewConfig().toQString()); + m_ui->m_PreviewSelector->setCurrentIndex(thePreviewSelected); + if (thePreviewSelected == -1) { + // select the first build configuration, or if no conriguration, the first application, i.e. + // AMPlayer + m_ui->m_PreviewSelector->setCurrentIndex(0); + long thePreviewCount = m_ui->m_PreviewSelector->count(); + for (long theIndex = 0; theIndex < thePreviewCount; ++theIndex) { + if (m_ui->m_PreviewSelector->itemData(theIndex).value() != nullptr) { + m_ui->m_PreviewSelector->setCurrentIndex(theIndex); + break; + } + } + } + + LoadBuildProperties(); +} + +//============================================================================== +/** + * When the build configuration is changed, all the properties have to be updated. + */ +//============================================================================== +void CStudioAppPrefsPage::OnChangePreviewConfiguration() +{ + LoadBuildProperties(); +} + +void CStudioAppPrefsPage::OnBgColorButtonClicked() +{ + QColorDialog dlg(this); + dlg.setCurrentColor(m_bgColor); + if (dlg.exec() == QDialog::Accepted) { + m_bgColor = dlg.selectedColor(); + updateColorButton(); + } + + this->SetModified(true); +} + +//============================================================================== +/** + * Load the build properties for the current preview application selected + */ +//============================================================================== +void CStudioAppPrefsPage::LoadBuildProperties() +{ + // Remove those dynamic controls + RemovePreviewPropertyControls(); + + if (m_ui->m_PreviewSelector->count() > 0) { + Q3DStudio::CBuildConfiguration *theConfig = + m_ui->m_PreviewSelector->itemData(m_ui->m_PreviewSelector->currentIndex()).value(); + if (theConfig) { + // Only configuration read from .build files will have the ItemDataPtr set. + + Q3DStudio::CBuildConfiguration::TConfigProperties &theProperties = + theConfig->GetBuildProperties(); + + auto layout = qobject_cast(m_ui->groupBoxPreview->layout()); + auto activated = static_cast(&QComboBox::activated); + + if (theProperties.empty() == false) { + Q3DStudio::CBuildConfiguration::TConfigProperties::iterator theIter; + + for (theIter = theProperties.begin(); theIter != theProperties.end(); ++theIter) { + Q3DStudio::CBuildConfiguration::TConfigPropertyValues &theValues = + theIter->GetAcceptableValues(); + // Only create the combo if there is more than 1 choices + if (theValues.size() > 1) { + Q3DStudio::CBuildConfiguration::TConfigPropertyValues::iterator + theValueIter; + long theMaxLength = 0; + for (theValueIter = theValues.begin(); theValueIter != theValues.end(); + ++theValueIter) { + long theLabelLength = theValueIter->GetLabel().Length(); + if (theLabelLength > theMaxLength) + theMaxLength = theLabelLength; + } + + QLabel *theStaticText = new QLabel(theIter->GetLabel().toQString()); + theStaticText->setFont(m_Font); + QComboBox *thePropertyDropdown = new QComboBox(); + connect(thePropertyDropdown, activated, [&]() {SetModified(true);}); + thePropertyDropdown->setFont(m_Font); + layout->addRow(theStaticText, thePropertyDropdown); + + m_BuildProperties.push_back(std::make_pair( + &*theIter, std::make_pair(theStaticText, thePropertyDropdown))); + + Q3DStudio::CString thePropertyValue = + CStudioPreferences::GetPreviewProperty(theIter->GetName()); + for (theValueIter = theValues.begin(); theValueIter != theValues.end(); + ++theValueIter) { + thePropertyDropdown->addItem(theValueIter->GetLabel().toQString()); + thePropertyDropdown->setItemData(thePropertyDropdown->count() - 1, QVariant::fromValue(&*theValueIter)); + if (theValueIter->GetName() == thePropertyValue) + thePropertyDropdown->setCurrentIndex(thePropertyDropdown->count() - 1); + } + + // Select the first entry + if (thePropertyDropdown->currentIndex() == -1) + thePropertyDropdown->setCurrentIndex(0); + } + } + } + } + } +} + +void CStudioAppPrefsPage::SavePreviewSettings() +{ + QString thePreviewApp = m_ui->m_PreviewSelector->currentText(); + CStudioPreferences::SetPreviewConfig(Q3DStudio::CString::fromQString(thePreviewApp)); + + std::list::iterator theIter; + for (theIter = m_BuildProperties.begin(); theIter != m_BuildProperties.end(); ++theIter) { + QComboBox *theCombo = theIter->second.second; + Q3DStudio::CString theName = theIter->first->GetName(); + Q3DStudio::CBuildConfiguration::SConfigPropertyValue *thePropertyValue = + theCombo->itemData(theCombo->currentIndex()).value(); + CStudioPreferences::SetPreviewProperty(theName, thePropertyValue->GetName()); + } +} + +//============================================================================== +/** + * Remove all the dynamically added controls that was read in from the build file + */ +//============================================================================== +void CStudioAppPrefsPage::RemovePreviewPropertyControls() +{ + // Remove the created control + std::list::iterator theIter; + for (theIter = m_BuildProperties.begin(); theIter != m_BuildProperties.end(); ++theIter) { + delete theIter->second.first; + delete theIter->second.second; + } + m_BuildProperties.clear(); +} diff --git a/src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.h b/src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.h new file mode 100644 index 00000000..a3be36c2 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#if !defined(AFX_STUDIOAPPPREFSPAGE_H__FA329789_EEDD_4439_B6F6_AAD0FED5285F__INCLUDED_) +#define AFX_STUDIOAPPPREFSPAGE_H__FA329789_EEDD_4439_B6F6_AAD0FED5285F__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +//============================================================================== +// Includes +//============================================================================== +#include "BuildConfigParser.h" + +#include "StudioPreferencesPropSheet.h" + +class QComboBox; +class QLabel; + +class CStudioApp; +///////////////////////////////////////////////////////////////////////////// +// CStudioAppPrefsPage dialog + +namespace Ui +{ + class StudioAppPrefsPage; +} + +class CStudioAppPrefsPage : public CStudioPreferencesPropPage +{ + Q_OBJECT +protected: + typedef std::pair TBuildLabelDropdownPair; + typedef std::pair + TBuildNameControlPair; + + // Construction +public: + explicit CStudioAppPrefsPage(QWidget *parent = nullptr); + ~CStudioAppPrefsPage(); + + // Dialog Data + QColor m_bgColor; + + double m_nudgeValue; + +public: + bool OnApply() override; + void OnOK() override; + void OnCancel() override; + + // Implementation +protected: + BOOL m_TimebarShowTime; ///< TRUE if timebars are to display their time value + BOOL m_InterpolationIsSmooth; ///< TRUE if default interpolation is smooth + QFont m_Font; ///< Font for text + QFont m_BoldFont; ///< Bold font for drawing the group boxes + void EnableOptions(); + void LoadSettings(); + void SaveSettings(); + + // Generated message map functions + virtual void OnInitDialog(); + void OnButtonRestoreDefaults(); + void OnSelChangeInterpolationDefault(); + void OnSelChangeSnapRange(); + void OnCheckTimelineAbsoluteSnapping(); + void OnChangeEditNudgeAmount(); + void OnSelChangeStartupView(); + void OnChangePreviewConfiguration(); + void OnBgColorButtonClicked(); + +protected: // helper functions + void InitEditStartViewCombo(); + +protected: + std::list + m_BuildProperties; ///< List of build properties, either ComboBox or Static + + void LoadPreviewSelections(); + void LoadBuildProperties(); + void SavePreviewSettings(); + void RemovePreviewPropertyControls(); + + QScopedPointer m_ui; + +private: + void updateColorButton(); +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STUDIOAPPPREFSPAGE_H__FA329789_EEDD_4439_B6F6_AAD0FED5285F__INCLUDED_) diff --git a/src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.ui b/src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.ui new file mode 100644 index 00000000..5e1b88c5 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StudioAppPrefsPage.ui @@ -0,0 +1,183 @@ + + + StudioAppPrefsPage + + + + 0 + 0 + 347 + 387 + + + + Form + + + + + + General + + + + + + Nudge Increment + + + m_editNudgeAmount + + + + + + + Default Interpolation + + + m_DefaultInterpolation + + + + + + + + + + Timeline Snapping Grid + + + + + + + + + + + + + + + + Editing View + + + + + + Background Color + + + m_EditViewBGColor + + + + + + + + + + + + + + Preferred Startup View + + + m_EditViewStartupView + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 293 + 16777215 + + + + Restore Defaults + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Preview + + + + + + Configuration + + + m_PreviewSelector + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + diff --git a/src/Authoring/Studio/_Win/UI/StudioPaletteBar.cpp b/src/Authoring/Studio/_Win/UI/StudioPaletteBar.cpp new file mode 100644 index 00000000..747ba442 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StudioPaletteBar.cpp @@ -0,0 +1,260 @@ +/**************************************************************************** +** +** 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 "StudioPaletteBar.h" +#include "Preferences.h" +#include "StudioConst.h" +#include "PaletteState.h" +#include "StudioApp.h" + +//============================================================================== +// Message Maps +//============================================================================== +BEGIN_MESSAGE_MAP(CStudioPaletteBar, CViewBar) +//{{AFX_MSG_MAP(CStudioPaletteBar) +//}}AFX_MSG_MAP +END_MESSAGE_MAP() + +//============================================================================== +// Constructors/Destructors +//============================================================================== + +CStudioPaletteBar::CStudioPaletteBar() +{ +} + +CStudioPaletteBar::~CStudioPaletteBar() +{ +} + +void CStudioPaletteBar::SetHorz(CSize inSize) +{ + m_szHorz.cx = max(m_szMinHorz.cx, inSize.cx); + m_szHorz.cy = max(m_szMinHorz.cy, inSize.cy); +} + +void CStudioPaletteBar::SetVert(CSize inSize) +{ + m_szVert.cx = max(m_szMinVert.cx, inSize.cx); + m_szVert.cy = max(m_szMinVert.cy, inSize.cy); +} + +void CStudioPaletteBar::SetFloat(CSize inSize) +{ + m_szFloat.cx = max(m_szMinFloat.cx, inSize.cx); + m_szFloat.cy = max(m_szMinFloat.cy, inSize.cy); +} + +//============================================================================== +/** + * Create: A wrapper around the CViewBar::Create() method. + * + * Simplifies the create parameters for the palette bar. + * + * @return BOOL The result from the Create() call (FALSE if unsuccessful) + */ +BOOL CStudioPaletteBar::Create(CString inTitle, CCreateContext *inCreateContext, long inControlId, + CWnd *theParent /* = nullptr */) +{ + BOOL theReturnValue; + + // Add the title of the bar to the registry location. + m_PaletteName = inTitle; + + // Create the palette bar. + theReturnValue = + CViewBar::Create(theParent, inCreateContext, inTitle, WS_CHILD | CBRS_TOP, inControlId); + ASSERT(theReturnValue == TRUE); + + SetBarStyle(GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); + EnableDocking(CBRS_ALIGN_ANY); + + return theReturnValue; +} + +//============================================================================== +/** + * Call this function when the palette's view needs to be updated for the first + * time on application launch. + */ +void CStudioPaletteBar::InitialUpdate() +{ + // Send the update message to the attached CView + SendMessageToDescendants(WM_STUDIO_INITIALIZE_PALETTES, reinterpret_cast(&g_StudioApp)); +} + +//============================================================================== +/** + * Shows or hides the palette and saves the visibility. + * + * This function should be called instead of ShowWindow(), so that the visibility + * will be saved in the registry. + */ +void CStudioPaletteBar::ShowPalette(bool inState /* = true */) +{ + ShowWindow(inState ? SW_SHOW : SW_HIDE); + m_pDockSite->ShowControlBar(this, inState, FALSE); +} + +//============================================================================== +/** + * Query the view associated with this palette + */ +CView *CStudioPaletteBar::GetView() +{ + // Looks like the first grandchild is the view + return (CView *)GetWindow(GW_CHILD)->GetWindow(GW_CHILD); +} + +//============================================================================== +// Message Maps +//============================================================================== +BEGIN_MESSAGE_MAP(CStudioDialog, CMiniFrameWnd) +//{{AFX_MSG_MAP(CStudioDialog) +//}}AFX_MSG_MAP +END_MESSAGE_MAP() + +//============================================================================== +// Constructors/Destructors +//============================================================================== + +CStudioDialog::CStudioDialog() +{ +} + +CStudioDialog::~CStudioDialog() +{ +} + +//============================================================================== +/** + * Create: A wrapper around the CMiniFrameWnd::Create() method. + * + * Simplifies the create parameters for the palette bar. + * + * @return BOOL The result from the Create() call (FALSE if unsuccessful) + */ +/* +BOOL CStudioDialog::Create( CString inTitle, CCreateContext* inCreateContext, long inControlId, +CWnd* theParent ) +{ + BOOL theReturnValue; + + // Add the title of the bar to the registry location. + m_DialogName = inTitle; + + // Create the palette bar. + theReturnValue = CMiniFrameWnd::Create( theParent, inCreateContext, _T( inTitle ), WS_CHILD +| CBRS_TOP, inControlId ); + ASSERT( theReturnValue == TRUE ); + + SetBarStyle( GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC ); + EnableDocking(CBRS_ALIGN_ANY); + + return theReturnValue; +}*/ + +//============================================================================== +/** +* Create: A wrapper around the CMiniFrameWnd::Create() method. +* +* Simplifies the create parameters for the palette bar. +* +* @return BOOL The result from the Create() call (FALSE if unsuccessful) +*/ +//============================================================================== +BOOL CStudioDialog::Create(CString inTitle, CCreateContext *inCreateContext, + CWnd *theParent /* = nullptr */) +{ + CString theWndClass = AfxRegisterWndClass(CS_DBLCLKS, ::LoadCursor(nullptr, IDC_ARROW)); + BOOL theReturnValue; + + // Add the title of the bar to the registry location. + m_DialogName = inTitle; + + // Create the palette bar. + theReturnValue = CFrameWnd::Create( + theWndClass, inTitle, WS_SYSMENU | MFS_SYNCACTIVE | WS_POPUP | WS_CAPTION | MFS_THICKFRAME, + CRect(300, 300, 550, 800), theParent, nullptr, 0, inCreateContext); + + // Get the view to initialize. + this->InitialUpdateFrame(inCreateContext->m_pCurrentDoc, FALSE); + + // Get a handle to the system menu on the palette window + CMenu *theSystemMenu = GetSystemMenu(FALSE); + + // Remove the unwanted system menu items + theSystemMenu->DeleteMenu(SC_MINIMIZE, MF_BYCOMMAND); + theSystemMenu->DeleteMenu(SC_MAXIMIZE, MF_BYCOMMAND); + theSystemMenu->DeleteMenu(SC_RESTORE, MF_BYCOMMAND); + + return theReturnValue; +} + +//============================================================================== +/** + * Call this function when the palette's view needs to be updated for the first + * time on application launch. + */ +void CStudioDialog::InitialUpdate() +{ + // Send the update message to the attached CView + SendMessageToDescendants(WM_STUDIO_INITIALIZE_PALETTES, reinterpret_cast(&g_StudioApp)); +} + +//============================================================================== +/** + * Shows or hides the dialog and saves the visibility. + * + * This function should be called instead of ShowWindow(), so that the visibility + * will be saved in the registry. + */ +void CStudioDialog::ShowDialog(bool inState /* = true */) +{ + ShowWindow(inState ? SW_SHOW : SW_HIDE); + // m_pDockSite->ShowControlBar( this, inState, FALSE ); +} + +//============================================================================== +/** + * Query the view associated with this palette + */ +CView *CStudioDialog::GetView() +{ + // Looks like the first grandchild is the view + return (CView *)GetWindow(GW_CHILD)->GetWindow(GW_CHILD); +} diff --git a/src/Authoring/Studio/_Win/UI/StudioPaletteBar.h b/src/Authoring/Studio/_Win/UI/StudioPaletteBar.h new file mode 100644 index 00000000..eed3fd05 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StudioPaletteBar.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** 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_STUDIO_PALETTE_BAR_H +#define INCLUDED_STUDIO_PALETTE_BAR_H 1 + +#pragma once + +#include "ViewBar.h" + +class CStudioApp; +class CPaletteState; +class CStudioApp; + +class CStudioPaletteBar : public CViewBar +{ +public: + CStudioPaletteBar(); + virtual ~CStudioPaletteBar(); + + virtual BOOL Create(CString inTitle, CCreateContext *inCreateContext, long inControlId, + CWnd *theParent = nullptr); + + void ShowPalette(bool inState = true); + void InitialUpdate(); + CView *GetView(); + CSize GetHorz() { return m_szHorz; } + void SetHorz(CSize inSize); + CSize GetVert() { return m_szVert; } + void SetVert(CSize inSize); + CSize GetFloat() { return m_szFloat; } + void SetFloat(CSize inSize); + +protected: + Q3DStudio::CString m_PaletteName; + + //{{AFX_MSG(CStudioPaletteBar) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +class CStudioDialog : public CMiniFrameWnd +{ +public: + CStudioDialog(); + virtual ~CStudioDialog(); + + virtual BOOL Create(CString inTitle, CCreateContext *inCreateContext, CWnd *theParent = nullptr); + + void ShowDialog(bool inState = true); + void InitialUpdate(); + CView *GetView(); + +protected: + Q3DStudio::CString m_DialogName; + + //{{AFX_MSG(CStudioDialog) + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +#endif // INCLUDED_STUDIO_PALETTE_BAR_H diff --git a/src/Authoring/Studio/_Win/UI/StudioPreferencesPropSheet.cpp b/src/Authoring/Studio/_Win/UI/StudioPreferencesPropSheet.cpp new file mode 100644 index 00000000..eb645d5e --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StudioPreferencesPropSheet.cpp @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** 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 "ui_StudioPreferencesPropSheet.h" + +//============================================================================== +// Includes +//============================================================================== +#include "StudioPreferences.h" +#include "StudioPreferencesPropSheet.h" +#include "StudioProjectSettingsPage.h" +#include "StringLoader.h" + +#include + +CStudioPreferencesPropPage::CStudioPreferencesPropPage(QWidget *parent) + : QWidget(parent) +{ +} + +void CStudioPreferencesPropPage::SetModified(bool modified) +{ + setProperty("modified", modified); + + auto s = sheet(); + if (s) { + auto buttons = s->findChild(); + bool anyModified = false; + for (auto page : s->findChildren()) + anyModified |= page->property("modified").toBool(); + buttons->button(QDialogButtonBox::Apply)->setEnabled(anyModified); + } +} + +CStudioPreferencesPropSheet* CStudioPreferencesPropPage::sheet() +{ + QWidget *parent = parentWidget(); + while (parent != nullptr) { + if (auto sheet = qobject_cast(parent)) + return sheet; + parent = parent->parentWidget(); + } + return nullptr; +} + + +void CStudioPreferencesPropPage::EndDialog(int returnCode) +{ + auto s = sheet(); + if (s) + s->done(returnCode); +} + +///////////////////////////////////////////////////////////////////////////// +// CStudioPreferencesPropSheet + +CStudioPreferencesPropSheet::CStudioPreferencesPropSheet(int nIDCaption, QWidget *pParentWnd, + int iSelectPage) + : QDialog(pParentWnd) + , m_ui(new Ui::StudioPreferencesPropSheet) +{ + setWindowTitle(::LoadResourceString(nIDCaption).toQString()); + OnInitDialog(); + m_ui->m_TabCtrl->setCurrentIndex(iSelectPage); +} + +CStudioPreferencesPropSheet::CStudioPreferencesPropSheet(const QString &pszCaption, QWidget *pParentWnd, + int iSelectPage) + : QDialog(pParentWnd) + , m_ui(new Ui::StudioPreferencesPropSheet) +{ + setWindowTitle(pszCaption); + OnInitDialog(); + m_ui->m_TabCtrl->setCurrentIndex(iSelectPage); +} + +CStudioPreferencesPropSheet::~CStudioPreferencesPropSheet() +{ +} + +///////////////////////////////////////////////////////////////////////////// +// CStudioPreferencesPropSheet message handlers + +//============================================================================== +/** + * OnInitDialog: Handle the WM_INITDIALOG message to initialize the property sheet. + * + * @param None + */ +//============================================================================== +void CStudioPreferencesPropSheet::OnInitDialog() +{ + m_ui->setupUi(this); + m_ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false); + + m_Font = QFont(CStudioPreferences::GetFontFaceName(), 8); + setFont(m_Font); + + connect(m_ui->buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, + this, &CStudioPreferencesPropSheet::apply); +} + +bool CStudioPreferencesPropSheet::apply() +{ + for (auto page : findChildren()) { + if (!page->OnApply()) + return false; + } + return true; +} + +void CStudioPreferencesPropSheet::accept() +{ + if (apply()) + QDialog::accept(); +} + +void CStudioPreferencesPropSheet::reject() +{ + for (auto page : findChildren()) + page->OnCancel(); + QDialog::reject(); +} diff --git a/src/Authoring/Studio/_Win/UI/StudioPreferencesPropSheet.h b/src/Authoring/Studio/_Win/UI/StudioPreferencesPropSheet.h new file mode 100644 index 00000000..7057ba0f --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StudioPreferencesPropSheet.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#if !defined(AFX_STUDIOPREFERENCESPROPSHEET_H__FADC69CE_5F0E_4F7E_A906_ED6052BBECF6__INCLUDED_) +#define AFX_STUDIOPREFERENCESPROPSHEET_H__FADC69CE_5F0E_4F7E_A906_ED6052BBECF6__INCLUDED_ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +#include + +class CStudioProjectSettingsPage; +class CStudioPreferencesPropSheet; +class CStudioApp; + +namespace Ui +{ + class StudioPreferencesPropSheet; +} + +class CStudioPreferencesPropPage : public QWidget +{ + Q_OBJECT +public: + explicit CStudioPreferencesPropPage(QWidget *parent = nullptr); + + virtual bool OnApply() { OnOK(); SetModified(false); return true; } + virtual void OnOK() {} + virtual void OnCancel() {} + +protected: + CStudioPreferencesPropSheet* sheet(); + + void SetModified(bool modified); + void EndDialog(int returnCode); +}; + +///////////////////////////////////////////////////////////////////////////// +// CStudioPreferencesPropSheet + +class CStudioPreferencesPropSheet : public QDialog +{ + Q_OBJECT + // Construction +public: + explicit CStudioPreferencesPropSheet(int nIDCaption, QWidget *pParentWnd = nullptr, + int iSelectPage = 0); + explicit CStudioPreferencesPropSheet(const QString &pszCaption, QWidget *pParentWnd = nullptr, + int iSelectPage = 0); + +protected: + QFont m_Font; // Font for text + + // Implementation +public: + virtual ~CStudioPreferencesPropSheet(); + + // Generated message map functions +protected: + //{{AFX_MSG(CStudioPreferencesPropSheet) + virtual void OnInitDialog(); + + bool apply(); + void accept() override; + void reject() override; + +private: + QScopedPointer m_ui; +}; + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STUDIOPREFERENCESPROPSHEET_H__FADC69CE_5F0E_4F7E_A906_ED6052BBECF6__INCLUDED_) diff --git a/src/Authoring/Studio/_Win/UI/StudioPreferencesPropSheet.ui b/src/Authoring/Studio/_Win/UI/StudioPreferencesPropSheet.ui new file mode 100644 index 00000000..813d6016 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StudioPreferencesPropSheet.ui @@ -0,0 +1,102 @@ + + + StudioPreferencesPropSheet + + + + 0 + 0 + 484 + 466 + + + + Studio Preferences + + + + + + + + :/res/prefstab-00.png:/res/prefstab-00.png + + + Studio + + + + + + :/res/prefstab-01.png:/res/prefstab-01.png + + + Presentation Settings + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + CStudioProjectSettingsPage + QWidget +
StudioProjectSettingsPage.h
+ 1 +
+ + CStudioAppPrefsPage + QWidget +
StudioAppPrefsPage.h
+ 1 +
+
+ + + + + + buttonBox + accepted() + StudioPreferencesPropSheet + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + StudioPreferencesPropSheet + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/src/Authoring/Studio/_Win/UI/StudioProjectSettingsPage.cpp b/src/Authoring/Studio/_Win/UI/StudioProjectSettingsPage.cpp new file mode 100644 index 00000000..c2a7e26c --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StudioProjectSettingsPage.cpp @@ -0,0 +1,385 @@ +/**************************************************************************** +** +** 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" + +#include "ui_StudioProjectSettingsPage.h" + +//============================================================================== +// Includes +//============================================================================== +#include "StudioProjectSettingsPage.h" +#include "StudioProjectSettings.h" +#include "StudioApp.h" +#include "Doc.h" +#include "Views.h" +#include "MainFrm.h" +#include "CommonConstants.h" + +#include "StudioPreferences.h" +#include "Core.h" + +///////////////////////////////////////////////////////////////////////////// +// CStudioProjectSettingsPage property page + +//============================================================================== +/** + * Constructor: Initializes the object. + */ +//============================================================================== +CStudioProjectSettingsPage::CStudioProjectSettingsPage(QWidget *parent) + : CStudioPreferencesPropPage(parent) + , m_AspectRatio(0.0f) + , m_ui(new Ui::StudioProjectSettingsPage) +{ + m_Font = QFont(CStudioPreferences::GetFontFaceName()); + m_Font.setPixelSize(CStudioPreferences::fontSize()); + + // Create a bold font for the group box text + m_BoldFont = m_Font; + m_BoldFont.setBold(true); + + OnInitDialog(); +} + +//============================================================================== +/** + * Destructor: Releases the object. + */ +//============================================================================== +CStudioProjectSettingsPage::~CStudioProjectSettingsPage() +{ +} + +//============================================================================== +// Message Map is defined by subclasses, since there is any specific handlers must be +// defined within the BEGIN_MESSAGE_MAP macros. +//============================================================================== + +///////////////////////////////////////////////////////////////////////////// +// CStudioProjectSettingsPage message handlers + +//============================================================================== +/** + * OnInitDialog: Handle the WM_INITDIALOG message. + * + * Initialize the dialog by setting the various control values. + * + * @param None + * + * @return Returns TRUE always. + */ +//============================================================================== +void CStudioProjectSettingsPage::OnInitDialog() +{ + m_ui->setupUi(this); + + m_ui->m_ClientSizeWidth->setToolTip(::LoadResourceString(IDS_PREFS_PRESENTATIONWIDTH).toQString()); + m_ui->m_ClientSizeHeight->setToolTip(::LoadResourceString(IDS_PREFS_PRESENTATIONHEIGHT).toQString()); + m_ui->m_checkConstrainProportions->setToolTip(::LoadResourceString(IDS_PREFS_PRESENTATIONASPECTRATIO).toQString()); + m_ui->m_Author->setToolTip(::LoadResourceString(IDS_PREFS_AUTHORNAME).toQString()); + m_ui->m_Company->setToolTip(::LoadResourceString(IDS_PREFS_COMPANYNAME).toQString()); + + // Set fonts for child windows. + for (auto w : findChildren()) + w->setFont(m_Font); + + // Make the group text bold + for (auto w : findChildren()) + w->setFont(m_BoldFont); + + // Set the ranges of the client width and height + m_ui->m_ClientSizeWidth->setRange(1, 16384); + m_ui->m_ClientSizeHeight->setRange(1, 16384); + + // Load the settings for the controls + this->LoadSettings(); + + auto valueChanged = static_cast(&QSpinBox::valueChanged); + connect(m_ui->m_ClientSizeWidth, valueChanged, this, &CStudioProjectSettingsPage::OnChangeEditPresWidth); + connect(m_ui->m_ClientSizeHeight, valueChanged, this, &CStudioProjectSettingsPage::OnChangeEditPresHeight); + connect(m_ui->m_checkConstrainProportions, &QCheckBox::clicked, this, &CStudioProjectSettingsPage::OnCheckMaintainRatio); + connect(m_ui->m_Author, &QLineEdit::textEdited, this, &CStudioProjectSettingsPage::OnChangeAuthor); + connect(m_ui->m_Company, &QLineEdit::textEdited, this, &CStudioProjectSettingsPage::OnChangeCompany); +} + +//============================================================================== +/** + * LoadSettings: Load the settings from the project settings and set the control values. + * + * @param None + */ +//============================================================================== +void CStudioProjectSettingsPage::LoadSettings() +{ + // Get the Client size + CStudioProjectSettings *theProjectSettings = g_StudioApp.GetCore()->GetStudioProjectSettings(); + CPt theClientSize = theProjectSettings->GetPresentationSize(); + + // Set client width & height + m_ui->m_ClientSizeWidth->setValue(theClientSize.x); + m_ui->m_ClientSizeHeight->setValue(theClientSize.y); + + // Save the aspect ratio + m_AspectRatio = (double)theClientSize.x / (double)theClientSize.y; + + // Maintain Aspect Ratio checkbox + m_ui->m_checkConstrainProportions->setChecked(theProjectSettings->GetMaintainAspect()); + + m_ui->m_checkPortraitFormat->setChecked(theProjectSettings->GetRotatePresentation()); + + // Author + m_ui->m_Author->setText(theProjectSettings->GetAuthor()); + + // Company + m_ui->m_Company->setText(theProjectSettings->GetCompany()); +} + +//============================================================================== +/** + * SaveSettings: Save the settings from the controls to the project settings. + * + * @param None + */ +//============================================================================== +void CStudioProjectSettingsPage::SaveSettings() +{ + CPt theClientSize; + CStudioProjectSettings *theProjectSettings = g_StudioApp.GetCore()->GetStudioProjectSettings(); + + // Presentation width & height + theClientSize.x = m_ui->m_ClientSizeWidth->value(); + theClientSize.y = m_ui->m_ClientSizeHeight->value(); + theProjectSettings->SetPresentationSize(theClientSize); + + // Author + QString theAuthor = m_ui->m_Author->text(); + theProjectSettings->SetAuthor(theAuthor); + + // Company + QString theCompany = m_ui->m_Company->text(); + theProjectSettings->SetCompany(theCompany); + + g_StudioApp.GetViews()->RecheckMainframeSizingMode(); + + // Maintain Aspect Ratio checkbox + theProjectSettings->SetMaintainAspect(m_ui->m_checkConstrainProportions->isChecked()); + + theProjectSettings->SetRotatePresentation(m_ui->m_checkPortraitFormat->isChecked()); +} + +//============================================================================== +/** + * Generic function when settings are modified. + * + * @param None + */ +//============================================================================== +void CStudioProjectSettingsPage::OnSettingsModified() +{ + this->SetModified(TRUE); +} + +//============================================================================== +/** + * OnApply: Handler for the Apply button + * + * @param None + */ +//============================================================================== +bool CStudioProjectSettingsPage::OnApply() +{ + // Apply was clicked - save settings and disabled the Apply button + this->SaveSettings(); + + this->SetModified(FALSE); + + return CStudioPreferencesPropPage::OnApply(); +} + +//============================================================================== +/** + * OnOK: Handler for the OK button + * + * @param None + */ +//============================================================================== +void CStudioProjectSettingsPage::OnOK() +{ + CStudioPreferencesPropPage::OnOK(); +} + +//============================================================================== +/** + * OnChangeEditPresWidth: EN_CHANGE handler for the IDC_EDIT_PRESWIDTH field + * + * @param None + */ +//============================================================================== +void CStudioProjectSettingsPage::OnChangeEditPresWidth() +{ + this->SetModified(TRUE); + + // Should the aspect ratio be maintained? + if (m_ui->m_checkConstrainProportions->isChecked()) { + long thePresWidth, thePresHeight; + + thePresWidth = m_ui->m_ClientSizeWidth->value(); + + // Change the height + thePresHeight = ((double)thePresWidth / m_AspectRatio); + + QSignalBlocker sb(m_ui->m_ClientSizeHeight); + m_ui->m_ClientSizeHeight->setValue(thePresHeight); + } +} + +//============================================================================== +/** + * OnChangeEditPresHeight: EN_CHANGE handler for the IDC_EDIT_PRESHEIGHT field + * + * @param None + */ +//============================================================================== +void CStudioProjectSettingsPage::OnChangeEditPresHeight() +{ + this->SetModified(TRUE); + + // Should the aspect ratio be maintained? + if (m_ui->m_checkConstrainProportions->isChecked()) { + long thePresWidth, thePresHeight; + + thePresHeight = m_ui->m_ClientSizeHeight->value(); + + // Change the width + thePresWidth = ((double)thePresHeight * m_AspectRatio); + + QSignalBlocker sb(m_ui->m_ClientSizeWidth); + m_ui->m_ClientSizeWidth->setValue(thePresWidth); + } +} + +//============================================================================== +/** + * OnCheckMaintainRatio: The aspect ratio checkbox has changed. + * + * @param None + */ +//============================================================================== +void CStudioProjectSettingsPage::OnCheckMaintainRatio() +{ + this->SetModified(TRUE); + + long thePresWidth, thePresHeight; + + // Get the width and height + thePresWidth = m_ui->m_ClientSizeWidth->value(); + thePresHeight = m_ui->m_ClientSizeHeight->value(); + + // Save the Aspect Ratio + m_AspectRatio = (double)thePresWidth / (double)thePresHeight; +} + +//============================================================================== +/** + * OnChangeAuthor: EN_CHANGE handler for the IDC_AUTHOR field. + * + * @param None + */ +//============================================================================== +void CStudioProjectSettingsPage::OnChangeAuthor() +{ + this->SetModified(TRUE); +} + +//============================================================================== +/** + * OnChangeCompany: EN_CHANGE handler for the IDC_COMPANY field. + * + * @param None + */ +//============================================================================== +void CStudioProjectSettingsPage::OnChangeCompany() +{ + this->SetModified(TRUE); +} + +//============================================================================== +/** + * OnChangeSet1: EN_CHANGE handler for the IDC_SET1 field. + * + * @param None + */ +//============================================================================== +void CStudioProjectSettingsPage::OnChangeSet1() +{ + this->SetModified(TRUE); +} + +//============================================================================== +/** + * OnChangeSet2: EN_CHANGE handler for the IDC_SET2 field. + * + * @param None + */ +//============================================================================== +void CStudioProjectSettingsPage::OnChangeSet2() +{ + this->SetModified(TRUE); +} + +//============================================================================== +/** + * OnChangeSet3: EN_CHANGE handler for the IDC_SET3 field. + * + * @param None + */ +//============================================================================== +void CStudioProjectSettingsPage::OnChangeSet3() +{ + this->SetModified(TRUE); +} + +//============================================================================== +/** + * OnChangeSet5: EN_CHANGE handler for the IDC_SET5 field. + * + * @param None + */ +//============================================================================== +void CStudioProjectSettingsPage::OnChangeSet5() +{ + this->SetModified(TRUE); +} diff --git a/src/Authoring/Studio/_Win/UI/StudioProjectSettingsPage.h b/src/Authoring/Studio/_Win/UI/StudioProjectSettingsPage.h new file mode 100644 index 00000000..64465e98 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StudioProjectSettingsPage.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$ +** +****************************************************************************/ + +#if !defined(AFX_STUDIOPROJECTSETTINGSPAGE_H__E3317E44_810D_4478_A7DD_CF8570B7C17C__INCLUDED_) +#define AFX_STUDIOPROJECTSETTINGSPAGE_H__E3317E44_810D_4478_A7DD_CF8570B7C17C__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +//============================================================================== +// Includes +//============================================================================== + +//#include "ParameterColor.h" + +#include "StudioPreferencesPropSheet.h" + +#ifdef _USENEWCOLORPICKER_ +#include "StudioColorPicker.h" +#endif + +//============================================================================== +// Forwards +//============================================================================== +class CStudioApp; + +namespace Ui { + class StudioProjectSettingsPage; +} + +//============================================================================== +// Base class for the settings for different modes +//============================================================================== +class CStudioProjectSettingsPage : public CStudioPreferencesPropPage +{ + Q_OBJECT + // Construction +public: + explicit CStudioProjectSettingsPage(QWidget *parent = nullptr); + ~CStudioProjectSettingsPage(); + + // Overrides + // ClassWizard generate virtual function overrides +public: + bool OnApply() override; + void OnOK() override; + + // Implementation +protected: + double m_AspectRatio; ///< Stores the presentation width divided by the presentation height + QFont m_Font; ///< Font for text + QFont m_BoldFont; ///< Bold font for drawing the group boxes + + void LoadSettings(); + void SaveSettings(); + +protected: + // Generated message map functions + virtual void OnInitDialog(); + void OnChangeEditPresWidth(); + void OnChangeEditPresHeight(); + void OnCheckMaintainRatio(); + void OnChangeAuthor(); + void OnChangeCompany(); + void OnSettingsModified(); + void OnSelChangePreviewApp(); + void OnCustomPreviewMore(); + void OnChangeSet1(); + void OnChangeSet2(); + void OnChangeSet3(); + void OnChangeSet5(); + + QScopedPointer m_ui; +}; + +#endif // !defined(AFX_STUDIOPROJECTSETTINGSPAGE_H__E3317E44_810D_4478_A7DD_CF8570B7C17C__INCLUDED_) diff --git a/src/Authoring/Studio/_Win/UI/StudioProjectSettingsPage.ui b/src/Authoring/Studio/_Win/UI/StudioProjectSettingsPage.ui new file mode 100644 index 00000000..07a4bf65 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/StudioProjectSettingsPage.ui @@ -0,0 +1,125 @@ + + + StudioProjectSettingsPage + + + + 0 + 0 + 259 + 269 + + + + + + + Presentation + + + + + + Width x Height + + + m_ClientSizeWidth + + + + + + + + + QAbstractSpinBox::NoButtons + + + + + + + QAbstractSpinBox::NoButtons + + + + + + + + + Constrain Proportions + + + + + + + Portrait Format + + + + + + + + + + Project Info + + + + + + Author + + + m_Author + + + + + + + + + + Company + + + m_Company + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + m_ClientSizeWidth + m_ClientSizeHeight + m_checkConstrainProportions + m_checkPortraitFormat + m_Author + m_Company + + + + diff --git a/src/Authoring/Studio/_Win/UI/TimeEditDlg.cpp b/src/Authoring/Studio/_Win/UI/TimeEditDlg.cpp new file mode 100644 index 00000000..619d7651 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/TimeEditDlg.cpp @@ -0,0 +1,524 @@ +/**************************************************************************** +** +** 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 "ui_timeeditdlg.h" + +#include "stdafx.h" +#include "StudioPreferences.h" +#include "Strings.h" +#include "StringLoader.h" + +//============================================================================== +// Includes +//============================================================================== + +#include "TimeEditDlg.h" +#include "IDoc.h" +#include "Bindings/ITimelineKeyframesManager.h" + +#include +#include + +//============================================================================= +/** + * Constructor + */ +CTimeEditDlg::CTimeEditDlg(QWidget *pParent) + : QDialog(pParent) + , m_MaxTime(0) + , m_MaxTimeDisplay(0) + , m_MinTimeDisplay(0) + , m_InitialTime1(0) + , m_InitialTime2(0) + , m_MinOffset(0) + , m_SecOffset(0) + , m_MSecOffset(0) + , m_MinMinorOffset(0) + , m_SecMinorOffset(0) + , m_MSecMinorOffset(0) + , m_CursorPosition(0) + , m_TimeFormat(0) + , m_PreviousFormat(0) + , m_TimeInMins(0.0f) + , m_NumberOfDigitsDrop(0) + , m_ColonPosition1(0) + , m_ColonPosition2(0) + , m_ObjectAssociation(0) + , m_OffsetFromInitialTime(0) + , m_Time1(0) + , m_Time2(0) + , m_Doc(nullptr) + , m_KeyframesManager(nullptr) + , m_Callback(nullptr) + , m_ui(new Ui::TimeEditDlg) +{ + m_ui->setupUi(this); + setAutoFillBackground(true); + + connect(m_ui->startTimeEdit, &QDateTimeEdit::timeChanged, this, &CTimeEditDlg::OnEnChangeTimeEdit1); + connect(m_ui->endTimeEdit, &QDateTimeEdit::timeChanged, this, &CTimeEditDlg::OnEnChangeTimeEdit2); +} + +//============================================================================= +/** + * Destructor + */ +CTimeEditDlg::~CTimeEditDlg() +{ + delete m_ui; +} + +void CTimeEditDlg::SetKeyframesManager(ITimelineKeyframesManager *inKeyframesManager) +{ + m_KeyframesManager = inKeyframesManager; +} + +//============================================================================= +/** + * InitData: Initializes the Time Edit Dialog Box. + * @param inTime1 is the intial start time, which will be shown when the time edit + * dialog box pops up + * @param inTime2 is the intial end time, which will be shown when the time edit + * dialog box pops up + * @param inDoc this can be nullptr where its not applicable + * @param inObjectAssociation is the identifier for that identifies the object + * associated with the time edit dialog + *(e.g. + * playhead, keyframe, timebar) + */ +void CTimeEditDlg::ShowDialog(long inTime1, long inTime2, IDoc *inDoc, long inObjectAssociation, + ITimeChangeCallback *inCallback /*= nullptr*/) +{ + m_InitialTime1 = inTime1; + m_InitialTime2 = inTime2; + m_ObjectAssociation = inObjectAssociation; + m_Doc = inDoc; + m_Callback = inCallback; + + m_OffsetFromInitialTime = 0; + m_NumberOfDigitsDrop = 0; + m_MinTimeDisplay = 0; + // if it is a Timebar, this will be adjusted, else this should be initialized to some value at + // least, + // for OverflowHandling to work correctly + m_MaxTimeDisplay = LONG_MAX; + + // 9999:59:999 converted to milliseconds + m_MaxTime = + TimeConversion(9999, CONVERT_MIN_TO_MSEC) + TimeConversion(59, CONVERT_SEC_TO_MSEC) + 999; + + m_TimeDisplay2 = FormatTime(m_InitialTime2); + // In cases Keyframes, where its only one set of time, do m_InitialTime1 later so that + // m_Min, etc. values are initializd to the valid values. + m_TimeDisplay1 = FormatTime(m_InitialTime1); + + // Present the dialog + exec(); +} + +//============================================================================== +/** + * FormatTime: Called to break up a given time in milliseconds into min:sec:msec + * store it in a string. The string is formatted in 99:59:999 form. + * @param inTime stores the time in milliseconds, which will be converted + * and stored in ioTimeString in 99:59:999 format. + * @return ioTimeString stores the result of the FormatTime method. + */ +QString CTimeEditDlg::FormatTime(long inTime) +{ + long theTime = inTime; + long hour = 0; + long min = 0; + long sec = 0; + long msec = 0; + // Translates the m_InitialTime1 (in milliseconds) into Minutes, Seconds and Milliseconds + if (inTime != 0) { + min = TimeConversion(theTime, CONVERT_MSEC_TO_MIN); + hour = min / 60; + theTime = theTime - TimeConversion(min, CONVERT_MIN_TO_MSEC); + min -= hour * 60; + sec = TimeConversion(theTime, CONVERT_MSEC_TO_SEC); + theTime = theTime - TimeConversion(sec, CONVERT_SEC_TO_MSEC); + msec = theTime; + } + return QString::asprintf("%02d:%02d:%02d:%03d", hour, min, sec, msec); +} + +//============================================================================== +/** + * OnInitDialog: Handle the WM_INITDIALOG message. + * @param None + * @return Returns TRUE always. + */ +void CTimeEditDlg::showEvent(QShowEvent *ev) +{ + OnInitDialog(); + QDialog::showEvent(ev); +} + + +void CTimeEditDlg::OnInitDialog() +{ + // Hide the window items associated with end time. + if (m_ObjectAssociation != TIMEBAR) + HideUnnecessaryFields(); + m_ui->startTimeEdit->setTime(QTime::fromString(m_TimeDisplay1, "hh:mm:ss:zzz")); + Q3DStudio::CString theTitle; + // Display the window captions for the correct object type + switch (m_ObjectAssociation) { + case PLAYHEAD: + theTitle = ::LoadResourceString(IDS_TIME_EDIT_DLG_GO_TO_TIME); + setWindowTitle(theTitle.toQString()); + break; + case ASSETKEYFRAME: + theTitle = ::LoadResourceString(IDS_TIME_EDIT_DLG_SET_KEYFRAME_TIME); + setWindowTitle(theTitle.toQString()); + break; + case TIMEBAR: + theTitle = ::LoadResourceString(IDS_TIME_EDIT_DLG_SET_TIMEBAR_TIME); + // m_TimeEditBoxNumber is a flag that switches the output between + // the first and second text box. + // When m_TimeEditBoxNumber = EDITBOX1, we are writing to the first text box + // (the one that appears on top). + // When it is EDITBOX2, the SetTimeEdit will write to the second text box. + setWindowTitle(theTitle.toQString()); + m_ui->endTimeEdit->setTime(QTime::fromString(m_TimeDisplay2, "hh:mm:ss:zzz")); + break; + } +} +//============================================================================== +/** + * accept: Upon clicking ok, the dialog will be exited + */ +void CTimeEditDlg::accept() +{ + // Only commit here, cos dup keyframes will be deleted. + if (m_ObjectAssociation == ASSETKEYFRAME && m_Doc && m_KeyframesManager) + m_KeyframesManager->CommitChangedKeyframes(); + else if (m_ObjectAssociation == TIMEBAR) + m_Callback->Commit(); + + QDialog::accept(); +} + +//============================================================================== +/** + * reject: Upon clicking Cancel, revert to the initial time. + */ +void CTimeEditDlg::reject() +{ + // Only commit here, cos dup keyframes will be deleted. + if (m_ObjectAssociation == ASSETKEYFRAME && m_Doc && m_KeyframesManager) + m_KeyframesManager->RollbackChangedKeyframes(); + else if (m_ObjectAssociation == TIMEBAR) + m_Callback->Rollback(); + QDialog::reject(); +} + +//============================================================================== +/** + * CountDigits: Counts the number of digits in a given number + * @param inNumber is the number that is used to count the number of digits + * @return the number of digits + */ +long CTimeEditDlg::CountDigits(long inNumber) +{ + long theNumberOfDigits = 0; + for (long theNumber = inNumber; theNumber >= 1; theNumber = theNumber / 10) + theNumberOfDigits++; + return theNumberOfDigits; +} + + +//============================================================================== +/** + * TimeOverflowUnderflow: Checks if inMin, inSec or inMSec has exceeded the overflow/ + * underflow limit. It will correct the time if it + *overflow/ + * underflow. + * @param inMin stores the min segment of the time + * @param inSec stores the sec segment of the time + * @param inMSec stores the msec segment of the time + * @param inTimeLimit stores the time limit before the overflow/underflow occurs + * @param inOverflowOrUnderflow is set to true if we are checking for overflow else + * we are checking for underflow + * @returns true if overflow/underflow occurs, otherwise returns false. + */ +bool CTimeEditDlg::TimeOverflowUnderflow(long *inMin, long *inSec, long *inMSec, long inTimeLimit, + bool inOverflowOrUnderflow) +{ + // The codes below translates inTimeLimit into theLimitMin:theLimitSec:theLimitMsec + bool theLimitExceeds = false; + long theLimitMin; + long theLimitSec; + long theLimitMsec; + TimeConversion(inTimeLimit, &theLimitMin, &theLimitSec, &theLimitMsec, + CONVERT_MSEC_TO_MIN_SEC_MSEC); + // Handle time overflow/underflow + if ((*inMin > theLimitMin && inOverflowOrUnderflow) + || (*inMin < theLimitMin && inOverflowOrUnderflow == false)) // Minutes exceeds limit + { + // Set all time segments to the limit + *inMin = theLimitMin; + *inSec = theLimitSec; + *inMSec = theLimitMsec; + theLimitExceeds = true; + } else if (*inMin == theLimitMin) { + if ((*inSec > theLimitSec && inOverflowOrUnderflow) + || (*inSec < theLimitSec && inOverflowOrUnderflow == false)) // Seconds exceeds limit + { + // Set the Sec and Msec segments to the limit + *inSec = theLimitSec; + *inMSec = theLimitMsec; + theLimitExceeds = true; + } else if (*inSec == theLimitSec) { + if ((*inMSec > theLimitMsec && inOverflowOrUnderflow) + || (*inMSec < theLimitMsec + && inOverflowOrUnderflow == false)) // Milliseconds exceeds limit + { + // Msec segments to the limit + *inMSec = theLimitMsec; + theLimitExceeds = true; + } + } + } + return theLimitExceeds; +} + +//============================================================================== +/** + * TimeConversion: Converts inTime to the format specified by inFlags. + * For example: + * inTime = 5 sec inFlags = CONVERT_SEC_TO_MSEC + * The method will convert 5 sec into 5000 msec and + *returns + * the result. + * @param inTime stores the time to be converted. + * inOperationCode determines the type of time conversion to be done on the + * inTime. + * @return theResult stores the result of the time conversion. + */ +long CTimeEditDlg::TimeConversion(long inTime, long inOperationCode) +{ + long theResult = 0; + switch (inOperationCode) { + case CONVERT_MIN_TO_MSEC: + theResult = inTime * 60 * 1000; + break; + case CONVERT_SEC_TO_MSEC: + theResult = inTime * 1000; + break; + case CONVERT_MSEC_TO_MIN: + theResult = inTime / (60 * 1000); + break; + case CONVERT_MSEC_TO_SEC: + theResult = inTime / 1000; + break; + } + return theResult; +} + +//============================================================================== +/** + * TimeConversion: Takes in the time in mins:secs:msec and convert it to + * the corresponding time in msec. + * @param inMin stores the minutes to be converted. + * inSec stores the seconds to be converted. + * inMsec stores the milliseconds to be converted. + * inOperationCode determines the type of time conversion to be done on the + * inMin, inSec and inMsec. + * @return theResult stores the result of the time conversion. + */ +long CTimeEditDlg::TimeConversion(long inMin, long inSec, long inMsec, long inOperationCode) +{ + long theResult = 0; + switch (inOperationCode) { + case CONVERT_TIME_TO_MSEC: + theResult = TimeConversion(inMin, CONVERT_MIN_TO_MSEC) + + TimeConversion(inSec, CONVERT_SEC_TO_MSEC) + inMsec; + break; + } + return theResult; +} + +//============================================================================== +/** + * TimeConversion: Takes in the time in milliseconds and converts them + * to min : sec : msec. + * @param inTotalTime stores the total time in msec. + * ioMin stores the mins result of the time conversion + * ioSec stores the secs result of the time conversion + * ioMsec stores the msecs result of the time conversion + * inOperationCode determines the type of time conversion to be done on the + * inTotalTime. + * @return NONE + */ +void CTimeEditDlg::TimeConversion(long inTotalTime, long *ioMin, long *ioSec, long *ioMsec, + long inOperationCode) +{ + switch (inOperationCode) { + case CONVERT_MSEC_TO_MIN_SEC_MSEC: + *ioMin = TimeConversion(inTotalTime, CONVERT_MSEC_TO_MIN); + *ioSec = inTotalTime - TimeConversion(*ioMin, CONVERT_MIN_TO_MSEC); + *ioSec = TimeConversion(*ioSec, CONVERT_MSEC_TO_SEC); + *ioMsec = inTotalTime - TimeConversion(*ioMin, CONVERT_MIN_TO_MSEC) + - TimeConversion(*ioSec, CONVERT_SEC_TO_MSEC); + break; + } +} +//============================================================================== +/** + * UpdateObjectTime: It updates the playhead, keyframe or timebar time according + * to the time displayed in the time edit dialogue. + * @param inTime is the time that will be updated. + * @param startTime if true, updates the start time on the object, otherwise the end time + * @return NONE + */ +void CTimeEditDlg::UpdateObjectTime(long inTime, bool startTime) +{ + long theDiff = 0; + switch (m_ObjectAssociation) { + case PLAYHEAD: // Update the playhead time + if (m_Doc) { + m_Doc->NotifyTimeChanged(inTime); + m_Doc->NotifyTimeChanged(inTime); + } + break; + case ASSETKEYFRAME: // Update the keyframe time + if (m_Doc) { + theDiff = inTime - m_OffsetFromInitialTime - m_InitialTime1; + m_OffsetFromInitialTime = m_OffsetFromInitialTime + theDiff; + if (theDiff != 0 && m_KeyframesManager) { + m_KeyframesManager->OffsetSelectedKeyframes(theDiff); + } + } + break; + case TIMEBAR: // Update the timebar start/end time + if (m_Callback) { + if (startTime) // Update Start Time + m_Callback->ChangeStartTime(inTime); + else // Update End Time + m_Callback->ChangeEndTime(inTime); + } + break; + } +} + +//============================================================================== +/** The codes methods below are provides platform independent wrappers for + * User Interface. + */ +//============================================================================== + +/** + * OnEnChangeTimeEdit: Event triggered when the text in the 1st time edit box has + * been changed. + * @param NONE + * @return NONE + */ +void CTimeEditDlg::OnEnChangeTimeEdit1() +{ + // Making sure that the start time is not greater than the end time, when + // the user modifies the start time of the timebar + if (m_ObjectAssociation == TIMEBAR) { + m_MaxTimeDisplay = m_InitialTime2; // the initial end time + } + m_MinTimeDisplay = 0; + + const auto time = m_ui->startTimeEdit->time(); + long min = time.minute() + time.hour() * 60; + long sec = time.second(); + long msec = time.msec(); + TimeOverflowUnderflow(&min, &sec, &sec, m_MaxTimeDisplay, true); + TimeOverflowUnderflow(&min, &sec, &msec, m_MinTimeDisplay, false); + if (min != time.minute() || sec != time.second() || + msec != time.msec()) { + m_ui->startTimeEdit->setTime(QTime(0, min, sec, msec)); + } + m_ui->startTimeMin->setText(QString::number(min)); + m_ui->startTimeSec->setText(QString::number(sec)); + m_ui->startTimeMsec->setText(QString::number(msec)); + + long theGoToTime = TimeConversion(min, CONVERT_MIN_TO_MSEC) + + TimeConversion(sec, CONVERT_SEC_TO_MSEC) + msec; + // Go to the time specified in the time edit display + UpdateObjectTime(theGoToTime, true /*start time*/); +} + +//============================================================================== +/** + * OnEnChangeTimeEdit2: Event triggered when the text in the 2nd time edit box has + * been changed. + * @param NONE + * @return NONE + */ +void CTimeEditDlg::OnEnChangeTimeEdit2() +{ + // Let the end time of the time bar go as far as possible + if (m_ObjectAssociation == TIMEBAR) { + m_MaxTimeDisplay = m_MaxTime; + m_MinTimeDisplay = m_InitialTime1; // the initial start time + } + const auto time = m_ui->endTimeEdit->time(); + long min = time.minute() + time.hour() * 60; + long sec = time.second(); + long msec = time.msec(); + TimeOverflowUnderflow(&min, &sec, &sec, m_MaxTimeDisplay, true); + TimeOverflowUnderflow(&min, &sec, &msec, m_MinTimeDisplay, false); + if (min != time.minute() || sec != time.second() || + msec != time.msec()) { + m_ui->endTimeEdit->setTime(QTime(0, min, sec, msec)); + } + m_ui->endTimeMin->setText(QString::number(min)); + m_ui->endTimeSec->setText(QString::number(sec)); + m_ui->endTimeMsec->setText(QString::number(msec)); + + long theGoToTime = TimeConversion(min, CONVERT_MIN_TO_MSEC) + + TimeConversion(sec, CONVERT_SEC_TO_MSEC) + msec; + // Go to the time specified in the time edit display + UpdateObjectTime(theGoToTime, false /*end time*/); +} + + +//============================================================================== +/** + * HideUnnecessaryFields: Hides unused dialog items + * @param NONE + * @return NONE + */ +void CTimeEditDlg::HideUnnecessaryFields() +{ + m_ui->endTimeGroup->hide(); + m_ui->startTimeLabel->hide(); +} + diff --git a/src/Authoring/Studio/_Win/UI/TimeEditDlg.h b/src/Authoring/Studio/_Win/UI/TimeEditDlg.h new file mode 100644 index 00000000..7103dd3e --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/TimeEditDlg.h @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** 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_EDIT_DIALOG_H +#define INCLUDED_TIME_EDIT_DIALOG_H 1 + +//============================================================================== +// Includes +//============================================================================== +#include "Dialogs.h" +#include +#include + +//============================================================================== +// Forwards +//============================================================================== +class CTimebarControl; +class IDoc; +class ITimelineKeyframesManager; + +//============================================================================== +// Defines +//============================================================================== + +enum ECursorPosition { MIN_POSITION, SEC_POSITION, MSEC_POSITION }; + +enum ETimeFormat { MSEC, SEC_MSEC, MIN_SEC_MSEC }; + +enum ETimeConversionOperation { + CONVERT_MIN_TO_MSEC, + CONVERT_SEC_TO_MSEC, + CONVERT_MSEC_TO_MIN, + CONVERT_MSEC_TO_SEC, + CONVERT_TIME_TO_MSEC, + CONVERT_MSEC_TO_MIN_SEC_MSEC +}; + +enum ETimeEditBoxNumber { EDITBOX1, EDITBOX2 }; + +enum EObjectAssociation { + PLAYHEAD, + ASSETKEYFRAME, + TIMEBAR, +}; + +class ITimeChangeCallback +{ +public: + virtual ~ITimeChangeCallback() {} + virtual void ChangeStartTime(long) = 0; + virtual void ChangeEndTime(long) = 0; + virtual void Commit() = 0; + virtual void Rollback() = 0; +}; + +#ifdef QT_NAMESPACE +using namespace QT_NAMESPACE; +#endif + +QT_BEGIN_NAMESPACE +namespace Ui { + class TimeEditDlg; +} +QT_END_NAMESPACE + +// This class workaround the problem of QDateTimeEdit overwriting the selected section +// See https://bugreports.qt.io/browse/QTBUG-34759 +class CDateTimeEdit : public QDateTimeEdit +{ + Q_OBJECT +public: + using QDateTimeEdit::QDateTimeEdit; + +protected: + void focusInEvent(QFocusEvent *event) { + QDateTimeEdit::focusInEvent(event); + setSelectedSection(QDateTimeEdit::SecondSection); + } +}; + +//============================================================================== +/** + * CTimeEditDlg: It is a dialog box that allows user to specify the time that + * he/she wishes to go to. This dialog box can be activated by + * pressing Control G or clicking on the time edit box in the + * timeline. + */ +//============================================================================== +class CTimeEditDlg : public QDialog +{ + Q_OBJECT + +public: + CTimeEditDlg(QWidget *pParent = nullptr); // standard constructor + virtual ~CTimeEditDlg(); + void SetKeyframesManager(ITimelineKeyframesManager *inKeyframeManager); + void ShowDialog(long inTime1, long inTime2, IDoc *inDoc, long inObjectAssociation, + ITimeChangeCallback *inCallback = nullptr); + +public Q_SLOTS: + void accept() override; + void reject() override; + +protected: + void showEvent(QShowEvent *) override; + + // Generated message map functions + void OnInitDialog(); + void OnEnChangeTimeEdit1(); + void OnEnChangeTimeEdit2(); + + QString FormatTime(long inTime); + long CountDigits(long inNumber); + long TimeConversion(long inTime, long inOperationCode); + long TimeConversion(long inMin, long inSec, long inMsec, long inOperationCode); + void TimeConversion(long inTotalTime, long *ioMin, long *ioSec, long *ioMsec, + long inOperationCode); + void UpdateObjectTime(long inTime, bool startTime); + bool TimeOverflow(long *inMin, long *inSec, long *inMSec, long inTimeLimit); + bool TimeOverflowUnderflow(long *inMin, long *inSec, long *inMSec, long inTimeLimit, + bool inOverflowOrUnderflow); + void HideUnnecessaryFields(); + +protected: + QString m_MinString; + QString m_SecString; + QString m_MSecString; + QString m_TimeDisplay1; + QString m_TimeDisplay2; + long m_MaxTime; + long m_MaxTimeDisplay; + long m_MinTimeDisplay; + long m_InitialTime1; + long m_InitialTime2; + long m_MinOffset; + long m_SecOffset; + long m_MSecOffset; + long m_MinMinorOffset; + long m_SecMinorOffset; + long m_MSecMinorOffset; + long m_CursorPosition; + long m_TimeFormat; + long m_PreviousFormat; + double m_TimeInMins; + long m_NumberOfDigitsDrop; + long m_ColonPosition1; + long m_ColonPosition2; + long m_ObjectAssociation; + long m_OffsetFromInitialTime; + QString m_DTime; + QString m_DTimeDisplay; + long m_Time1; + long m_Time2; + IDoc *m_Doc; + ITimelineKeyframesManager *m_KeyframesManager; + + ITimeChangeCallback *m_Callback; + Ui::TimeEditDlg *m_ui; +}; +#endif // INCLUDED_TIME_EDIT_DIALOG_H diff --git a/src/Authoring/Studio/_Win/UI/timeeditdlg.ui b/src/Authoring/Studio/_Win/UI/timeeditdlg.ui new file mode 100644 index 00000000..f46cb1a2 --- /dev/null +++ b/src/Authoring/Studio/_Win/UI/timeeditdlg.ui @@ -0,0 +1,364 @@ + + + TimeEditDlg + + + + 0 + 0 + 371 + 274 + + + + Go To Time + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + QDateTimeEdit::SecondSection + + + hh:mm:ss:zzz + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + + : + + + + + + + 00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + : + + + + + + + sec + + + + + + + 00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + min + + + + + + + 000 + + + + + + + : + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + + Start Time + + + + + + + + + + + + + End Time + + + + + + + + + QDateTimeEdit::SecondSection + + + hh:mm:ss:zzz + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + + : + + + + + + + 00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + : + + + + + + + sec + + + + + + + 00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + min + + + + + + + 000 + + + + + + + : + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + CDateTimeEdit + QTimeEdit +
TimeEditDlg.h
+
+
+ + + + buttonBox + accepted() + TimeEditDlg + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + TimeEditDlg + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/src/Authoring/Studio/_Win/Utils/MouseCursor.cpp b/src/Authoring/Studio/_Win/Utils/MouseCursor.cpp new file mode 100644 index 00000000..9cd7328d --- /dev/null +++ b/src/Authoring/Studio/_Win/Utils/MouseCursor.cpp @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +// WIN32 VERSION + +//============================================================================= +// Prefix +//============================================================================= +#include "stdafx.h" + +//============================================================================= +// Includes +//============================================================================= +#include "MouseCursor.h" +#include +#include + +//#ifdef WIN32 +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_ARROW = 0; // IDC_ARROW +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_WAIT = 1; // IDC_WAIT +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_RESIZE_LEFTRIGHT = 2; // IDC_SIZEWE +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_RESIZE_UPDOWN = 3; // IDC_SIZENS +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_GROUP_MOVE = 4; // IDC_GROUP_MOVE +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_GROUP_ROTATE = 5; // IDC_GROUP_ROTATE +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_GROUP_SCALE = 6; // IDC_GROUP_SCALE +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_ITEM_MOVE = 7; // IDC_ITEM_MOVE +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_ITEM_ROTATE = 8; // IDC_ITEM_ROTATE +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_ITEM_SCALE = 9; // IDC_ITEM_SCALE +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_EDIT_CAMERA_PAN = + 10; // IDC_EDIT_CAMERA_PAN +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_EDIT_CAMERA_ROTATE = + 11; // IDC_EDIT_CAMERA_ROTATE +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_EDIT_CAMERA_ZOOM = + 12; // IDC_EDIT_CAMERA_ZOOM +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_BLANK = 13; // blank cursor +const CMouseCursor::TUICMouseCursor CMouseCursor::CURSOR_IBEAM = 14; + +//============================================================================= +/** + * Constructor + */ +CMouseCursor::CMouseCursor() + : m_IsThemeCursor(false) + , m_ThemeCursor(-1) +{ +} + +//============================================================================= +/** + * Destructor + */ +CMouseCursor::~CMouseCursor() +{ + Destroy(); +} + +//============================================================================= +/** + * @return A platform-specific handle to the cursor, or nullptr if no cursor has been loaded + */ +QCursor CMouseCursor::GetHandle() +{ + return m_Handle; +} + +//============================================================================= +/** + * If a cursor has been loaded, this function will change the current cursor + * to the newly loaded one. + */ +void CMouseCursor::Show() +{ + qWarning() << Q_FUNC_INFO << "QCursor doesn't work this way - set a breakpoint and debug caller"; +} + +//============================================================================= +/** +* Sets the cursor position +* @param inXPos x position of the cursor (in pixels) +* @param inYPos y position of the cursor (in pixels) +*/ +void CMouseCursor::SetCursorPos(long inXPos, long inYPos) +{ + QCursor::setPos(QPoint(inXPos, inYPos)); +} + +//============================================================================= +/** + * Releases the cursor if one has been loaded. Called by the destructor. + * WINDOWS IMPLEMENTATION + */ +void CMouseCursor::Destroy() +{ +} + +//============================================================================= +/** + * Loads the specified cursor resource. All cursors are expected to be + * resources that are loaded from ".cur" files. Some standard cursors are + * defined by the system and can be found in the MSDN (IDC_ARROW for example). + * WINDOWS IMPLEMENTATION + * + * @param inCursor ID of the cursor to be loaded + * @return true if the cursor was successfully loaded, otherwise false + */ +bool CMouseCursor::Load(TUICMouseCursor inCursor) +{ + // Convert from our cursors to Windows specific cursors + switch (inCursor) { + case CURSOR_ARROW: + m_Handle = Qt::ArrowCursor; + break; + + case CURSOR_WAIT: + m_Handle = Qt::WaitCursor; + break; + + case CURSOR_RESIZE_LEFTRIGHT: + m_Handle = Qt::SizeHorCursor; + break; + + case CURSOR_RESIZE_UPDOWN: + m_Handle = Qt::SizeVerCursor; + break; + + case CURSOR_GROUP_MOVE: + m_Handle = QCursor(QPixmap(":/cursors/group_move.png"), 0, 0); + break; + + case CURSOR_GROUP_ROTATE: + m_Handle = QCursor(QPixmap(":/cursors/group_rotate.png"), 0, 0); + break; + + case CURSOR_GROUP_SCALE: + m_Handle = QCursor(QPixmap(":/cursors/group_scale.png"), 0, 0); + break; + + case CURSOR_ITEM_MOVE: + m_Handle = QCursor(QPixmap(":/cursors/item_move.png"), 0, 0); + break; + + case CURSOR_ITEM_ROTATE: + m_Handle = QCursor(QPixmap(":/cursors/item_rotate.png"), 0, 0); + break; + + case CURSOR_ITEM_SCALE: + m_Handle = QCursor(QPixmap(":/cursors/item_scale.png"), 0, 0); + break; + + case CURSOR_EDIT_CAMERA_PAN: + m_Handle = QCursor(QPixmap(":/cursors/edit_camera_pan.png"), 10, 10); + break; + + case CURSOR_EDIT_CAMERA_ROTATE: + m_Handle = QCursor(QPixmap(":/cursors/edit_camera_rot.png"), 8, 10); + break; + + case CURSOR_EDIT_CAMERA_ZOOM: + m_Handle = QCursor(QPixmap(":/cursors/edit_camera_zoom.png"), 8, 8); + break; + + case CURSOR_BLANK: + m_Handle = Qt::BlankCursor; + break; + case CURSOR_IBEAM: + m_Handle = Qt::IBeamCursor; + break; + default: + m_Handle = QCursor(); + break; + } + return true; +} diff --git a/src/Authoring/Studio/_Win/Utils/WinUtils.cpp b/src/Authoring/Studio/_Win/Utils/WinUtils.cpp new file mode 100644 index 00000000..e159fa12 --- /dev/null +++ b/src/Authoring/Studio/_Win/Utils/WinUtils.cpp @@ -0,0 +1,600 @@ +/**************************************************************************** +** +** 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" + +#include "WinUtils.h" + +//============================================================================== +/** + * DrawBitmap + * + * Draw a bitmap given a device context, position and HBITMAP handle. + * + * @param inDC Device context for drawing + * @param inPos CPoint position for drawing + * @param inBitmap Handle of the bitmap to draw + */ +//============================================================================== +void CWinUtils::DrawBitmap(CDC *inDC, CPoint inPos, HBITMAP inBitmap) +{ + CDC theMemDC; + BITMAP theBitmapStruct; + CBitmap *theOldBitmap; + + if ((inDC != nullptr) && (inBitmap != nullptr)) { + GetObject(inBitmap, sizeof(BITMAP), &theBitmapStruct); + + theMemDC.CreateCompatibleDC(inDC); + theOldBitmap = theMemDC.SelectObject(CBitmap::FromHandle(inBitmap)); + + inDC->BitBlt(inPos.x, inPos.y, theBitmapStruct.bmWidth, theBitmapStruct.bmHeight, &theMemDC, + 0, 0, SRCCOPY); + + theMemDC.SelectObject(theOldBitmap); + theMemDC.DeleteDC(); + } +} + +//============================================================================== +/** + * DrawTransparentBitmap + * + * Draw a bitmap given a device context, position and HBITMAP handle using transparency + * + * @param inDC Device context for drawing + * @param inDestX Destination X position + * @param inDestY Destination Y position + * @param inBmp Bitmap for drawing + * @param inColorTransparent Transparent color + * @param inWidth Destination width + * @param inHeight Destination height + * @param inSourceX Source X position + * @param inSourceY Source Y position + */ +//============================================================================== +void CWinUtils::DrawTransparentBitmap(CDC *inDC, long inDestX, long inDestY, HBITMAP inBmp, + COLORREF inColorTransparent, long inWidth, long inHeight, + long inSourceX, long inSourceY) +{ + CDC theMemDC; + BITMAP theBitmap; + CBitmap *theOldBmp; + + GetObject(inBmp, sizeof(BITMAP), &theBitmap); + + if (inWidth == -1) + inWidth = theBitmap.bmWidth; + if (inHeight == -1) + inHeight = theBitmap.bmHeight; + + theMemDC.CreateCompatibleDC(inDC); + theOldBmp = theMemDC.SelectObject(CBitmap::FromHandle(inBmp)); + + TransparentBltExt(inDC->m_hDC, inDestX, inDestY, inWidth, inHeight, theMemDC.m_hDC, inSourceX, + inSourceY, inWidth, inHeight, inColorTransparent); + + theMemDC.SelectObject(theOldBmp); + theMemDC.DeleteDC(); +} + +//============================================================================== +/** + * TransparentBltExt + * + * Draw a bitmap given a device context, position and HBITMAP handle using transparency + * + * @param inDC Device context for drawing + * @param inDestX Destination X position + * @param inDestY Destination Y position + * @param inBmp Bitmap for drawing + * @param inColorTransparent Transparent color + * @param inWidth Destination width + * @param inHeight Destination height + * @param inSourceX Source X position + * @param inSourceY Source Y position + */ +//============================================================================== +BOOL CWinUtils::TransparentBltExt(HDC inDCDest, long inXOriginDest, long inYOriginDest, + long inWidthDest, long inHeightDest, HDC inDCSrc, + long inXOriginSrc, long inYOriginSrc, long inWidthSrc, + long inHeightSrc, UINT inColorTransparent) +{ + if ((inWidthDest < 1) || (inWidthSrc < 1) || (inHeightDest < 1) || (inHeightSrc < 1)) + return FALSE; + + HDC theDC, theMaskDC; + HDC theNewMaskDC; + HBITMAP theBmp, theOldBmp, theMaskBmp, theOldMask; + HBITMAP theNewMask; + + theDC = CreateCompatibleDC(nullptr); + theBmp = CreateBitmap(inWidthSrc, inHeightSrc, 1, GetDeviceCaps(theDC, BITSPIXEL), nullptr); + + if (theBmp == nullptr) { + DeleteDC(theDC); + return FALSE; + } + + theOldBmp = (HBITMAP)SelectObject(theDC, theBmp); + + if (!BitBlt(theDC, 0, 0, inWidthSrc, inHeightSrc, inDCSrc, inXOriginSrc, inYOriginSrc, + SRCCOPY)) { + SelectObject(theDC, theOldBmp); + DeleteObject(theBmp); + DeleteDC(theDC); + return FALSE; + } + + theMaskDC = CreateCompatibleDC(nullptr); + theMaskBmp = CreateBitmap(inWidthSrc, inHeightSrc, 1, 1, nullptr); + + if (theMaskBmp == nullptr) { + SelectObject(theDC, theOldBmp); + DeleteObject(theBmp); + DeleteDC(theDC); + DeleteDC(theMaskDC); + return FALSE; + } + + theOldMask = (HBITMAP)SelectObject(theMaskDC, theMaskBmp); + SetBkColor(theMaskDC, RGB(0x00, 0x00, 0x00)); + SetTextColor(theMaskDC, RGB(0xFF, 0xFF, 0xFF)); + + if (!BitBlt(theMaskDC, 0, 0, inWidthSrc, inHeightSrc, nullptr, 0, 0, BLACKNESS)) { + SelectObject(theMaskDC, theOldMask); + DeleteObject(theMaskBmp); + DeleteDC(theMaskDC); + SelectObject(theDC, theOldBmp); + DeleteObject(theBmp); + DeleteDC(theDC); + return FALSE; + } + + SetBkColor(theDC, inColorTransparent); + BitBlt(theMaskDC, 0, 0, inWidthSrc, inHeightSrc, theDC, 0, 0, SRCINVERT); + + SetBkColor(theDC, RGB(0x00, 0x00, 0x00)); + SetTextColor(theDC, RGB(0xFF, 0xFF, 0xFF)); + BitBlt(theDC, 0, 0, inWidthSrc, inHeightSrc, theMaskDC, 0, 0, SRCAND); + + theNewMaskDC = CreateCompatibleDC(nullptr); + theNewMask = + CreateBitmap(inWidthDest, inHeightDest, 1, GetDeviceCaps(theNewMaskDC, BITSPIXEL), nullptr); + if (theNewMask == nullptr) { + SelectObject(theDC, theOldBmp); + DeleteDC(theDC); + SelectObject(theMaskDC, theOldMask); + DeleteDC(theMaskDC); + DeleteDC(theNewMaskDC); + DeleteObject(theBmp); + DeleteObject(theMaskBmp); + return FALSE; + } + + SetStretchBltMode(theNewMaskDC, COLORONCOLOR); + HBITMAP theOldNewMask = (HBITMAP)SelectObject(theNewMaskDC, theNewMask); + StretchBlt(theNewMaskDC, 0, 0, inWidthDest, inHeightDest, theMaskDC, 0, 0, inWidthSrc, + inHeightSrc, SRCCOPY); + + SelectObject(theMaskDC, theOldMask); + DeleteDC(theMaskDC); + DeleteObject(theMaskBmp); + + HDC theNewImageDC = CreateCompatibleDC(nullptr); + HBITMAP theNewImage = + CreateBitmap(inWidthDest, inHeightDest, 1, GetDeviceCaps(theNewMaskDC, BITSPIXEL), nullptr); + if (theNewImage == nullptr) { + SelectObject(theDC, theOldBmp); + DeleteDC(theDC); + DeleteDC(theNewMaskDC); + DeleteObject(theBmp); + return FALSE; + } + + HBITMAP theOldNewImage = (HBITMAP)SelectObject(theNewImageDC, theNewImage); + StretchBlt(theNewImageDC, 0, 0, inWidthDest, inHeightDest, theDC, 0, 0, inWidthSrc, inHeightSrc, + SRCCOPY); + + SelectObject(theDC, theOldBmp); + DeleteDC(theDC); + DeleteObject(theBmp); + + // Finally, do the final blitting to get the image to the destination device context. + BitBlt(inDCDest, inXOriginDest, inYOriginDest, inWidthDest, inHeightDest, theNewMaskDC, 0, 0, + SRCAND); + BitBlt(inDCDest, inXOriginDest, inYOriginDest, inWidthDest, inHeightDest, theNewImageDC, 0, 0, + SRCPAINT); + + SelectObject(theNewImageDC, theOldNewImage); + DeleteDC(theNewImageDC); + SelectObject(theNewMaskDC, theOldNewMask); + DeleteDC(theNewMaskDC); + DeleteObject(theNewImage); + DeleteObject(theNewMask); + + return TRUE; +} + +//============================================================================== +/** + * DrawAlphaBlendBitmap + * + * Draw a bitmap given a device context, position and HBITMAP handle using + * alpha blending and transparency. + * + * @param inDC Device context for drawing + * @param inDestX Destination X position + * @param inDestY Destination Y position + * @param inBmp Bitmap for drawing + * @param inColorTransparent Transparent color + * @param inWidth Destination width + * @param inHeight Destination height + * @param inSourceX Source X position + * @param inSourceY Source Y position + */ +//============================================================================== +void CWinUtils::DrawAlphaBlendBitmap(CDC *inDC, short inDestX, short inDestY, HBITMAP inBmp, + short inWidth, short inHeight, short inSourceX, + short inSourceY, short inAlpha, BOOL inTransparentFlag, + COLORREF inColorTransparent) +{ + Q_UNUSED(inColorTransparent); + + CDC theMemDC; + BITMAP theBitmap; + CBitmap *theOldBmp; + short theWidth = inWidth; + short theHeight = inHeight; + + COLORREF theBackColor; + + // Get the size of the bitmap. + GetObject(inBmp, sizeof(BITMAP), &theBitmap); + + if (inWidth == -1) + theWidth = (short)theBitmap.bmWidth; + if (inHeight == -1) + theHeight = (short)theBitmap.bmHeight; + + theMemDC.CreateCompatibleDC(inDC); + theOldBmp = theMemDC.SelectObject(CBitmap::FromHandle(inBmp)); + + if (inTransparentFlag) { + // Get the current background pixel at 0,0 + theBackColor = theMemDC.GetPixel(0, 0); + + // Create a fill brush and select into the device context + CBrush theFillBrush(inColorTransparent); + CBrush *theOldFillBrush; + + // Fill to replace the existing background color with the replacement color. + theOldFillBrush = theMemDC.SelectObject(&theFillBrush); + theMemDC.ExtFloodFill(0, 0, theBackColor, FLOODFILLSURFACE); + theMemDC.ExtFloodFill(theWidth - 1, 0, theBackColor, FLOODFILLSURFACE); + theMemDC.ExtFloodFill(theWidth - 1, theHeight - 1, theBackColor, FLOODFILLSURFACE); + theMemDC.ExtFloodFill(0, theHeight - 1, theBackColor, FLOODFILLSURFACE); + theMemDC.SelectObject(theOldFillBrush); + } + + // Draw the alpha-blended image. + AlphaBlendExt(inDC->m_hDC, inDestX, inDestY, theWidth, theHeight, theMemDC.m_hDC, inSourceX, + inSourceY, theWidth, theHeight, inAlpha); + + theMemDC.SelectObject(theOldBmp); + theMemDC.DeleteDC(); +} + +//============================================================================== +/** + * AlphaBlendExt + * + * Draws a bitmap using alpha blending. Works in NT/2000/9x + * + * @param inDCDest Destination device context + * @param inX X coordinate for drawing + * @param inY Y coordinate for drawing + * @param inWidth Drawing width + * @param inHeight Drawing height + * @param inDCSrc Source device context + * @param inSourceX X source coordinate + * @param inSourceY Y source coordinate + * @param inSourceWidth Source drawing width + * @param inSourceHeight Source drawing height + * @param inAlpha Alpha blend: 0-255, where 255 is opaque + */ +//============================================================================== +BOOL CWinUtils::AlphaBlendExt(HDC inDCDest, short inX, short inY, short inWidth, short inHeight, + HDC inDCSrc, short inSourceX, short inSourceY, short inSourceWidth, + short inSourceHeight, short inAlpha) +{ + BITMAPINFOHEADER theBMI; + + theBMI.biSize = sizeof(BITMAPINFOHEADER); + theBMI.biWidth = inWidth; + theBMI.biHeight = inHeight; + theBMI.biPlanes = 1; + theBMI.biBitCount = 32; // 24 bits + alpha channel + theBMI.biCompression = BI_RGB; // no compression + theBMI.biSizeImage = 0; + theBMI.biXPelsPerMeter = 0; + theBMI.biYPelsPerMeter = 0; + theBMI.biClrUsed = 0; // use the whole palette + theBMI.biClrImportant = 0; + + BYTE *theSrcBits; + HBITMAP theBmpSrc; + + // Create DIB section in shared memory + theBmpSrc = CreateDIBSection(inDCSrc, (BITMAPINFO *)&theBMI, DIB_RGB_COLORS, + (void **)&theSrcBits, 0, 0L); + + BYTE *theDestBits; + HBITMAP theBmpDest; + + // Create DIB section in shared memory + theBmpDest = CreateDIBSection(inDCDest, (BITMAPINFO *)&theBMI, DIB_RGB_COLORS, + (void **)&theDestBits, 0, 0L); + + // Copy our source and destination bitmaps onto our DIBSections. + // so we can get access to their bits using the BYTE*'s we used + // in the CreateDIBSection()s above. + + HDC theDC = CreateCompatibleDC(nullptr); + HBITMAP theDCOld = (HBITMAP)SelectObject(theDC, theBmpSrc); + + if (!StretchBlt(theDC, 0, 0, inWidth, inHeight, inDCSrc, inSourceX, inSourceY, inSourceWidth, + inSourceHeight, SRCCOPY)) { + SelectObject(theDC, theDCOld); + DeleteDC(theDC); + DeleteObject(theBmpSrc); + DeleteObject(theBmpDest); + return FALSE; + } + + SelectObject(theDC, theBmpDest); + + if (!StretchBlt(theDC, 0, 0, inWidth, inHeight, inDCDest, inX, inY, inWidth, inHeight, + SRCCOPY)) { + SelectObject(theDC, theDCOld); + DeleteDC(theDC); + DeleteObject(theBmpSrc); + DeleteObject(theBmpDest); + return FALSE; + } + + SelectObject(theDC, theDCOld); + DeleteDC(theDC); + + short theXLoop, theYLoop; + + for (theYLoop = 0; theYLoop < inHeight; ++theYLoop) { + LPBYTE theDestRGB = (LPBYTE) & ((DWORD *)theDestBits)[theYLoop * inWidth]; + LPBYTE theSrcRGB = (LPBYTE) & ((DWORD *)theSrcBits)[theYLoop * inWidth]; + + for (theXLoop = 0; theXLoop < inWidth; theXLoop++) { + theSrcRGB[0] = (BYTE)((theDestRGB[0] * (255 - inAlpha) + theSrcRGB[0] * inAlpha) >> 8); + theSrcRGB[1] = (BYTE)((theDestRGB[1] * (255 - inAlpha) + theSrcRGB[1] * inAlpha) >> 8); + theSrcRGB[2] = (BYTE)((theDestRGB[2] * (255 - inAlpha) + theSrcRGB[2] * inAlpha) >> 8); + + theSrcRGB += 4; + theDestRGB += 4; + } + } + + theDC = CreateCompatibleDC(nullptr); + + theDCOld = (HBITMAP)SelectObject(theDC, theBmpSrc); + + if (!BitBlt(inDCDest, inX, inY, inWidth, inHeight, theDC, 0, 0, SRCCOPY)) { + SelectObject(theDC, theDCOld); + DeleteDC(theDC); + DeleteObject(theBmpSrc); + DeleteObject(theBmpDest); + return FALSE; + } + + SelectObject(theDC, theDCOld); + DeleteDC(theDC); + + DeleteObject(theBmpSrc); + DeleteObject(theBmpDest); + + return TRUE; +} + +//============================================================================== +/** + * GetStudioLogFont: Fill a LOGFONT structure with the default font information for Studio + *objects. + * + * Create a LOGFONT structure with data used by the various palettes and controls in Studio. + * + * @param outLogFont LOGFONT structure returned by this function. + */ +//============================================================================== +void CWinUtils::GetStudioLogFont(LOGFONT &outLogFont) +{ + // Create the default Studio font - specified in string table so that it can be changed for + // different languages + memset(&outLogFont, 0, sizeof(LOGFONT)); + CString theFontSize = ::LoadResourceString(IDS_STUDIOFONT_SIZE); + CString theFontFace = L"SegoeUI"; + outLogFont.lfHeight = _wtoi(theFontSize); + wcscpy(outLogFont.lfFaceName, theFontFace); + // Make sure that you set the character set to the system default or your strings won't be + // localizable + outLogFont.lfCharSet = DEFAULT_CHARSET; +} + +//============================================================================= +/** + * Copy the contents of a File into an Archive. + * This will read the entire file into the archive. + * The file should exist already. + * @param inFilename the name of the file to read in. + * @param inDestination the destination archive for the data. + */ +//============================================================================= +void CWinUtils::CopyFileToArchive(CString inFilename, CArchive &inDestination) +{ + CFile theFile(inFilename, CFile::modeRead); + + unsigned long theLength = (unsigned long)theFile.GetLength(); + unsigned long theBufferSize = 1024; + while (theBufferSize < theLength / 10 && theBufferSize < 1e6) + theBufferSize *= 2; // double until we have a buffer that is about %10 of file size + char *theBuffer = new char[theBufferSize]; + + unsigned long theReadCount = theBufferSize; + unsigned long theTotalReadCount = 0; + + // Loop around reading the file in chunks + while (theTotalReadCount < theLength) { + if (theLength - theTotalReadCount < theReadCount) + theReadCount = theLength - theTotalReadCount; + + theFile.Read(theBuffer, theReadCount); + inDestination.Write(theBuffer, theReadCount); + + theTotalReadCount += theReadCount; + } + + theFile.Close(); + delete[] theBuffer; +} + +//============================================================================= +/** + * Copy the contents of an Archive into a File. + * If the file does not exist it will be created. If it does exist it will be + * cleared. + * @param inArchive the source of the data for the file. + * @param inDestination the file the data is to be written to. + * @param inLength the amount of data to copy to the file. + */ +//============================================================================= +void CWinUtils::CopyArchiveToFile(CArchive &inArchive, CString inDestination, + unsigned long inLength) +{ + CFile theFile(inDestination, CFile::modeWrite | CFile::modeCreate); + + unsigned long theBufferSize = 1024; + while (theBufferSize < inLength / 10 && theBufferSize < 1e6) + theBufferSize *= 2; // double until we have a buffer that is about %10 of file size + char *theBuffer = new char[theBufferSize]; + + unsigned long theLength = inLength; + unsigned long theReadCount = theBufferSize; + unsigned long theTotalReadCount = 0; + + // Loop around reading from the archive and writing to the file. + while (theTotalReadCount < theLength) { + if (theLength - theTotalReadCount < theReadCount) + theReadCount = theLength - theTotalReadCount; + + inArchive.Read(theBuffer, theReadCount); + theFile.Write(theBuffer, theReadCount); + + theTotalReadCount += theReadCount; + } + theFile.Close(); + delete[] theBuffer; +} + +//============================================================================= +/** + * Used for StringToInt64 to avoid double errors in math.h's pow( ). + * + * @param inNumber Base number + * @param inPower Power to raise the base + * + * @return Result of x^y + */ +//============================================================================= +unsigned __int64 CWinUtils::RaisePower(unsigned __int64 inNumber, unsigned long inPower) +{ + if (inPower == 0) + return 1; + return inNumber * RaisePower(inNumber, inPower - 1); +} + +//============================================================================= +/** + * Parse the string into an __int64. + * + * @param inString the string to parse. + * @param inStringLen the length of the string. + * @param inBase the base of the character encoding (16 is Hex, 10 is decimal). + * + * @return +#include +#include + +#include + +//============================================================================= +/** + * Constructor + * @param inShowGUI true if dialogs should be displayed or piped to std:cout instead + */ +CDialogs::CDialogs(bool inShowGUI /*= true*/) +#ifdef KDAB_TEMPORARILY_REMOVED + : m_ProgressPalette(nullptr) + , m_ShowGUI(inShowGUI) + , m_LastSaveFile(CUICFile::GetApplicationDirectory().GetAbsolutePath()) +#endif +{ +} + +//============================================================================= +/** + * Destructor + */ +CDialogs::~CDialogs() +{ +} + +//============================================================================= +/** + * Displays a multiline text edit. + * @param ioText + * @param inNotification + */ +#if 0 +void CDialogs::DisplayMultilineTextEdit(Q3DStudio::CString &ioText, + CMultilineEditDlg::INotification *inNotifiction) +{ + CRct theLocation = CStudioPreferences::GetMultilineTextLocation(); + + CMultilineEditDlg theMultilineEditDlg(inNotifiction, theLocation); + theMultilineEditDlg.SetString(ioText); + if (theMultilineEditDlg.DoModal() == IDOK) { + // Set the string + ioText = theMultilineEditDlg.GetString(); + + // Save the window position + theLocation = theMultilineEditDlg.GetLocation(); + CStudioPreferences::SetMultilineTextLocation(theLocation); + } +} +#endif + +//============================================================================= +/** + * Displays a dialog asking the user to choose the keyframe interpolation. + * + * @param ioEaseIn value to be set as the ease in default - passes back the value chosen by the user + * @param ioEaseOut value to be set as the ease out default - passes back the value chosen by the + * user + * @return true if the user clicked OK on the dialog (indicating that the values should be updated + * on the track) + */ +bool CDialogs::PromptForKeyframeInterpolation(float &ioEaseIn, float &ioEaseOut) +{ + bool theReturnValue = false; + + CInterpolationDlg theInterpolationDialog; + theInterpolationDialog.setEaseIn(ioEaseIn); + theInterpolationDialog.setEaseOut(ioEaseOut); + + // If the user presses the OK button + if (theInterpolationDialog.exec() == QDialog::Accepted) { + // Retrieve the new interpolation values + ioEaseIn = theInterpolationDialog.easeIn(); + ioEaseOut = theInterpolationDialog.easeOut(); + theReturnValue = true; + } + + return theReturnValue; +} + +//============================================================================= +/** + * Notify the user that the deletion of an asset has failed. + */ +void CDialogs::DisplayAssetDeleteFailed() +{ + Q3DStudio::CString theMessage = + ::LoadResourceString(IDS_ERROR_CLIENTSAVE); // TODO: Should display the correct string + Q3DStudio::CString theTitle = ::LoadResourceString(IDS_ERROR_MSGTITLE); + + if (m_ShowGUI) + CUICMessageBox::Show(theTitle, theMessage, CUICMessageBox::ICON_ERROR, false, + qApp->activeWindow()); + else { + std::cout << theTitle.GetCharStar() << ": " << theMessage.GetCharStar() << std::endl; + } +} + +//============================================================================= +/** + * Get the export choice. + */ +CUICFile CDialogs::GetExportChoice(const Q3DStudio::CString &, const Q3DStudio::CString &) +{ + // Need to fix this for windows if we decide to use it + return CUICFile("", false, false); +} + +//============================================================================== +/** + * Notify that we are unable to refresh the resource. + */ +void CDialogs::DisplayRefreshResourceFailed(const Q3DStudio::CString &inResourceName, + const Q3DStudio::CString &inDescription) +{ + Q3DStudio::CString theTitle(::LoadResourceString(IDS_ERROR_REFRESHRESOURCETITLE)); + + Q3DStudio::CString theText; + theText.Format(::LoadResourceString(IDS_ERROR_REFRESHRESOURCETEXT), + static_cast(inResourceName)); + + if (!inDescription.IsEmpty()) + theText += inDescription; + + if (m_ShowGUI) + CUICMessageBox::Show(theTitle, theText, CUICMessageBox::ICON_WARNING, false, + qApp->activeWindow()); + else { + std::cout << theTitle.GetCharStar() << ": " << theText.GetCharStar() << std::endl << std::endl; + } +} + +//============================================================================= +/** + * Notify the user that the loading of the requested resource failed. + * + * Possible failed import messages are: + * IDS_ERROR_IMPORTLUARESOURCETEXT - Sorry - Studio was unable to + *import the LUA script.\nPlease check the file and try again.\nNote that LUA files must be + *syntactically correct to be importable. + * IDS_ERROR_IMPORTRESOURCETEXT - Sorry - Studio was unable to + *import the resource.\nPlease check the above file and try again. + * IDS_ERROR_IMPORTUNSUPPORTEDRESOURCETYPETEXT - Sorry - Studio was unable to import + *the resource file.\nThis resource file type is not currently supported by Studio.\n + * + * @param inURL the URL for the asset that was to have been imported + * @param inErrorDescription description for the failure, if any + * @param inWarningsOnly not a failure, just warnings + */ +void CDialogs::DisplayImportFailed(const QUrl &inURL, const QString &inDescription, + bool inWarningsOnly) +{ + // Notify the user we couldn't load the resource. + Q3DStudio::CString theTitle, theText, theMsgText; + + theTitle = ::LoadResourceString(IDS_ERROR_IMPORTRESOURCETITLE); + // specify if its an error or warning + theTitle = (!inWarningsOnly) ? ::LoadResourceString(IDS_ERROR_IMPORTRESOURCETITLE_ERROR) + : ::LoadResourceString(IDS_ERROR_IMPORTRESOURCETITLE_WARNING); + + // Determine the asset type + EStudioObjectType theAssetType = + Q3DStudio::ImportUtils::GetObjectFileTypeForFile(inURL.path(), false) + .m_ObjectType; + + bool theIsStudioObject = theAssetType != OBJTYPE_UNKNOWN; + + // Is this a LUA file, but perhaps incorrectly formatted? + if (theAssetType == OBJTYPE_BEHAVIOR) { + // Load the message about the LUA format + if (inWarningsOnly) + theText = ::LoadResourceString(IDS_WARNING_IMPORTLUARESOURCETEXT); + else + theText = ::LoadResourceString(IDS_ERROR_IMPORTLUARESOURCETEXT); + if (!inDescription.isEmpty()) { + theText += L"\n"; + theText += Q3DStudio::CString::fromQString(inDescription); + } + } else if (theAssetType != OBJTYPE_UNKNOWN || theIsStudioObject) { + // Valid registered file type, but invalid file + + bool theNoDescription = inDescription.isEmpty(); + // Load default text stating that the import resource failed. + // descriptions if present are presented as "reasons" for failure. + if (!inWarningsOnly || theNoDescription) { + theText.Format(::LoadResourceString(IDS_ERROR_IMPORTRESOURCETEXT), theNoDescription + ? L"." + : ::LoadResourceString(IDS_ERROR_IMPORTRESOURCETEXT_REASON).c_str()); + theText += "\n"; + } + if (!theNoDescription) + theText += Q3DStudio::CString::fromQString(inDescription); + else + theText += ::LoadResourceString(IDS_ERROR_IMPORTRESOURCETEXT_CHECKFILE); + } else { + // Display the warning messsage if we have one + // instead of a meaningless message. This provides more feed back + if (!inDescription.isEmpty()) + theText += Q3DStudio::CString::fromQString(inDescription); + else + theText = ::LoadResourceString( + IDS_ERROR_IMPORTUNSUPPORTEDRESOURCETYPETEXT); // Load default text stating that the + // import resource failed. + } + + Q3DStudio::CString theFormatString( + !inWarningsOnly ? ::LoadResourceString(IDS_ERROR_IMPORTRESOURCETEXT_FAILED) + : ::LoadResourceString(IDS_ERROR_IMPORTRESOURCETEXT_COMPLETEWITHWARNING)); + theFormatString += _UIC("\n%ls\n\n"); + std::wstring wstr = inURL.path().toStdWString(); + theMsgText.Format(theFormatString, static_cast(wstr.c_str())); + theMsgText += theText; + + // Display the failed import resource message. + if (m_ShowGUI) + CUICMessageBox::Show(theTitle, theMsgText, CUICMessageBox::ICON_WARNING, false, + qApp->activeWindow()); + else { + std::cout << theTitle.GetCharStar() << ": " << theMsgText.GetCharStar() << std::endl; + } +} + +namespace { + +inline Q3DStudio::CString CreateExtensionsList(const char **extList) +{ + Q3DStudio::CString retval; + for (const char **ext = extList; *ext != nullptr; ++ext) { + if (retval.Length()) + retval += " "; + retval += Q3DStudio::CString("*.") + *ext; + } + return retval; +} + +struct SAllowedTypesEntry +{ + Q3DStudio::DocumentEditorFileType::Enum m_FileType; + long m_ResourceStringId; // Model Files, Image Files, etc + const char **m_FileExtensions; +}; +const char *imgExts[] = { + "png", "jpg", "jpeg", "dds", "bmp", "gif", "hdr", nullptr, +}; +const wchar_t *wideImgExts[] = { + L"png", L"jpg", L"jpeg", L"dds", L"bmp", L"gif", L"hdr", nullptr, +}; +const char *modelExts[] = { + CDialogs::GetDAEFileExtension(), +#ifdef QT_3DSTUDIO_FBX + CDialogs::GetFbxFileExtension(), +#endif + // TODO CDialogs::GetImportFileExtension(), + // TODO CDialogs::GetMeshFileExtension(), + nullptr, +}; +const char *meshExts[] = { + CDialogs::GetMeshFileExtension(), nullptr, +}; +const char *importExts[] = { + CDialogs::GetImportFileExtension(), nullptr, +}; +const char *behaviorExts[] = { + CDialogs::GetLUAFileExtension(), nullptr, +}; +const char *fontExts[] = { + "ttf", "otf", nullptr, +}; +const wchar_t *wideFontExts[] = { + L"ttf", L"otf", nullptr, +}; +const char *effectExts[] = { + "effect", nullptr, +}; +const wchar_t *wideEffectExts[] = { + L"effect", nullptr, +}; +const char *materialExts[] = { + "material", nullptr, +}; +const wchar_t *wideMaterialExts[] = { + L"material", nullptr, +}; +const char *soundExts[] = { + "wav", nullptr, +}; +const wchar_t *wideSoundExts[] = { + L"wav", nullptr, +}; + +// List of file types allowed during import +SAllowedTypesEntry g_AllowedImportTypes[] = { + { Q3DStudio::DocumentEditorFileType::DAE, IDS_LIBRARYIMPORT_MODEL, modelExts }, +#ifdef QT_3DSTUDIO_FBX + { Q3DStudio::DocumentEditorFileType::FBX, IDS_LIBRARYIMPORT_MODEL, modelExts }, +#endif +}; +size_t g_NumAllowedImportTypes = sizeof(g_AllowedImportTypes) / sizeof(*g_AllowedImportTypes); + +// List of file types allowed for file references +SAllowedTypesEntry g_AllowedFileReferencesTypes[] = { + { Q3DStudio::DocumentEditorFileType::Image, IDS_LIBRARYIMPORT_IMAGE, imgExts }, + { Q3DStudio::DocumentEditorFileType::Behavior, IDS_LIBRARYIMPORT_BEHAVIOR, behaviorExts }, + { Q3DStudio::DocumentEditorFileType::Mesh, IDS_LIBRARYIMPORT_MESH, meshExts }, + { Q3DStudio::DocumentEditorFileType::Import, IDS_LIBRARYIMPORT_IMPORT, importExts }, + { Q3DStudio::DocumentEditorFileType::Effect, IDS_LIBRARYIMPORT_EFFECT, effectExts }, +}; +size_t g_NumAllowedFileReferencesTypes = + sizeof(g_AllowedFileReferencesTypes) / sizeof(*g_AllowedFileReferencesTypes); +} + +QString CDialogs::ConfirmRefreshModelFile(const QString &inFile) +{ + // this produces an extension string which contains all allowed formats specified in + // g_AllowedImportTypes + // currently DAE and FBX + QString theFileFilter = + CreateAllowedTypesString(Q3DStudio::DocumentEditorFileType::DAE, true); + + + return QFileDialog::getOpenFileName(qApp->activeWindow(), QObject::tr("Open"), + inFile, theFileFilter); +} + +//============================================================================== +/** + * Allows the user to select/confirm the file to fix broken file reference. + * This method opens a file dialog to the specified location, and allows the user to + * accept, or select a different file. + * @param outFile The output path + * @param inFileType The file type filter for the dialog. + * @return true If the user accepted the file, false if the user canceled. + */ +bool CDialogs::LocateFileReference(CUICFile &outFile, long inFileType) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + Q3DStudio::CString theFileFilter = CreateAllowedTypesString(inFileType, false); + + bool theResult = false; + + // Open the dialog. + CFileDialogEx theFileDialog(TRUE, nullptr, nullptr, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, + theFileFilter, nullptr); + + // Set the initial directory to document path's directory (it should exist). + CUICFile theDocumentFile(g_StudioApp.GetCore()->GetDoc()->GetDocumentPath()); + Q3DStudio::CFilePath theInitDir = + Q3DStudio::CFilePath(theDocumentFile.GetAbsolutePath()).GetDirectory(); + theFileDialog.SetInitialDirectory(theInitDir); + + // Set the title of the dialog + theFileDialog.SetWindowTitle(::LoadResourceString(IDS_PROJECT_CM_LOCATE_FILE)); + + INT_PTR refreshResult = theFileDialog.DoModal(); + + if (refreshResult == IDOK) { + Q3DStudio::CString thePath = theFileDialog.GetPathName(); + Q3DStudio::CString theName = theFileDialog.GetFileName(); + outFile = CUICFile(thePath, theName); + + // The user has accepted this file. + theResult = true; + } + + return theResult; +#endif + return false; +} + +//============================================================================== +/** + * Allows the user to select/confirm the folder to fix broken folder reference. + * This method opens a folder dialog to the specified location, and allows the user to + * accept, or select a different folder. + * @param outFile The output path + * @return true If the user accepted the file, false if the user canceled. + */ +bool CDialogs::LocateFolderReference(CUICFile &outFile) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + // Set the initial directory to document path's directory (it should exist). + CUICFile theDocumentFile(g_StudioApp.GetCore()->GetDoc()->GetDocumentPath()); + Q3DStudio::CFilePath theInitDir = + Q3DStudio::CFilePath(theDocumentFile.GetAbsolutePath()).GetDirectory(); + + // Set the title of the dialog + Q3DStudio::CString theDialogTitle(::LoadResourceString(IDS_PROJECT_CM_LOCATE_FOLDER)); + + return BrowseForFolderDialog(outFile, theInitDir, theDialogTitle); +#endif + return false; +} + +//============================================================================== +/** + * BrowseCallbackProc: Handles the callback proc for SHBrowseForFolder() + * + * Handles selecting the correct path when the SHBrowseForFolder dialog is + * initially displayed. + */ +#ifdef KDAB_TEMPORARILY_REMOVED +static int CALLBACK BrowseCallbackProc(HWND inHwnd, UINT inMsg, LPARAM /*inlParam*/, + LPARAM inlpData) +{ + switch (inMsg) { + case BFFM_INITIALIZED: + // Indicates the browse dialog box has finished initializing. The lParam value is zero. + if (inlpData != nullptr) { + // Do so by sendint the BFFM_SETSELECTION message to the inHwnd: + // Selects the specified folder. To use a PIDL to specify the folder, set the + // message's lParam to the PIDL, and set wParam to FALSE. To specify the folder's + // path, set the message's lParam value to point to a nullptr-terminated string with + // the path, and set wParam to TRUE. + + SendMessage(inHwnd, BFFM_SETSELECTION, (WPARAM)TRUE, (LPARAM)inlpData); + } + break; + + default: + break; + } + + return 0; +} +#endif + +//============================================================================== +/** + * Show browse for folder dialog + * @param outFile The output path + * @param inDefaultDir The default directory + * @param inDialogTitle The title of the dialog + * @return true If the user accepted the file, false if the user canceled. + */ +bool CDialogs::BrowseForFolderDialog(CUICFile &outFile, Q3DStudio::CString inDefaultDir, + Q3DStudio::CString inDialogTitle) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + bool theResult = false; + BROWSEINFO theInfo = { 0 }; + TCHAR theDispName[MAX_PATH] = { '\0' }; + + theInfo.pszDisplayName = theDispName; + theInfo.lpszTitle = inDialogTitle; + theInfo.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS | BIF_NONEWFOLDERBUTTON; + theInfo.lpfn = BrowseCallbackProc; + theInfo.lParam = (LPARAM)inDefaultDir.c_str(); + + // Ask the user to choose a directory + LPITEMIDLIST theItem = SHBrowseForFolder(&theInfo); + + if (theItem != nullptr) { + TCHAR thePath[MAX_PATH] = { '\0' }; + // If a path was chosen + if (::SHGetPathFromIDList(theItem, thePath)) { + theResult = true; + outFile = CUICFile(Q3DStudio::CString(thePath)); + } + + // Free Memory used + LPMALLOC thePMalloc = 0; + if (SUCCEEDED(SHGetMalloc(&thePMalloc))) { + thePMalloc->Free(theItem); + thePMalloc->Release(); + } + } + + return theResult; +#endif + return false; +} + +//============================================================================== +/** + * Notify the user that the presentation we tried to load has failed. + * @param inPresentation The AKFile that we failed to load. + */ +void CDialogs::DisplayLoadingPresentationFailed(const CUICFile &inPresentation, + long inErrorIDS /*= -1 */) +{ + Q_UNUSED(inPresentation); + + if (inErrorIDS == -1) // if unspecified, default to the 'generic' string + inErrorIDS = IDS_ERROR_LOADPRESENTATION; + Q3DStudio::CString theErrorMessage; + theErrorMessage.Format(::LoadResourceString(inErrorIDS), + static_cast(inPresentation.GetName())); + Q3DStudio::CString theErrorTitle(::LoadResourceString(IDS_ERROR_LOADPRESENTATION_TITLE)); + + if (m_ShowGUI) + CUICMessageBox::Show(theErrorTitle, theErrorMessage, CUICMessageBox::ICON_WARNING, false, + qApp->activeWindow()); + else { + std::cout << theErrorTitle.GetCharStar() << ": " << theErrorMessage.GetCharStar() << std::endl; + } +} + +//============================================================================== +/** + * Notify the user that the presentation we tried to save has failed. + * + * @param inSavedLocation The AKFile that we failed to save. + */ +void CDialogs::DisplaySavingPresentationFailed() +{ + Q3DStudio::CString theErrorMessage = ::LoadResourceString(IDS_ERROR_EXPORTPRESENTATION); + Q3DStudio::CString theErrorTitle = ::LoadResourceString(IDS_PROJNAME); + + if (m_ShowGUI) + CUICMessageBox::Show(theErrorTitle, theErrorMessage, CUICMessageBox::ICON_WARNING, false, + qApp->activeWindow()); + else { + std::cout << theErrorTitle.GetCharStar() << ": " << theErrorMessage.GetCharStar() << std::endl; + } +} + +//============================================================================== +/** + * Display a message box to indicate failure to overwrite a read-only file + * + * @param inSavedLocation + * the file location to be saved + * + * @return void + */ +void CDialogs::DisplaySaveReadOnlyFailed(const CUICFile &inSavedLocation) +{ + Q3DStudio::CString theMsg = ::LoadResourceString(IDS_SAVE_READONLY_WARNING); + Q3DStudio::CString theTitle = ::LoadResourceString(IDS_PROJNAME); + + Q3DStudio::CString theFormattedText; + theFormattedText.Format(theMsg, static_cast(inSavedLocation.GetName())); + + if (m_ShowGUI) + CUICMessageBox::Show(theTitle, theFormattedText, CUICMessageBox::ICON_WARNING, false, + qApp->activeWindow()); + else { + std::cout << theTitle.GetCharStar() << ": " << theFormattedText.GetCharStar() << std::endl; + } +} + +//============================================================================== +/** + * Displays a CUICMessageBox using the specified parameters. The message box + * is modal to the main frame. This provides an easy way to place modal dialogs + * to the user, without requiring your class to know about the main frame or + * window refs. + * @param inTitle Title of the message box (not used on Mac) + * @param inText Text of the message + * @param inIcon Icon to be displayed next to the text + * @param inShowCancel true to show a Cancel button, false only show an OK button + * @return Indication of which button was pressed to dismiss the dialog + */ +CUICMessageBox::EMessageBoxReturn +CDialogs::DisplayMessageBox(const Q3DStudio::CString &inTitle, const Q3DStudio::CString &inText, + CUICMessageBox::EMessageBoxIcon inIcon, bool inShowCancel) +{ + CUICMessageBox::EMessageBoxReturn theUserChoice; + + if (m_ShowGUI) { + theUserChoice = + CUICMessageBox::Show(inTitle, inText, inIcon, inShowCancel, qApp->activeWindow()); + } else { + std::cout << inTitle.GetCharStar() << ": " << inText.GetCharStar() << std::endl; + theUserChoice = CUICMessageBox::MSGBX_OK; + } + + return theUserChoice; +} + +int CDialogs::DisplayChoiceBox(const Q3DStudio::CString &inTitle, const Q3DStudio::CString &inText, + int inIcon) +{ + if (m_ShowGUI) { + QMessageBox box; + box.setWindowTitle(inTitle.toQString()); + box.setText(inText.toQString()); + switch (inIcon) { + case CUICMessageBox::ICON_WARNING: + box.setIcon(QMessageBox::Warning); + break; + case CUICMessageBox::ICON_ERROR: + box.setIcon(QMessageBox::Critical); + break; + case CUICMessageBox::ICON_INFO: + box.setIcon(QMessageBox::Information); + break; + default: + break; + } + box.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + switch (box.exec()) { + case QMessageBox::Yes: + return IDYES; + case QMessageBox::No: + return IDNO; + default: + Q_UNREACHABLE(); + } + } else { + std::cout << inTitle.GetCharStar() << ": " << inText << std::endl; + return IDYES; + } +} + +const char *CDialogs::GetDAEFileExtension() +{ + return "dae"; +} +const char *CDialogs::GetFbxFileExtension() +{ + return "fbx"; +} +// Null terminated list +const char **CDialogs::GetImgFileExtensions() +{ + return imgExts; +} +const char *CDialogs::GetImportFileExtension() +{ + return "import"; +} +const char *CDialogs::GetMeshFileExtension() +{ + return "mesh"; +} +const char *CDialogs::GetLUAFileExtension() +{ + return "lua"; +} +const char *CDialogs::GetQmlFileExtension() +{ + return "qml"; +} +const char **CDialogs::GetFontFileExtensions() +{ + return fontExts; +} +const char **CDialogs::GetEffectFileExtensions() +{ + return effectExts; +} +const char **CDialogs::GetMaterialFileExtensions() +{ + return materialExts; +} +const char **CDialogs::GetSoundFileExtensions() +{ + return soundExts; +} + +bool IsFileExtension(const char *inExt, const char **inExts) +{ + if (inExt == nullptr) + return false; + for (const char **ext = inExts; *ext != nullptr; ++ext) + if (QString::compare(inExt, *ext, Qt::CaseInsensitive) == 0) + return true; + return false; +} +bool CDialogs::IsImageFileExtension(const char *inExt) +{ + return IsFileExtension(inExt, imgExts); +} +bool CDialogs::IsFontFileExtension(const char *inExt) +{ + return IsFileExtension(inExt, fontExts); +} +bool CDialogs::IsEffectFileExtension(const char *inExt) +{ + return IsFileExtension(inExt, effectExts); +} +bool CDialogs::IsMaterialFileExtension(const char *inExt) +{ + return IsFileExtension(inExt, materialExts); +} +bool CDialogs::IsSoundFileExtension(const char *inExt) +{ + return IsFileExtension(inExt, soundExts); +} + +const wchar_t **CDialogs::GetWideImgFileExtensions() +{ + return wideImgExts; +} +const wchar_t *CDialogs::GetWideDAEFileExtension() +{ + return L"dae"; +} +const wchar_t *CDialogs::GetWideFbxFileExtension() +{ + return L"fbx"; +} +const wchar_t *CDialogs::GetWideImportFileExtension() +{ + return L"import"; +} +const wchar_t *CDialogs::GetWideMeshFileExtension() +{ + return L"mesh"; +} +const wchar_t *CDialogs::GetWideLUAFileExtension() +{ + return L"lua"; +} +const wchar_t **CDialogs::GetWideFontFileExtensions() +{ + return wideFontExts; +} +const wchar_t **CDialogs::GetWideEffectFileExtensions() +{ + return wideEffectExts; +} +const wchar_t **CDialogs::GetWideMaterialFileExtensions() +{ + return wideMaterialExts; +} + +bool IsFileExtension(const wchar_t *inExt, const wchar_t **inExts) +{ + if (inExt == nullptr) + return false; + for (const wchar_t **ext = inExts; *ext != nullptr; ++ext) { + if (QString::compare(QString::fromWCharArray(inExt), + QString::fromWCharArray(*ext), Qt::CaseInsensitive) == 0) { + return true; + } + } + return false; +} +bool CDialogs::IsImageFileExtension(const wchar_t *inExt) +{ + return IsFileExtension(inExt, wideImgExts); +} +bool CDialogs::IsFontFileExtension(const wchar_t *inExt) +{ + return IsFileExtension(inExt, wideFontExts); +} +bool CDialogs::IsEffectFileExtension(const wchar_t *inExt) +{ + return IsFileExtension(inExt, wideEffectExts); +} + +bool CDialogs::IsMaterialFileExtension(const wchar_t *inExt) +{ + return IsFileExtension(inExt, wideMaterialExts); +} + +bool CDialogs::IsPathFileExtension(const wchar_t *inExt) +{ + return QString::compare(QString::fromWCharArray(inExt), "svg", Qt::CaseInsensitive) == 0; +} + +bool CDialogs::IsPathBufferExtension(const wchar_t *inExt) +{ + return QString::compare(QString::fromWCharArray(inExt), "path", Qt::CaseInsensitive) == 0; +} + +bool CDialogs::IsSoundFileExtension(const wchar_t *inExt) +{ + return IsFileExtension(inExt, wideSoundExts); +} + +//============================================================================== +/** + * File picker. + * Format for filter is as follows: + * Each entry in the filter list is '|*.ext' + * String must end with '|' + * Example, XML Exporter (*.xml)|*.xml|All files (*.*)|*.*| + * + * @param inFileExtensionFilter Well-formed extension filter string. See comments + *above for the format. + * @param inDefault Default string in case of abortion or + *failure + * @return chosen file path if successful, inDefault otherwise. + */ +Q3DStudio::CString CDialogs::GetFilePathChoice(const Q3DStudio::CString &inFileExtensionFilter, + const Q3DStudio::CString &inDefault, + const Q3DStudio::CString *inDialogTitle /*= nullptr */) +{ + Q3DStudio::CString theResult(inDefault); + +#ifdef KDAB_TEMPORARILY_REMOVED + CFileDialogEx theFileDlg(true, nullptr, nullptr, 0, inFileExtensionFilter, AfxGetMainWnd()); + + Q3DStudio::CString theInitDir = + CPreferences::GetUserPreferences().GetStringValue("LastChosenFile", ""); + theFileDlg.SetInitialDirectory(theInitDir); + + // Remember the filter setting between invokations + static long s_LastFilterIndex = -1; + if (s_LastFilterIndex > 0) + theFileDlg.SetFilterIndex(s_LastFilterIndex); + + if (inDialogTitle) // Set the title of the dialog if specied + theFileDlg.SetWindowTitle(*inDialogTitle); + + if (theFileDlg.DoModal() == IDOK) { + theResult = theFileDlg.GetPathName(); + CPreferences::GetUserPreferences().SetStringValue("LastChosenFile", theResult); + s_LastFilterIndex = theFileDlg.GetLastFilterIndex(); + } +#endif + + return theResult; +} + +//============================================================================== +/** + * CreateAllowedTypesString: Creates the string used to determine allowable types for import or + *for filereferences + * @return the string that dynamicly created with the extensions supported. + */ +QString CDialogs::CreateAllowedTypesString(long inFileTypeFilter, bool inForImport) +{ + QString theReturnString; + size_t theCount = inForImport ? g_NumAllowedImportTypes : g_NumAllowedFileReferencesTypes; + for (size_t idx = 0; idx < theCount; ++idx) { + const SAllowedTypesEntry &entry = + inForImport ? g_AllowedImportTypes[idx] : g_AllowedFileReferencesTypes[idx]; + if (inFileTypeFilter == Q3DStudio::DocumentEditorFileType::Unknown + || inFileTypeFilter == entry.m_FileType) { + QString theTypeString(::LoadResourceString(entry.m_ResourceStringId).toQString()); + QString theExtensions(CreateExtensionsList(entry.m_FileExtensions).toQString()); + theReturnString += theTypeString + " (" + theExtensions + ");;"; + } + } + return theReturnString; +} + +//============================================================================== +/** + * Display a error dialog box with the given text string that describes the error. + */ +void CDialogs::DisplayKnownErrorDialog(const Q3DStudio::CString &inErrorText) +{ + if (inErrorText.Length() > 0) // make sure this is valid + { + Q3DStudio::CString theTitle(::LoadResourceString(IDS_PROJNAME)); + if (m_ShowGUI) + CUICMessageBox::Show(theTitle, inErrorText, CUICMessageBox::ICON_ERROR, false, + qApp->activeWindow()); + else + std::cout << inErrorText.GetCharStar() << ": " << inErrorText.GetCharStar() << std::endl; + } +} + +//============================================================================== +/** + * Prompt the user to save the document before losing their changes. + * This is used when closing, loading or newing up a document when the current + * one has modifications. + * @return the user's choice. + */ +CDialogs::ESavePromptResult CDialogs::PromptForSave() +{ + Q3DStudio::CString theDocTitle; + + CUICFile theCurrentDoc = g_StudioApp.GetCore()->GetDoc()->GetDocumentPath(); + if (theCurrentDoc.IsFile()) + theDocTitle = theCurrentDoc.GetName(); + else // if the current doc has not been saved then use the default title. + theDocTitle = ::LoadResourceString(IDS_UNTITLED_DOCUMENT_TITLE); + + Q3DStudio::CString thePrompt = ::LoadResourceString(IDS_PROMPT_FOR_SAVE); + thePrompt.Format(thePrompt, static_cast(theDocTitle)); + + int theChoice = QMessageBox::warning(nullptr, ::LoadResourceString(IDS_PROJNAME).toQString(), + thePrompt.toQString(), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + + ESavePromptResult theResult = CANCEL_OPERATION; + + switch (theChoice) { + case QMessageBox::Yes: + theResult = SAVE_FIRST; + break; + case QMessageBox::No: + theResult = CONTINUE_NO_SAVE; + break; + case QMessageBox::Cancel: + theResult = CANCEL_OPERATION; + break; + default: + break; + } + + return theResult; +} + +//============================================================================== +/** + * Prompt the user for a file to save to from the SaveAs menu option. + * @return an invalid file if the user cancels the save dialog. + */ +std::pair CDialogs::GetSaveAsChoice(const Q3DStudio::CString &inDialogTitle, + bool inFilenameUntitled) +{ + CUICFile theFile(""); + Q3DStudio::CString theFileExt; + Q3DStudio::CString theImportFilter; + + Q3DStudio::CString theFilename = g_StudioApp.GetCore()->GetDoc()->GetDocumentPath().GetAbsolutePath(); + + if (theFilename == "" || inFilenameUntitled) + theFilename = ::LoadResourceString(IDS_UNTITLED_DOCUMENT_TITLE); + + theFileExt = ::LoadResourceString(IDS_FILE_EXT_UIP); + theImportFilter = ::LoadResourceString(IDS_FILE_DESC_UIP); + + theImportFilter += " (*" + theFileExt + ")|*" + theFileExt + "|"; + + QFileDialog theFileDlg; + theFileDlg.setOption(QFileDialog::DontConfirmOverwrite); + const QFileInfo fi(m_LastSaveFile.toQString()); + theFileDlg.setDirectory((fi.path() == QLatin1Char('.')) ? QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) : fi.path()); + theFileDlg.setAcceptMode(QFileDialog::AcceptSave); + theFileDlg.setDefaultSuffix(theFileExt.toQString()); + if (inDialogTitle != "") + theFileDlg.setWindowTitle(inDialogTitle.toQString()); + + bool theCreateDir = false; + bool theShowDialog = true; + + while (theShowDialog && theFileDlg.exec()) { + theShowDialog = false; + theFile = CUICFile(Q3DStudio::CString::fromQString(theFileDlg.selectedFiles().front())); + + m_LastSaveFile = theFile.GetAbsolutePath(); + // customising a dialog box will force us to use non-native. + // defaulting this for now, until we can agree a better workflow for + // creating new projects + theCreateDir = true; + + if (theCreateDir) { + // If user checks "Create directory for project" + // we need to check manually if the file in the directory already exists (because the + // default file dialog can't do that for you) + // If the file exists, show warning message if user wants to overwrite the file + // This is to fix bug #6315: Create new project in folder with same name will overwrite + // existing file without warning + Q3DStudio::CFilePath theFinalDir; + Q3DStudio::CFilePath theFinalDoc; + g_StudioApp.GetCore()->GetCreateDirectoryFileName(theFile, theFinalDir, theFinalDoc); + + // Update last save file to final doc + m_LastSaveFile = theFinalDoc; + if (theFinalDoc.Exists()) { + const QString theTitle(QObject::tr("Confirm Save As")); + const QString filePath(theFinalDir.GetFileName().toQString() + QDir::separator() + theFinalDoc.GetFileName().toQString()); + const QString theString = QObject::tr("%1 already exists.\nDo you want to replace it?").arg(filePath); + + auto result = QMessageBox::question(nullptr, theTitle, theString); + if (result != QMessageBox::Yes) { + // Reset the file and show the file dialog again + theFile = CUICFile(""); + theShowDialog = true; + continue; + } + } // of over-writing case + } + } + + return std::make_pair(theFile, theCreateDir); +} + +//============================================================================== +/** + * Prompt the user for a file to create. + * @return an invalid file if the user cancels the save dialog. + */ +std::pair +CDialogs::GetNewDocumentChoice(const Q3DStudio::CString &inInitialDirectory) +{ + if (inInitialDirectory.size()) + m_LastSaveFile = inInitialDirectory; + return GetSaveAsChoice(::LoadResourceString(IDS_CREATE_NEW_DOCUMENT_TITLE), true); +} + +//============================================================================== +/** + * Prompt the user for a file to open. + * This will return an invalid file if the user cancels the save dialog. + */ +CUICFile CDialogs::GetFileOpenChoice(const Q3DStudio::CString &inInitialDirectory) +{ + CUICFile theFile(""); + Q3DStudio::CString theFileExt; + Q3DStudio::CString theImportFilter; + + theFileExt = ::LoadResourceString(IDS_FILE_EXT_UIP); + theImportFilter = ::LoadResourceString(IDS_FILE_DESC_UIP); + + theImportFilter += " (*" + theFileExt + ")"; + + QFileDialog theFileDlg(qApp->activeWindow(), QString(), inInitialDirectory.toQString(), theImportFilter.toQString()); + theFileDlg.setAcceptMode(QFileDialog::AcceptOpen); + + if (theFileDlg.exec() == QDialog::Accepted) { + QFileInfo fi(theFileDlg.selectedFiles().first()); + Q3DStudio::CString thePath = Q3DStudio::CString::fromQString(fi.absolutePath()); + Q3DStudio::CString theName = Q3DStudio::CString::fromQString(fi.fileName()); + theFile = CUICFile(thePath, theName); + + m_LastSaveFile = theFile.GetAbsolutePath(); + } + + return theFile; +} + +//============================================================================== +/** + * Prompt the user to make sure they want to revert the current project. + * @return true if they do want to continue with the revert. + */ +bool CDialogs::ConfirmRevert() +{ + bool theConfirmation = false; + Q3DStudio::CString thePrompt = ::LoadResourceString(IDS_PROMPT_FOR_REVERT); + Q3DStudio::CString theTitle = ::LoadResourceString(IDS_PROJNAME); + + CUICMessageBox::EMessageBoxReturn theChoice; + + if (m_ShowGUI) + theChoice = CUICMessageBox::Show(theTitle, thePrompt, CUICMessageBox::ICON_WARNING, true, + qApp->activeWindow()); + else { + std::cout << theTitle.GetCharStar() << ": " << thePrompt.GetCharStar() << std::endl; + theChoice = CUICMessageBox::MSGBX_OK; + } + + // user decided to go ahead and delete all unused resources + if (theChoice == CUICMessageBox::MSGBX_OK) + theConfirmation = true; + + return theConfirmation; +} + +//============================================================================== +/** + * Displays a progress screen, if there is not one aleady being shown. The + * progress screen doesn't get dismissed until you call + * CDialogs::DestroyProgressScreen(). + * @param inActionText text to be displayed above the file name on the screen + * @param inFileName name of the file that you are loading + * @param inWindowTitle the window's title + */ +void CDialogs::DisplayProgressScreen(const Q3DStudio::CString &inActionText, + const Q3DStudio::CString &inFileName, + const Q3DStudio::CString &inWindowTitle) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + if (m_ShowGUI && (!m_ProgressPalette || !m_ProgressPalette->GetSafeHwnd())) { + m_ProgressPalette = new CProgressPalette(); + CViews::CreateDialogAndView(RUNTIME_CLASS(CProgressView), m_ProgressPalette, + (CFrameWnd *)AfxGetMainWnd(), inWindowTitle); + m_ProgressPalette->ShowDialog(); + m_ProgressPalette->InitialUpdate(); + m_ProgressPalette->SetActionText(inActionText); + m_ProgressPalette->SetFileName(inFileName); + m_ProgressPalette->RedrawWindow(nullptr, nullptr, RDW_UPDATENOW); + } +#endif +} + +//============================================================================== +/** + * Retrieve the pointer to the progress screen. + * @return m_ProgressPalette + */ +IProgressCallback *CDialogs::GetProgressScreen() const +{ +#ifdef KDAB_TEMPORARILY_REMOVED + return m_ProgressPalette; +#endif + return nullptr; +} + +//============================================================================== +/** + * If a loading screen is currently being shown, this function destroys it. You + * can show the loading screen again with another call to + * CDialogs::DisplayLoadingScreen(). + */ +void CDialogs::DestroyProgressScreen() +{ +#ifdef KDAB_TEMPORARILY_REMOVED + if (m_ShowGUI && (m_ProgressPalette && m_ProgressPalette->GetSafeHwnd())) { + // Don't call delete on m_ProgressPalette. You should only call DestroyWindow on + // CFrameWnds. See the MSDN. + m_ProgressPalette->DestroyWindow(); + m_ProgressPalette = nullptr; + } +#endif +} + +//============================================================================== +/** + * Prompt the user for the Object Timebar color. + * @param ioColor + * @return true if we successfully obtained a color using the displayed dialog. + */ +bool CDialogs::PromptObjectTimebarColor(CColor &ioColor) +{ +#ifdef KDAB_TEMPORARILY_REMOVED + std::auto_ptr theColorDlg(new CColorDialog(ioColor, CC_SOLIDCOLOR | CC_FULLOPEN)); + ::CColor theSelectedColor; + if (theColorDlg->DoModal() == IDOK) { + ioColor = theColorDlg->GetColor(); + return true; + } + return false; +#endif + return false; +} + +//============================================================================== +/** + * Display statistics from profiling. + */ +void CDialogs::DisplayProfilingStatistics() +{ + Q3DStudio::CString theStatistics = ""; +#ifdef KDAB_TEMPORARILY_REMOVED +#ifdef PERFORM_PROFILE + CMasterProf *theMasterP = CMasterProf::GetInstance(); + + for (long theIndex = 0; theIndex < theMasterP->GetProfilerCount(); ++theIndex) { + CMethProf *theProf = theMasterP->GetProfiler(theIndex); + if (theProf->GetCount() > 0) { + theStatistics += theProf->GetDescription(); + theStatistics += "\n"; + } + } +#endif // #ifdef PERFORM_PROFILE + if (m_ShowGUI) + CUICMessageBox::Show("Profiling Statistics", theStatistics, CUICMessageBox::ICON_INFO); + else { + std::cout << "Profiling Statistics" + << ": " << theStatistics.GetMulti() << std::endl; + } +#endif +} + +//============================================================================== +/** + * Inform the user that the environment variables entered does not match the format + * expected, listing down all those settings that are wrong. + * @param inErrorMessage the listing of all those errors. + */ +void CDialogs::DisplayEnvironmentVariablesError(const Q3DStudio::CString &inErrorMessage) +{ + Q3DStudio::CString theTitle = ::LoadResourceString(IDS_ERROR_PROJECT_VARIABLES_TITLE); + Q3DStudio::CString theMessage = ::LoadResourceString(IDS_ERROR_PROJECT_VARIABLES_MSG); + theMessage += inErrorMessage; + theMessage += ::LoadResourceString(IDS_PROJECT_VARIABLES_FORMAT); + if (m_ShowGUI) + CUICMessageBox::Show(theTitle, theMessage, CUICMessageBox::ICON_ERROR, false, + qApp->activeWindow()); + else { + std::cout << theTitle.GetCharStar() << ": " << theMessage.GetCharStar() << std::endl; + } +} + +//============================================================================== +/** + * Reset settings. + * Typically inCurrentDocPath is only set when Studio is first launched. + * @param inCurrentDocPath the current document path, if any. Application directory if + *there is none. + */ +void CDialogs::ResetSettings(const Q3DStudio::CString &inCurrentDocPath) +{ + // Initialize the default dir/paths to the current document path if specified, otherwise leave + // everything as it is. + if (!inCurrentDocPath.IsEmpty()) { + m_LastSaveFile = inCurrentDocPath; + } +} + +bool CDialogs::DisplayResetKeyframeValuesDlg() +{ +#ifdef KDAB_TEMPORARILY_REMOVED + CResetKeyframeValuesDlg theDialog; + return theDialog.DoModal() == IDOK; +#endif + return false; +} + +//============================================================================== +/** + * User trying to do a pathological paste, such as pasting a component copied from a different + *instance + * of Studio into an instance of the same component that already exists in the current instance + *of Studio, and + * is potentially replaced and deleted. + */ +void CDialogs::DisplayPasteFailed() +{ + Q3DStudio::CString theTitle(::LoadResourceString(IDS_ERROR_PATHOLOGICAL_PASTE_TITLE)); + Q3DStudio::CString theMessage(::LoadResourceString(IDS_ERROR_PATHOLOGICAL_PASTE_MESSAGE)); + + if (m_ShowGUI) + CUICMessageBox::Show(theTitle, theMessage, CUICMessageBox::ICON_ERROR, false, + qApp->activeWindow()); + else + std::cout << theTitle.GetCharStar() << ": " << theMessage.GetCharStar() << std::endl; +} + +//============================================================================== +/** + * Video card OpenGL version is too low to be supported. + */ +void CDialogs::DisplayGLVersionError(const Q3DStudio::CString &inGLVersion, + const Q3DStudio::CString &inMinVersion) +{ + DisplayGLVersionDialog(inGLVersion, inMinVersion, true); +} + +//============================================================================== +/** + * Video card OpenGL version is outdated, but could be usable. + */ +void CDialogs::DisplayGLVersionWarning(const Q3DStudio::CString &inGLVersion, + const Q3DStudio::CString &inRecommendedVersion) +{ + DisplayGLVersionDialog(inGLVersion, inRecommendedVersion, false); +} + +//============================================================================== +/** + * Display the error dialog or warning dialog that OpenGL version is lower than what is + *expected + */ +void CDialogs::DisplayGLVersionDialog(const Q3DStudio::CString &inGLVersion, + const Q3DStudio::CString &inRecommendedVersion, bool inError) +{ + long theTitleResourceID; + long theMessageResourceID; + + if (inError) { + theTitleResourceID = IDS_ERROR_MSGTITLE; + theMessageResourceID = IDS_GL_VERSION_ERROR; + } else { + theTitleResourceID = IDS_WARNING_MSGTITLE; + theMessageResourceID = IDS_GL_VERSION_WARNING; + } + +#ifdef KDAB_TEMPORARILY_REMOVED + Q3DStudio::CString theTitle(::LoadResourceString(theTitleResourceID)); + Q3DStudio::CString theMessage(::LoadResourceString(theMessageResourceID)); + Q3DStudio::CString theFormattedMessage; + theFormattedMessage.Format(theMessage, static_cast(inGLVersion), + static_cast(inRecommendedVersion)); + + CGLVersionDlg theGLVersionDlg; + theGLVersionDlg.Initialize(theTitle, theFormattedMessage, inError); + theGLVersionDlg.DoModal(); + + if (theGLVersionDlg.GetDontShowAgain()) + CStudioPreferences::SetDontShowGLVersionDialog(true); +#endif +} diff --git a/src/Authoring/Studio/_Win/Workspace/Views.cpp b/src/Authoring/Studio/_Win/Workspace/Views.cpp new file mode 100644 index 00000000..50ab6f62 --- /dev/null +++ b/src/Authoring/Studio/_Win/Workspace/Views.cpp @@ -0,0 +1,195 @@ +/**************************************************************************** +** +** 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 "Views.h" + +//============================================================================== +// Includes +//============================================================================== +#ifdef KDAB_TEMPORARILY_REMOVED +#include "Doc.h" +#endif +#include "MainFrm.h" +#ifdef KDAB_TEMPORARILY_REMOVED +#include "TimelineTimelineLayout.h" +#include "ScalableScroller.h" +#include "PaletteManager.h" +#include "HotKeys.h" +#include "Dispatch.h" +#include "ActionControl.h" +#include "StudioPaletteBar.h" +#endif + +//============================================================================== +// Implementation +//============================================================================== + +//============================================================================= +/** + * Constructor + */ +CViews::CViews(CStudioApp * /*inStudioApp*/) + : m_MainFrame(nullptr) +{ +} + +//============================================================================= +/** + * Destructor + */ +CViews::~CViews() +{ + DestroyViews(); +} + +//============================================================================= +/** + * + */ +void CViews::CreateViews() +{ + // To create the main window, this code creates a new frame window + // object and then sets it as the application's main window object + m_MainFrame = new CMainFrame(); + m_MainFrame->show(); +#ifdef KDAB_TEMPORARILY_REMOVED + // create and load the frame with its resources + m_MainFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE, nullptr, nullptr); + + m_MainFrame->RestoreLayout(); +#endif +} + +//============================================================================= +/** + * + */ +void CViews::DestroyViews() +{ + if (m_MainFrame) { + // Do NOT use delete to destroy a CFrameWnd object! Use DestroyWindow() instead. + m_MainFrame->deleteLater(); + m_MainFrame = nullptr; + } +} + +//============================================================================== +// Keyboard +//============================================================================== + +//============================================================================= +/** + * Register all Application specific shortcut keys. + * Used to map hotkeys that are active through the whole app, not just one + * view. + * @param inHotKeys the handler to register on. + */ +void CViews::RegisterGlobalKeyboardShortcuts(CHotKeys *inHotKeys) +{ + if (m_MainFrame) + m_MainFrame->RegisterGlobalKeyboardShortcuts(inHotKeys); +} + +//============================================================================= +/** + * NO ONE SHOULD USE THIS FUNCTION OTHER THAN THE MAINFRAME ON WINDOWS + */ +CMainFrame *CViews::GetMainFrame() +{ + return m_MainFrame; +} + +//============================================================================= +/** + * + */ +void CViews::RecheckMainframeSizingMode() +{ + if (m_MainFrame != nullptr) + m_MainFrame->RecheckSizingMode(); +} + +//============================================================================== +// Static +//============================================================================== + +//============================================================================= +/** + * Creates a palette and the associated view. + * @param inClass Should be RUNTIME_CLASS( CCLASS ) where CCLASS is a class that + * inherits from MFC::CView (must implement dynamic creation) and is the view + * that you want associated with the palette. + * @param inPalette Palette that you want the view attached to + * @param inParent Parent window or nullptr for top level windows + * @param inWindowTitle Title caption to appear on the title bar of the palette + * @param inShowWindow true to show the window after creation, false to hide it + */ +#ifdef KDAB_TEMPORARILY_REMOVED +void CViews::CreatePaletteAndView(CRuntimeClass *inClass, CStudioPaletteBar *inPalette, + CFrameWnd *inParent, Q3DStudio::CString inWindowTitle) +{ + CCreateContext theCreateContext; + memset(&theCreateContext, 0, sizeof(CCreateContext)); + theCreateContext.m_pNewViewClass = inClass; + theCreateContext.m_pCurrentFrame = inParent; + theCreateContext.m_pCurrentDoc = nullptr; + + inPalette->Create(::CString(inWindowTitle.GetMulti()), &theCreateContext, + CPaletteManager::GetUniquePaletteId(), inParent); +} +#endif + +//============================================================================= +/** + * Creates a dialog and the associated view. + * @param inClass Should be RUNTIME_CLASS( CCLASS ) where CCLASS is a class that + * inherits from MFC::CView (must implement dynamic creation) and is the view + * that you want associated with the palette. + * @param inPalette Palette that you want the view attached to + * @param inParent Parent window or nullptr for top level windows + * @param inWindowTitle Title caption to appear on the title bar of the palette + * @param inShowWindow true to show the window after creation, false to hide it + */ +#ifdef KDAB_TEMPORARILY_REMOVED +void CViews::CreateDialogAndView(CRuntimeClass *inClass, CStudioDialog *inDialog, + CFrameWnd *inParent, Q3DStudio::CString inWindowTitle) +{ + CCreateContext theCreateContext; + memset(&theCreateContext, 0, sizeof(CCreateContext)); + theCreateContext.m_pNewViewClass = inClass; + theCreateContext.m_pCurrentFrame = inParent; + theCreateContext.m_pCurrentDoc = nullptr; + + inDialog->Create(::CString(inWindowTitle.GetMulti()), &theCreateContext, inParent); +} +#endif diff --git a/src/Authoring/Studio/images.qrc b/src/Authoring/Studio/images.qrc new file mode 100644 index 00000000..19cabdc1 --- /dev/null +++ b/src/Authoring/Studio/images.qrc @@ -0,0 +1,179 @@ + + + images/Action-MasterAction.png + images/Action-Trash-Disabled.png + images/Action-Trash-Disabled@2x.png + images/Action-Trash-Normal.png + images/Action-Trash-Normal@2x.png + images/add.png + images/add@2x.png + images/arrow.png + images/arrow@2x.png + images/arrow_down.png + images/arrow_down@2x.png + images/Asset-Alias-Normal.png + images/Asset-Alias-Normal@2x.png + images/Asset-Camera-Normal.png + images/Asset-Camera-Normal@2x.png + images/Asset-Component-Normal.png + images/Asset-Component-Normal@2x.png + images/Asset-Cone-Normal.png + images/Asset-Cone-Normal@2x.png + images/Asset-Cube-Normal.png + images/Asset-Cube-Normal@2x.png + images/Asset-Cylinder-Normal.png + images/Asset-Cylinder-Normal@2x.png + images/Asset-Group-Normal.png + images/Asset-Group-Normal@2x.png + images/Asset-Layer-Normal.png + images/Asset-Layer-Normal@2x.png + images/Asset-Light-Normal.png + images/Asset-Light-Normal@2x.png + images/Asset-Rectangle-Normal.png + images/Asset-Rectangle-Normal@2x.png + images/Asset-Sphere-Normal.png + images/Asset-Sphere-Normal@2x.png + images/Asset-Text-Normal.png + images/Asset-Text-Normal@2x.png + images/checkbox-checked.png + images/checkbox-unchecked.png + images/Inspector-AnimateToggle-Active.png + images/Inspector-AnimateToggle-Active@2x.png + images/Inspector-AnimateToggle-Normal.png + images/Inspector-AnimateToggle-Normal@2x.png + images/Objects-Behavior-Normal.png + images/Objects-Effect-Normal.png + images/Objects-Folder-Normal.png + images/Objects-Image-Normal.png + images/Objects-Layer-Normal.png + images/Objects-Layer-Normal@2x.png + images/Objects-Material-Normal.png + images/Objects-Model-Normal.png + images/Objects-Text-Normal.png + images/Objects-Text-Normal@2x.png + images/Slide-Active.png + images/Slide-Active@2x.png + images/Slide-Master-Active.png + images/Slide-Normal.png + images/Objects-Group-Normal.png + images/Objects-Group-Normal@2x.png + images/Objects-Light-Normal.png + images/Objects-Light-Normal@2x.png + images/Objects-Property-Normal.png + images/Objects-Property-Normal@2x.png + images/filter-shy-down.png + images/filter-shy-down@2x.png + images/filter-toggle-eye-down.png + images/filter-toggle-eye-down@2x.png + images/filter-toggle-eye-up.png + images/filter-toggle-eye-up@2x.png + images/PlaybackHead.png + images/PlaybackHead@2x.png + images/Toggle-HideShow.png + images/Toggle-HideShow@2x.png + images/obsolete_placeholder.png + images/empty-pixel.png + images/Toggle-Lock.png + images/Toggle-Lock@2x.png + images/Toggle-Shy.png + images/Toggle-Shy@2x.png + images/Toggle-Empty.png + images/Objects-Scene-Normal.png + images/Objects-Scene-Normal@2x.png + images/Action-Action.png + images/Action-ChildAction.png + images/Objects-Camera-Normal.png + images/timebarhandle-disabled-left.png + images/timebarhandle-disabled-right.png + images/timebarhandle-left.png + images/timebarhandle-right.png + images/Toggle-HideShow-disabled.png + images/Toggle-HideShow-disabled@2x.png + images/Objects-Alias-Normal.png + images/Objects-Alias-Normal@2x.png + images/Objects-Behavior-Normal@2x.png + images/Objects-Camera-Normal@2x.png + images/Objects-Component-Normal.png + images/Objects-Component-Normal@2x.png + images/Objects-Effect-Normal@2x.png + images/Objects-Folder-Normal@2x.png + images/Objects-Image-Normal@2.png + images/Objects-Material-Normal@2x.png + images/Objects-Model-Normal@2x.png + images/scrollbar-arrows-down-depressed.png + images/scrollbar-arrows-down-disabled.png + images/scrollbar-arrows-down-normal.png + images/scrollbar-arrows-left-depressed.png + images/scrollbar-arrows-left-disabled.png + images/scrollbar-arrows-left-normal.png + images/scrollbar-arrows-right-depressed.png + images/scrollbar-arrows-right-disabled.png + images/scrollbar-arrows-right-normal.png + images/scrollbar-arrows-up-depressed.png + images/scrollbar-arrows-up-disabled.png + images/scrollbar-arrows-up-normal.png + images/Keyframe-Master-Disabled.png + images/Keyframe-MasterDynamic-Normal.png + images/Keyframe-MasterDynamic-Selected.png + images/Keyframe-MasterLeft-disabled.png + images/Keyframe-MasterLeftDynamic-Normal.png + images/Keyframe-MasterLeftDynamic-Selected.png + images/Keyframe-MasterLeft-Normal.png + images/Keyframe-MasterLeft-Selected.png + images/Keyframe-Master-Normal.png + images/Keyframe-MasterRight-disabled.png + images/Keyframe-MasterRightDynamic-Normal.png + images/Keyframe-MasterRightDynamic-Selected.png + images/Keyframe-MasterRight-Normal.png + images/Keyframe-MasterRight-Selected.png + images/Keyframe-Master-Selected.png + images/Keyframe-Property-Disabled.png + images/Keyframe-PropertyDynamic-Normal.png + images/Keyframe-PropertyDynamic-Selected.png + images/Keyframe-Property-Normal.png + images/Keyframe-Property-Selected.png + images/Objects-Property-Disabled.png + images/Objects-Property-Disabled@2x.png + images/Action-ChildMasterAction.png + images/Action-ComponentAction.png + images/Action-ComponentMasterAction.png + images/breadcrumb_component_button.png + images/breadcrumb_component_colon_button.png + images/breadcrumb_component_grey_button.png + images/breadcrumb_component_scene.png + images/Insert-Left.png + images/Insert-Rearrange-Left.png + images/Insert-Rearrange-Right.png + images/Insert-Right.png + images/Objects-Alias-Disabled.png + images/Objects-Behavior-Disabled.png + images/Objects-Camera-Disabled.png + images/Objects-Component-Disabled.png + images/Objects-Effect-Disabled.png + images/Objects-Group-Disabled.png + images/Objects-Group-Disabled@2x.png + images/Objects-Image-Disabled.png + images/Objects-Layer-Disabled.png + images/Objects-Layer-Disabled@2x.png + images/Objects-Light-Disabled.png + images/Objects-Light-Disabled@2x.png + images/Objects-Material-Disabled.png + images/Objects-Model-Disabled.png + images/Objects-Scene-Disabled.png + images/Objects-Text-Disabled.png + images/Objects-Alias-Disabled@2x.png + images/Objects-Behavior-Disabled@2x.png + images/Objects-Camera-Disabled@2x.png + images/Objects-Component-Disabled@2x.png + images/Objects-Effect-Disabled@2x.png + images/Objects-Folder-Disabled.png + images/Objects-Folder-Disabled@2x.png + images/Objects-Image-Disabled@2x.png + images/Objects-Material-Disabled@2x.png + images/Objects-Model-Disabled@2x.png + images/Objects-Scene-Disabled@2x.png + images/Objects-Text-Disabled@2x.png + images/Slide-Master-Active@2x.png + images/Slide-Normal@2x.png + + diff --git a/src/Authoring/Studio/images/Action-Action.png b/src/Authoring/Studio/images/Action-Action.png new file mode 100644 index 00000000..4b8d9c8e Binary files /dev/null and b/src/Authoring/Studio/images/Action-Action.png differ diff --git a/src/Authoring/Studio/images/Action-ChildAction.png b/src/Authoring/Studio/images/Action-ChildAction.png new file mode 100644 index 00000000..6589b104 Binary files /dev/null and b/src/Authoring/Studio/images/Action-ChildAction.png differ diff --git a/src/Authoring/Studio/images/Action-ChildMasterAction.png b/src/Authoring/Studio/images/Action-ChildMasterAction.png new file mode 100644 index 00000000..39159191 Binary files /dev/null and b/src/Authoring/Studio/images/Action-ChildMasterAction.png differ diff --git a/src/Authoring/Studio/images/Action-ComponentAction.png b/src/Authoring/Studio/images/Action-ComponentAction.png new file mode 100644 index 00000000..d7287f46 Binary files /dev/null and b/src/Authoring/Studio/images/Action-ComponentAction.png differ diff --git a/src/Authoring/Studio/images/Action-ComponentMasterAction.png b/src/Authoring/Studio/images/Action-ComponentMasterAction.png new file mode 100644 index 00000000..bb34a3da Binary files /dev/null and b/src/Authoring/Studio/images/Action-ComponentMasterAction.png differ diff --git a/src/Authoring/Studio/images/Action-MasterAction.png b/src/Authoring/Studio/images/Action-MasterAction.png new file mode 100644 index 00000000..74f06661 Binary files /dev/null and b/src/Authoring/Studio/images/Action-MasterAction.png differ diff --git a/src/Authoring/Studio/images/Action-Trash-Disabled.png b/src/Authoring/Studio/images/Action-Trash-Disabled.png new file mode 100644 index 00000000..c175290d Binary files /dev/null and b/src/Authoring/Studio/images/Action-Trash-Disabled.png differ diff --git a/src/Authoring/Studio/images/Action-Trash-Disabled@2x.png b/src/Authoring/Studio/images/Action-Trash-Disabled@2x.png new file mode 100644 index 00000000..2793f0c2 Binary files /dev/null and b/src/Authoring/Studio/images/Action-Trash-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Action-Trash-Normal.png b/src/Authoring/Studio/images/Action-Trash-Normal.png new file mode 100644 index 00000000..616a85a0 Binary files /dev/null and b/src/Authoring/Studio/images/Action-Trash-Normal.png differ diff --git a/src/Authoring/Studio/images/Action-Trash-Normal@2x.png b/src/Authoring/Studio/images/Action-Trash-Normal@2x.png new file mode 100644 index 00000000..1365907e Binary files /dev/null and b/src/Authoring/Studio/images/Action-Trash-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Asset-Alias-Normal.png b/src/Authoring/Studio/images/Asset-Alias-Normal.png new file mode 100644 index 00000000..4a40aecf Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Alias-Normal.png differ diff --git a/src/Authoring/Studio/images/Asset-Alias-Normal@2x.png b/src/Authoring/Studio/images/Asset-Alias-Normal@2x.png new file mode 100644 index 00000000..6b14d31f Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Alias-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Asset-Camera-Normal.png b/src/Authoring/Studio/images/Asset-Camera-Normal.png new file mode 100644 index 00000000..faa642c2 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Camera-Normal.png differ diff --git a/src/Authoring/Studio/images/Asset-Camera-Normal@2x.png b/src/Authoring/Studio/images/Asset-Camera-Normal@2x.png new file mode 100644 index 00000000..d69675e8 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Camera-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Asset-Component-Normal.png b/src/Authoring/Studio/images/Asset-Component-Normal.png new file mode 100644 index 00000000..9b1fc237 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Component-Normal.png differ diff --git a/src/Authoring/Studio/images/Asset-Component-Normal@2x.png b/src/Authoring/Studio/images/Asset-Component-Normal@2x.png new file mode 100644 index 00000000..45b10cb5 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Component-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Asset-Cone-Normal.png b/src/Authoring/Studio/images/Asset-Cone-Normal.png new file mode 100644 index 00000000..5b42abe9 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Cone-Normal.png differ diff --git a/src/Authoring/Studio/images/Asset-Cone-Normal@2x.png b/src/Authoring/Studio/images/Asset-Cone-Normal@2x.png new file mode 100644 index 00000000..4edac2fa Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Cone-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Asset-Cube-Normal.png b/src/Authoring/Studio/images/Asset-Cube-Normal.png new file mode 100644 index 00000000..c858a011 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Cube-Normal.png differ diff --git a/src/Authoring/Studio/images/Asset-Cube-Normal@2x.png b/src/Authoring/Studio/images/Asset-Cube-Normal@2x.png new file mode 100644 index 00000000..07bfc514 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Cube-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Asset-Cylinder-Normal.png b/src/Authoring/Studio/images/Asset-Cylinder-Normal.png new file mode 100644 index 00000000..99b8b418 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Cylinder-Normal.png differ diff --git a/src/Authoring/Studio/images/Asset-Cylinder-Normal@2x.png b/src/Authoring/Studio/images/Asset-Cylinder-Normal@2x.png new file mode 100644 index 00000000..887855e9 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Cylinder-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Asset-Group-Normal.png b/src/Authoring/Studio/images/Asset-Group-Normal.png new file mode 100644 index 00000000..4575da6e Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Group-Normal.png differ diff --git a/src/Authoring/Studio/images/Asset-Group-Normal@2x.png b/src/Authoring/Studio/images/Asset-Group-Normal@2x.png new file mode 100644 index 00000000..162c008b Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Group-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Asset-Layer-Normal.png b/src/Authoring/Studio/images/Asset-Layer-Normal.png new file mode 100644 index 00000000..e11e3d26 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Layer-Normal.png differ diff --git a/src/Authoring/Studio/images/Asset-Layer-Normal@2x.png b/src/Authoring/Studio/images/Asset-Layer-Normal@2x.png new file mode 100644 index 00000000..d479fca7 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Layer-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Asset-Light-Normal.png b/src/Authoring/Studio/images/Asset-Light-Normal.png new file mode 100644 index 00000000..47bc8d89 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Light-Normal.png differ diff --git a/src/Authoring/Studio/images/Asset-Light-Normal@2x.png b/src/Authoring/Studio/images/Asset-Light-Normal@2x.png new file mode 100644 index 00000000..d36e0bf8 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Light-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Asset-Rectangle-Normal.png b/src/Authoring/Studio/images/Asset-Rectangle-Normal.png new file mode 100644 index 00000000..dd904770 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Rectangle-Normal.png differ diff --git a/src/Authoring/Studio/images/Asset-Rectangle-Normal@2x.png b/src/Authoring/Studio/images/Asset-Rectangle-Normal@2x.png new file mode 100644 index 00000000..1ad5bc31 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Rectangle-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Asset-Sphere-Normal.png b/src/Authoring/Studio/images/Asset-Sphere-Normal.png new file mode 100644 index 00000000..c53885ba Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Sphere-Normal.png differ diff --git a/src/Authoring/Studio/images/Asset-Sphere-Normal@2x.png b/src/Authoring/Studio/images/Asset-Sphere-Normal@2x.png new file mode 100644 index 00000000..e14312f1 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Sphere-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Asset-Text-Normal.png b/src/Authoring/Studio/images/Asset-Text-Normal.png new file mode 100644 index 00000000..0ae00949 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Text-Normal.png differ diff --git a/src/Authoring/Studio/images/Asset-Text-Normal@2x.png b/src/Authoring/Studio/images/Asset-Text-Normal@2x.png new file mode 100644 index 00000000..734900e8 Binary files /dev/null and b/src/Authoring/Studio/images/Asset-Text-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Insert-Left.png b/src/Authoring/Studio/images/Insert-Left.png new file mode 100644 index 00000000..14871c90 Binary files /dev/null and b/src/Authoring/Studio/images/Insert-Left.png differ diff --git a/src/Authoring/Studio/images/Insert-Rearrange-Left.png b/src/Authoring/Studio/images/Insert-Rearrange-Left.png new file mode 100644 index 00000000..7a0d2703 Binary files /dev/null and b/src/Authoring/Studio/images/Insert-Rearrange-Left.png differ diff --git a/src/Authoring/Studio/images/Insert-Rearrange-Right.png b/src/Authoring/Studio/images/Insert-Rearrange-Right.png new file mode 100644 index 00000000..58bbc0c8 Binary files /dev/null and b/src/Authoring/Studio/images/Insert-Rearrange-Right.png differ diff --git a/src/Authoring/Studio/images/Insert-Right.png b/src/Authoring/Studio/images/Insert-Right.png new file mode 100644 index 00000000..4393a84a Binary files /dev/null and b/src/Authoring/Studio/images/Insert-Right.png differ diff --git a/src/Authoring/Studio/images/Inspector-AnimateToggle-Active.png b/src/Authoring/Studio/images/Inspector-AnimateToggle-Active.png new file mode 100644 index 00000000..1ed0e731 Binary files /dev/null and b/src/Authoring/Studio/images/Inspector-AnimateToggle-Active.png differ diff --git a/src/Authoring/Studio/images/Inspector-AnimateToggle-Active@2x.png b/src/Authoring/Studio/images/Inspector-AnimateToggle-Active@2x.png new file mode 100644 index 00000000..ef83fea8 Binary files /dev/null and b/src/Authoring/Studio/images/Inspector-AnimateToggle-Active@2x.png differ diff --git a/src/Authoring/Studio/images/Inspector-AnimateToggle-Normal.png b/src/Authoring/Studio/images/Inspector-AnimateToggle-Normal.png new file mode 100644 index 00000000..ff00f71c Binary files /dev/null and b/src/Authoring/Studio/images/Inspector-AnimateToggle-Normal.png differ diff --git a/src/Authoring/Studio/images/Inspector-AnimateToggle-Normal@2x.png b/src/Authoring/Studio/images/Inspector-AnimateToggle-Normal@2x.png new file mode 100644 index 00000000..dc1cee05 Binary files /dev/null and b/src/Authoring/Studio/images/Inspector-AnimateToggle-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Keyframe-Master-Disabled.png b/src/Authoring/Studio/images/Keyframe-Master-Disabled.png new file mode 100644 index 00000000..7e66cd27 Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-Master-Disabled.png differ diff --git a/src/Authoring/Studio/images/Keyframe-Master-Normal.png b/src/Authoring/Studio/images/Keyframe-Master-Normal.png new file mode 100644 index 00000000..9fb6281b Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-Master-Normal.png differ diff --git a/src/Authoring/Studio/images/Keyframe-Master-Selected.png b/src/Authoring/Studio/images/Keyframe-Master-Selected.png new file mode 100644 index 00000000..5d3806ba Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-Master-Selected.png differ diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.png new file mode 100644 index 00000000..919c310f Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.png differ diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.png new file mode 100644 index 00000000..7712d96f Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.png differ diff --git a/src/Authoring/Studio/images/Keyframe-MasterLeft-Normal.png b/src/Authoring/Studio/images/Keyframe-MasterLeft-Normal.png new file mode 100644 index 00000000..bb198c49 Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-MasterLeft-Normal.png differ diff --git a/src/Authoring/Studio/images/Keyframe-MasterLeft-Selected.png b/src/Authoring/Studio/images/Keyframe-MasterLeft-Selected.png new file mode 100644 index 00000000..1fbd3e06 Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-MasterLeft-Selected.png differ diff --git a/src/Authoring/Studio/images/Keyframe-MasterLeft-disabled.png b/src/Authoring/Studio/images/Keyframe-MasterLeft-disabled.png new file mode 100644 index 00000000..46fb034f Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-MasterLeft-disabled.png differ diff --git a/src/Authoring/Studio/images/Keyframe-MasterLeftDynamic-Normal.png b/src/Authoring/Studio/images/Keyframe-MasterLeftDynamic-Normal.png new file mode 100644 index 00000000..2e8a3f1b Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-MasterLeftDynamic-Normal.png differ diff --git a/src/Authoring/Studio/images/Keyframe-MasterLeftDynamic-Selected.png b/src/Authoring/Studio/images/Keyframe-MasterLeftDynamic-Selected.png new file mode 100644 index 00000000..51d2be2e Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-MasterLeftDynamic-Selected.png differ diff --git a/src/Authoring/Studio/images/Keyframe-MasterRight-Normal.png b/src/Authoring/Studio/images/Keyframe-MasterRight-Normal.png new file mode 100644 index 00000000..56bcacff Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-MasterRight-Normal.png differ diff --git a/src/Authoring/Studio/images/Keyframe-MasterRight-Selected.png b/src/Authoring/Studio/images/Keyframe-MasterRight-Selected.png new file mode 100644 index 00000000..1d98fc59 Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-MasterRight-Selected.png differ diff --git a/src/Authoring/Studio/images/Keyframe-MasterRight-disabled.png b/src/Authoring/Studio/images/Keyframe-MasterRight-disabled.png new file mode 100644 index 00000000..2b1086a7 Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-MasterRight-disabled.png differ diff --git a/src/Authoring/Studio/images/Keyframe-MasterRightDynamic-Normal.png b/src/Authoring/Studio/images/Keyframe-MasterRightDynamic-Normal.png new file mode 100644 index 00000000..105f61f4 Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-MasterRightDynamic-Normal.png differ diff --git a/src/Authoring/Studio/images/Keyframe-MasterRightDynamic-Selected.png b/src/Authoring/Studio/images/Keyframe-MasterRightDynamic-Selected.png new file mode 100644 index 00000000..5c706f5c Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-MasterRightDynamic-Selected.png differ diff --git a/src/Authoring/Studio/images/Keyframe-Property-Disabled.png b/src/Authoring/Studio/images/Keyframe-Property-Disabled.png new file mode 100644 index 00000000..87e5dde9 Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-Property-Disabled.png differ diff --git a/src/Authoring/Studio/images/Keyframe-Property-Normal.png b/src/Authoring/Studio/images/Keyframe-Property-Normal.png new file mode 100644 index 00000000..7afc5b09 Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-Property-Normal.png differ diff --git a/src/Authoring/Studio/images/Keyframe-Property-Selected.png b/src/Authoring/Studio/images/Keyframe-Property-Selected.png new file mode 100644 index 00000000..7eb45ab3 Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-Property-Selected.png differ diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.png new file mode 100644 index 00000000..2231a10c Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.png differ diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.png new file mode 100644 index 00000000..02186956 Binary files /dev/null and b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.png differ diff --git a/src/Authoring/Studio/images/Objects-Alias-Disabled.png b/src/Authoring/Studio/images/Objects-Alias-Disabled.png new file mode 100644 index 00000000..85e6dd94 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Alias-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Alias-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Alias-Disabled@2x.png new file mode 100644 index 00000000..6f9dffc3 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Alias-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Alias-Normal.png b/src/Authoring/Studio/images/Objects-Alias-Normal.png new file mode 100644 index 00000000..c97c38f2 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Alias-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Alias-Normal@2x.png b/src/Authoring/Studio/images/Objects-Alias-Normal@2x.png new file mode 100644 index 00000000..620608d8 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Alias-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Behavior-Disabled.png b/src/Authoring/Studio/images/Objects-Behavior-Disabled.png new file mode 100644 index 00000000..a7c71f93 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Behavior-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Behavior-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Behavior-Disabled@2x.png new file mode 100644 index 00000000..5ded4633 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Behavior-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Behavior-Normal.png b/src/Authoring/Studio/images/Objects-Behavior-Normal.png new file mode 100644 index 00000000..0aa09e8f Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Behavior-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Behavior-Normal@2x.png b/src/Authoring/Studio/images/Objects-Behavior-Normal@2x.png new file mode 100644 index 00000000..aa65ef2d Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Behavior-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Camera-Disabled.png b/src/Authoring/Studio/images/Objects-Camera-Disabled.png new file mode 100644 index 00000000..5d87e29a Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Camera-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Camera-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Camera-Disabled@2x.png new file mode 100644 index 00000000..47efdc5c Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Camera-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Camera-Normal.png b/src/Authoring/Studio/images/Objects-Camera-Normal.png new file mode 100644 index 00000000..69f6e385 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Camera-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Camera-Normal@2x.png b/src/Authoring/Studio/images/Objects-Camera-Normal@2x.png new file mode 100644 index 00000000..2c8bc946 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Camera-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Component-Disabled.png b/src/Authoring/Studio/images/Objects-Component-Disabled.png new file mode 100644 index 00000000..f417a7a2 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Component-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Component-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Component-Disabled@2x.png new file mode 100644 index 00000000..bfb5d2d2 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Component-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Component-Normal.png b/src/Authoring/Studio/images/Objects-Component-Normal.png new file mode 100644 index 00000000..c95f7b4d Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Component-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Component-Normal@2x.png b/src/Authoring/Studio/images/Objects-Component-Normal@2x.png new file mode 100644 index 00000000..e852f0a7 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Component-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Effect-Disabled.png b/src/Authoring/Studio/images/Objects-Effect-Disabled.png new file mode 100644 index 00000000..0b0bde6e Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Effect-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Effect-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Effect-Disabled@2x.png new file mode 100644 index 00000000..34eb98d8 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Effect-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Effect-Normal.png b/src/Authoring/Studio/images/Objects-Effect-Normal.png new file mode 100644 index 00000000..d54948a4 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Effect-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Effect-Normal@2x.png b/src/Authoring/Studio/images/Objects-Effect-Normal@2x.png new file mode 100644 index 00000000..c2edac40 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Effect-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Folder-Disabled.png b/src/Authoring/Studio/images/Objects-Folder-Disabled.png new file mode 100644 index 00000000..67585cd3 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Folder-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Folder-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Folder-Disabled@2x.png new file mode 100644 index 00000000..fc1fadc8 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Folder-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Folder-Normal.png b/src/Authoring/Studio/images/Objects-Folder-Normal.png new file mode 100644 index 00000000..2cc95c46 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Folder-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Folder-Normal@2x.png b/src/Authoring/Studio/images/Objects-Folder-Normal@2x.png new file mode 100644 index 00000000..44c2e3b6 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Folder-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Group-Disabled.png b/src/Authoring/Studio/images/Objects-Group-Disabled.png new file mode 100644 index 00000000..0e4e6eaf Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Group-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Group-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Group-Disabled@2x.png new file mode 100644 index 00000000..2feb6c6b Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Group-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Group-Normal.png b/src/Authoring/Studio/images/Objects-Group-Normal.png new file mode 100644 index 00000000..3c22bb61 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Group-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Group-Normal@2x.png b/src/Authoring/Studio/images/Objects-Group-Normal@2x.png new file mode 100644 index 00000000..286be9b8 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Group-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Image-Disabled.png b/src/Authoring/Studio/images/Objects-Image-Disabled.png new file mode 100644 index 00000000..34654dae Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Image-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Image-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Image-Disabled@2x.png new file mode 100644 index 00000000..2f1dfd5e Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Image-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Image-Normal.png b/src/Authoring/Studio/images/Objects-Image-Normal.png new file mode 100644 index 00000000..3d657b8a Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Image-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Image-Normal@2.png b/src/Authoring/Studio/images/Objects-Image-Normal@2.png new file mode 100644 index 00000000..c99df5d2 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Image-Normal@2.png differ diff --git a/src/Authoring/Studio/images/Objects-Layer-Disabled.png b/src/Authoring/Studio/images/Objects-Layer-Disabled.png new file mode 100644 index 00000000..c52e0340 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Layer-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Layer-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Layer-Disabled@2x.png new file mode 100644 index 00000000..6fa6f7aa Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Layer-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Layer-Normal.png b/src/Authoring/Studio/images/Objects-Layer-Normal.png new file mode 100644 index 00000000..d06bb2cd Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Layer-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Layer-Normal@2x.png b/src/Authoring/Studio/images/Objects-Layer-Normal@2x.png new file mode 100644 index 00000000..532764ab Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Layer-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Light-Disabled.png b/src/Authoring/Studio/images/Objects-Light-Disabled.png new file mode 100644 index 00000000..9fea9d3f Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Light-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Light-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Light-Disabled@2x.png new file mode 100644 index 00000000..d476c9b3 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Light-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Light-Normal.png b/src/Authoring/Studio/images/Objects-Light-Normal.png new file mode 100644 index 00000000..68fec179 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Light-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Light-Normal@2x.png b/src/Authoring/Studio/images/Objects-Light-Normal@2x.png new file mode 100644 index 00000000..4b627f1d Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Light-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Material-Disabled.png b/src/Authoring/Studio/images/Objects-Material-Disabled.png new file mode 100644 index 00000000..ec77957f Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Material-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Material-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Material-Disabled@2x.png new file mode 100644 index 00000000..f9b216d0 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Material-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Material-Normal.png b/src/Authoring/Studio/images/Objects-Material-Normal.png new file mode 100644 index 00000000..225bb4b5 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Material-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Material-Normal@2x.png b/src/Authoring/Studio/images/Objects-Material-Normal@2x.png new file mode 100644 index 00000000..d51fd360 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Material-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Model-Disabled.png b/src/Authoring/Studio/images/Objects-Model-Disabled.png new file mode 100644 index 00000000..ead6ede5 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Model-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Model-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Model-Disabled@2x.png new file mode 100644 index 00000000..8c0f635a Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Model-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Model-Normal.png b/src/Authoring/Studio/images/Objects-Model-Normal.png new file mode 100644 index 00000000..9e066414 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Model-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Model-Normal@2x.png b/src/Authoring/Studio/images/Objects-Model-Normal@2x.png new file mode 100644 index 00000000..075663bf Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Model-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Property-Disabled.png b/src/Authoring/Studio/images/Objects-Property-Disabled.png new file mode 100644 index 00000000..84c55833 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Property-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Property-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Property-Disabled@2x.png new file mode 100644 index 00000000..15428fe9 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Property-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Property-Normal.png b/src/Authoring/Studio/images/Objects-Property-Normal.png new file mode 100644 index 00000000..a75d0561 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Property-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Property-Normal@2x.png b/src/Authoring/Studio/images/Objects-Property-Normal@2x.png new file mode 100644 index 00000000..e1cf503a Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Property-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Scene-Disabled.png b/src/Authoring/Studio/images/Objects-Scene-Disabled.png new file mode 100644 index 00000000..a4aba973 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Scene-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Scene-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Scene-Disabled@2x.png new file mode 100644 index 00000000..2d21542a Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Scene-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Scene-Normal.png b/src/Authoring/Studio/images/Objects-Scene-Normal.png new file mode 100644 index 00000000..56253242 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Scene-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Scene-Normal@2x.png b/src/Authoring/Studio/images/Objects-Scene-Normal@2x.png new file mode 100644 index 00000000..c963c77b Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Scene-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Text-Disabled.png b/src/Authoring/Studio/images/Objects-Text-Disabled.png new file mode 100644 index 00000000..f8ba1b9a Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Text-Disabled.png differ diff --git a/src/Authoring/Studio/images/Objects-Text-Disabled@2x.png b/src/Authoring/Studio/images/Objects-Text-Disabled@2x.png new file mode 100644 index 00000000..22cec550 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Text-Disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Objects-Text-Normal.png b/src/Authoring/Studio/images/Objects-Text-Normal.png new file mode 100644 index 00000000..0ae00949 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Text-Normal.png differ diff --git a/src/Authoring/Studio/images/Objects-Text-Normal@2x.png b/src/Authoring/Studio/images/Objects-Text-Normal@2x.png new file mode 100644 index 00000000..734900e8 Binary files /dev/null and b/src/Authoring/Studio/images/Objects-Text-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/PlaybackHead.png b/src/Authoring/Studio/images/PlaybackHead.png new file mode 100644 index 00000000..ce001ad2 Binary files /dev/null and b/src/Authoring/Studio/images/PlaybackHead.png differ diff --git a/src/Authoring/Studio/images/PlaybackHead@2x.png b/src/Authoring/Studio/images/PlaybackHead@2x.png new file mode 100644 index 00000000..f1a579a7 Binary files /dev/null and b/src/Authoring/Studio/images/PlaybackHead@2x.png differ diff --git a/src/Authoring/Studio/images/Slide-Active.png b/src/Authoring/Studio/images/Slide-Active.png new file mode 100644 index 00000000..8ee8a8bd Binary files /dev/null and b/src/Authoring/Studio/images/Slide-Active.png differ diff --git a/src/Authoring/Studio/images/Slide-Active@2x.png b/src/Authoring/Studio/images/Slide-Active@2x.png new file mode 100644 index 00000000..8c2031e1 Binary files /dev/null and b/src/Authoring/Studio/images/Slide-Active@2x.png differ diff --git a/src/Authoring/Studio/images/Slide-Master-Active.png b/src/Authoring/Studio/images/Slide-Master-Active.png new file mode 100644 index 00000000..0672c3c0 Binary files /dev/null and b/src/Authoring/Studio/images/Slide-Master-Active.png differ diff --git a/src/Authoring/Studio/images/Slide-Master-Active@2x.png b/src/Authoring/Studio/images/Slide-Master-Active@2x.png new file mode 100644 index 00000000..43baf38f Binary files /dev/null and b/src/Authoring/Studio/images/Slide-Master-Active@2x.png differ diff --git a/src/Authoring/Studio/images/Slide-Normal.png b/src/Authoring/Studio/images/Slide-Normal.png new file mode 100644 index 00000000..bb44401c Binary files /dev/null and b/src/Authoring/Studio/images/Slide-Normal.png differ diff --git a/src/Authoring/Studio/images/Slide-Normal@2x.png b/src/Authoring/Studio/images/Slide-Normal@2x.png new file mode 100644 index 00000000..5f6bf90e Binary files /dev/null and b/src/Authoring/Studio/images/Slide-Normal@2x.png differ diff --git a/src/Authoring/Studio/images/Toggle-Empty.png b/src/Authoring/Studio/images/Toggle-Empty.png new file mode 100644 index 00000000..3f6660c9 Binary files /dev/null and b/src/Authoring/Studio/images/Toggle-Empty.png differ diff --git a/src/Authoring/Studio/images/Toggle-HideShow-disabled.png b/src/Authoring/Studio/images/Toggle-HideShow-disabled.png new file mode 100644 index 00000000..fa28ed9c Binary files /dev/null and b/src/Authoring/Studio/images/Toggle-HideShow-disabled.png differ diff --git a/src/Authoring/Studio/images/Toggle-HideShow-disabled@2x.png b/src/Authoring/Studio/images/Toggle-HideShow-disabled@2x.png new file mode 100644 index 00000000..e75f821f Binary files /dev/null and b/src/Authoring/Studio/images/Toggle-HideShow-disabled@2x.png differ diff --git a/src/Authoring/Studio/images/Toggle-HideShow.png b/src/Authoring/Studio/images/Toggle-HideShow.png new file mode 100644 index 00000000..bfa3c734 Binary files /dev/null and b/src/Authoring/Studio/images/Toggle-HideShow.png differ diff --git a/src/Authoring/Studio/images/Toggle-HideShow@2x.png b/src/Authoring/Studio/images/Toggle-HideShow@2x.png new file mode 100644 index 00000000..5425b285 Binary files /dev/null and b/src/Authoring/Studio/images/Toggle-HideShow@2x.png differ diff --git a/src/Authoring/Studio/images/Toggle-Lock.png b/src/Authoring/Studio/images/Toggle-Lock.png new file mode 100644 index 00000000..627fa7f7 Binary files /dev/null and b/src/Authoring/Studio/images/Toggle-Lock.png differ diff --git a/src/Authoring/Studio/images/Toggle-Lock@2x.png b/src/Authoring/Studio/images/Toggle-Lock@2x.png new file mode 100644 index 00000000..d1a6dfc4 Binary files /dev/null and b/src/Authoring/Studio/images/Toggle-Lock@2x.png differ diff --git a/src/Authoring/Studio/images/Toggle-Shy.png b/src/Authoring/Studio/images/Toggle-Shy.png new file mode 100644 index 00000000..2b990ad3 Binary files /dev/null and b/src/Authoring/Studio/images/Toggle-Shy.png differ diff --git a/src/Authoring/Studio/images/Toggle-Shy@2x.png b/src/Authoring/Studio/images/Toggle-Shy@2x.png new file mode 100644 index 00000000..1c9fa9f4 Binary files /dev/null and b/src/Authoring/Studio/images/Toggle-Shy@2x.png differ diff --git a/src/Authoring/Studio/images/add.png b/src/Authoring/Studio/images/add.png new file mode 100644 index 00000000..efd65386 Binary files /dev/null and b/src/Authoring/Studio/images/add.png differ diff --git a/src/Authoring/Studio/images/add@2x.png b/src/Authoring/Studio/images/add@2x.png new file mode 100644 index 00000000..98fd8d80 Binary files /dev/null and b/src/Authoring/Studio/images/add@2x.png differ diff --git a/src/Authoring/Studio/images/arrow.png b/src/Authoring/Studio/images/arrow.png new file mode 100644 index 00000000..40ebda88 Binary files /dev/null and b/src/Authoring/Studio/images/arrow.png differ diff --git a/src/Authoring/Studio/images/arrow@2x.png b/src/Authoring/Studio/images/arrow@2x.png new file mode 100644 index 00000000..1a21ee06 Binary files /dev/null and b/src/Authoring/Studio/images/arrow@2x.png differ diff --git a/src/Authoring/Studio/images/arrow_down.png b/src/Authoring/Studio/images/arrow_down.png new file mode 100644 index 00000000..238f8b6f Binary files /dev/null and b/src/Authoring/Studio/images/arrow_down.png differ diff --git a/src/Authoring/Studio/images/arrow_down@2x.png b/src/Authoring/Studio/images/arrow_down@2x.png new file mode 100644 index 00000000..831189b6 Binary files /dev/null and b/src/Authoring/Studio/images/arrow_down@2x.png differ diff --git a/src/Authoring/Studio/images/breadcrumb_component_button.png b/src/Authoring/Studio/images/breadcrumb_component_button.png new file mode 100644 index 00000000..4f0cd4b5 Binary files /dev/null and b/src/Authoring/Studio/images/breadcrumb_component_button.png differ diff --git a/src/Authoring/Studio/images/breadcrumb_component_colon_button.png b/src/Authoring/Studio/images/breadcrumb_component_colon_button.png new file mode 100644 index 00000000..ff80c8b7 Binary files /dev/null and b/src/Authoring/Studio/images/breadcrumb_component_colon_button.png differ diff --git a/src/Authoring/Studio/images/breadcrumb_component_grey_button.png b/src/Authoring/Studio/images/breadcrumb_component_grey_button.png new file mode 100644 index 00000000..0db36558 Binary files /dev/null and b/src/Authoring/Studio/images/breadcrumb_component_grey_button.png differ diff --git a/src/Authoring/Studio/images/breadcrumb_component_scene.png b/src/Authoring/Studio/images/breadcrumb_component_scene.png new file mode 100644 index 00000000..f1c68fe6 Binary files /dev/null and b/src/Authoring/Studio/images/breadcrumb_component_scene.png differ diff --git a/src/Authoring/Studio/images/checkbox-checked.png b/src/Authoring/Studio/images/checkbox-checked.png new file mode 100644 index 00000000..f13b9aa5 Binary files /dev/null and b/src/Authoring/Studio/images/checkbox-checked.png differ diff --git a/src/Authoring/Studio/images/checkbox-unchecked.png b/src/Authoring/Studio/images/checkbox-unchecked.png new file mode 100644 index 00000000..7482c028 Binary files /dev/null and b/src/Authoring/Studio/images/checkbox-unchecked.png differ diff --git a/src/Authoring/Studio/images/empty-pixel.png b/src/Authoring/Studio/images/empty-pixel.png new file mode 100644 index 00000000..0ae92115 Binary files /dev/null and b/src/Authoring/Studio/images/empty-pixel.png differ diff --git a/src/Authoring/Studio/images/filter-shy-down.png b/src/Authoring/Studio/images/filter-shy-down.png new file mode 100644 index 00000000..2b990ad3 Binary files /dev/null and b/src/Authoring/Studio/images/filter-shy-down.png differ diff --git a/src/Authoring/Studio/images/filter-shy-down@2x.png b/src/Authoring/Studio/images/filter-shy-down@2x.png new file mode 100644 index 00000000..1c9fa9f4 Binary files /dev/null and b/src/Authoring/Studio/images/filter-shy-down@2x.png differ diff --git a/src/Authoring/Studio/images/filter-toggle-eye-down.png b/src/Authoring/Studio/images/filter-toggle-eye-down.png new file mode 100644 index 00000000..fa28ed9c Binary files /dev/null and b/src/Authoring/Studio/images/filter-toggle-eye-down.png differ diff --git a/src/Authoring/Studio/images/filter-toggle-eye-down@2x.png b/src/Authoring/Studio/images/filter-toggle-eye-down@2x.png new file mode 100644 index 00000000..e75f821f Binary files /dev/null and b/src/Authoring/Studio/images/filter-toggle-eye-down@2x.png differ diff --git a/src/Authoring/Studio/images/filter-toggle-eye-up.png b/src/Authoring/Studio/images/filter-toggle-eye-up.png new file mode 100644 index 00000000..bfa3c734 Binary files /dev/null and b/src/Authoring/Studio/images/filter-toggle-eye-up.png differ diff --git a/src/Authoring/Studio/images/filter-toggle-eye-up@2x.png b/src/Authoring/Studio/images/filter-toggle-eye-up@2x.png new file mode 100644 index 00000000..5425b285 Binary files /dev/null and b/src/Authoring/Studio/images/filter-toggle-eye-up@2x.png differ diff --git a/src/Authoring/Studio/images/obsolete_placeholder.png b/src/Authoring/Studio/images/obsolete_placeholder.png new file mode 100644 index 00000000..4837e5f0 Binary files /dev/null and b/src/Authoring/Studio/images/obsolete_placeholder.png differ diff --git a/src/Authoring/Studio/images/scrollbar-arrows-down-depressed.png b/src/Authoring/Studio/images/scrollbar-arrows-down-depressed.png new file mode 100644 index 00000000..3c50a1a0 Binary files /dev/null and b/src/Authoring/Studio/images/scrollbar-arrows-down-depressed.png differ diff --git a/src/Authoring/Studio/images/scrollbar-arrows-down-disabled.png b/src/Authoring/Studio/images/scrollbar-arrows-down-disabled.png new file mode 100644 index 00000000..be0b4a3d Binary files /dev/null and b/src/Authoring/Studio/images/scrollbar-arrows-down-disabled.png differ diff --git a/src/Authoring/Studio/images/scrollbar-arrows-down-normal.png b/src/Authoring/Studio/images/scrollbar-arrows-down-normal.png new file mode 100644 index 00000000..9e70abe1 Binary files /dev/null and b/src/Authoring/Studio/images/scrollbar-arrows-down-normal.png differ diff --git a/src/Authoring/Studio/images/scrollbar-arrows-left-depressed.png b/src/Authoring/Studio/images/scrollbar-arrows-left-depressed.png new file mode 100644 index 00000000..fde5c4e6 Binary files /dev/null and b/src/Authoring/Studio/images/scrollbar-arrows-left-depressed.png differ diff --git a/src/Authoring/Studio/images/scrollbar-arrows-left-disabled.png b/src/Authoring/Studio/images/scrollbar-arrows-left-disabled.png new file mode 100644 index 00000000..15fb43a5 Binary files /dev/null and b/src/Authoring/Studio/images/scrollbar-arrows-left-disabled.png differ diff --git a/src/Authoring/Studio/images/scrollbar-arrows-left-normal.png b/src/Authoring/Studio/images/scrollbar-arrows-left-normal.png new file mode 100644 index 00000000..9ecd27d4 Binary files /dev/null and b/src/Authoring/Studio/images/scrollbar-arrows-left-normal.png differ diff --git a/src/Authoring/Studio/images/scrollbar-arrows-right-depressed.png b/src/Authoring/Studio/images/scrollbar-arrows-right-depressed.png new file mode 100644 index 00000000..4f473c04 Binary files /dev/null and b/src/Authoring/Studio/images/scrollbar-arrows-right-depressed.png differ diff --git a/src/Authoring/Studio/images/scrollbar-arrows-right-disabled.png b/src/Authoring/Studio/images/scrollbar-arrows-right-disabled.png new file mode 100644 index 00000000..a32ea1cc Binary files /dev/null and b/src/Authoring/Studio/images/scrollbar-arrows-right-disabled.png differ diff --git a/src/Authoring/Studio/images/scrollbar-arrows-right-normal.png b/src/Authoring/Studio/images/scrollbar-arrows-right-normal.png new file mode 100644 index 00000000..8ad8f45f Binary files /dev/null and b/src/Authoring/Studio/images/scrollbar-arrows-right-normal.png differ diff --git a/src/Authoring/Studio/images/scrollbar-arrows-up-depressed.png b/src/Authoring/Studio/images/scrollbar-arrows-up-depressed.png new file mode 100644 index 00000000..74060ef8 Binary files /dev/null and b/src/Authoring/Studio/images/scrollbar-arrows-up-depressed.png differ diff --git a/src/Authoring/Studio/images/scrollbar-arrows-up-disabled.png b/src/Authoring/Studio/images/scrollbar-arrows-up-disabled.png new file mode 100644 index 00000000..ee9fbecc Binary files /dev/null and b/src/Authoring/Studio/images/scrollbar-arrows-up-disabled.png differ diff --git a/src/Authoring/Studio/images/scrollbar-arrows-up-normal.png b/src/Authoring/Studio/images/scrollbar-arrows-up-normal.png new file mode 100644 index 00000000..2174ba70 Binary files /dev/null and b/src/Authoring/Studio/images/scrollbar-arrows-up-normal.png differ diff --git a/src/Authoring/Studio/images/timebarhandle-disabled-left.png b/src/Authoring/Studio/images/timebarhandle-disabled-left.png new file mode 100644 index 00000000..a5c0e661 Binary files /dev/null and b/src/Authoring/Studio/images/timebarhandle-disabled-left.png differ diff --git a/src/Authoring/Studio/images/timebarhandle-disabled-right.png b/src/Authoring/Studio/images/timebarhandle-disabled-right.png new file mode 100644 index 00000000..a23ba5fe Binary files /dev/null and b/src/Authoring/Studio/images/timebarhandle-disabled-right.png differ diff --git a/src/Authoring/Studio/images/timebarhandle-left.png b/src/Authoring/Studio/images/timebarhandle-left.png new file mode 100644 index 00000000..598b6151 Binary files /dev/null and b/src/Authoring/Studio/images/timebarhandle-left.png differ diff --git a/src/Authoring/Studio/images/timebarhandle-right.png b/src/Authoring/Studio/images/timebarhandle-right.png new file mode 100644 index 00000000..149d834a Binary files /dev/null and b/src/Authoring/Studio/images/timebarhandle-right.png differ diff --git a/src/Authoring/Studio/qt3dstudio.qrc b/src/Authoring/Studio/qt3dstudio.qrc new file mode 100644 index 00000000..dba77f4a --- /dev/null +++ b/src/Authoring/Studio/qt3dstudio.qrc @@ -0,0 +1,16 @@ + + + res/Tutorial/button_back.png + res/Tutorial/button_next.png + res/Tutorial/screens/1.png + res/Tutorial/screens/2.png + res/Tutorial/screens/3.png + res/Tutorial/screens/4.png + res/Tutorial/screens/5.png + res/Tutorial/screens/6.png + res/Tutorial/screens/7.png + res/Tutorial/button_back@2x.png + res/Tutorial/button_next@2x.png + English.lproj/Strings/Static.stro + + diff --git a/src/Authoring/Studio/remoteproject.cpp b/src/Authoring/Studio/remoteproject.cpp new file mode 100644 index 00000000..f1b0cfe1 --- /dev/null +++ b/src/Authoring/Studio/remoteproject.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** 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 "remoteproject.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ConnectionDialog : public QDialog +{ +public: + static QPair getInfo(QWidget *parent); + +private: + ConnectionDialog(QWidget *parent); + QLineEdit *m_hostLineEdit = nullptr; + QLineEdit *m_portLineEdit = nullptr; +}; + +ConnectionDialog::ConnectionDialog(QWidget *parent) + : QDialog(parent) +{ + m_hostLineEdit = new QLineEdit(this); + QLabel *hostLabel = new QLabel(tr("Address:")); + hostLabel->setBuddy(m_hostLineEdit); + + m_portLineEdit = new QLineEdit(this); + m_portLineEdit->setText("36000"); + QLabel *portLabel = new QLabel(tr("Port:")); + portLabel->setBuddy(m_portLineEdit); + + QDialogButtonBox *buttonBox = new QDialogButtonBox( + QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this); + + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + + QGridLayout *mainLayout = new QGridLayout(this); + mainLayout->addWidget(hostLabel, 0, 0); + mainLayout->addWidget(m_hostLineEdit, 0, 1); + mainLayout->addWidget(portLabel, 1, 0); + mainLayout->addWidget(m_portLineEdit, 1, 1); + mainLayout->addWidget(buttonBox, 3, 0, 1, 2); + + setWindowTitle(tr("Connect to Device")); + m_hostLineEdit->setFocus(); +} + +QPair ConnectionDialog::getInfo(QWidget *parent) +{ + ConnectionDialog dialog(parent); + if (!dialog.exec()) + return QPair(); + + return qMakePair(dialog.m_hostLineEdit->text(), + dialog.m_portLineEdit->text().toInt()); +} + +RemoteProject::RemoteProject(QWidget *parent) + : QObject(parent) + , m_tcpSocket(0) + , m_mainWindow(parent) +{ +} + +void RemoteProject::connect() +{ + if (isConnected()) + return; + + delete m_tcpSocket; + m_tcpSocket = new QTcpSocket(this); + + QObject::connect(m_tcpSocket, &QTcpSocket::connected, this, + &RemoteProject::checkConnection); + QObject::connect(m_tcpSocket, &QTcpSocket::disconnected, this, + &RemoteProject::checkConnection); + QObject::connect(m_tcpSocket, + static_cast + (&QAbstractSocket::error), + this, &RemoteProject::connectionError); + + QPair info = ConnectionDialog::getInfo(m_mainWindow); + + m_tcpSocket->connectToHost(info.first, info.second); + if (!m_tcpSocket->waitForConnected(2000)) { + m_tcpSocket->abort(); + checkConnection(); + } +} + +void RemoteProject::disconnect() +{ + Q_ASSERT(m_tcpSocket); + m_tcpSocket->disconnectFromHost(); +} + +bool RemoteProject::isConnected() const +{ + return m_tcpSocket && m_tcpSocket->state() + == QAbstractSocket::ConnectedState; +} + +void RemoteProject::checkConnection() +{ + Q_EMIT connectionChanged(isConnected()); +} + +void RemoteProject::connectionError() +{ + if (m_tcpSocket) { + QMessageBox::warning(m_mainWindow, tr("Connect to Device"), + tr("Device connection error: ") + m_tcpSocket->errorString()); + } + Q_EMIT connectionChanged(isConnected()); +} + +void RemoteProject::streamProject(const QString &projectFile) +{ + Q_ASSERT(isConnected()); + if (!isConnected()) + return; + + QByteArray block; + QDataStream out(&block, QIODevice::WriteOnly); + out.setVersion(QDataStream::Qt_5_8); + + const QFileInfo fileInfo(projectFile); + if (!fileInfo.exists()) { + qWarning() << "failed to find file " << projectFile; + return; + } + + const QDir projectDirectory(fileInfo.absolutePath()); + + // The file to be loaded + const QString relativePath + = projectDirectory.relativeFilePath(fileInfo.filePath()); + + int fileCount = 0; + QDirIterator it(fileInfo.absolutePath(), QDir::Files, + QDirIterator::Subdirectories); + while (it.hasNext()) { + const QString filePath = it.next(); + QFile file(filePath); + if (!file.open(QIODevice::ReadOnly)) { + qWarning() << "could not open file " << filePath; + return; + } + + fileCount++; + const QString relativePath = projectDirectory.relativeFilePath(filePath); + const QByteArray payload = file.readAll(); + out << relativePath; + out << payload; + } + + QByteArray metaBlock; + QDataStream metaOut(&metaBlock, QIODevice::WriteOnly); + metaOut.setVersion(QDataStream::Qt_5_8); + metaOut << block.size(); + metaOut << fileCount; + metaOut << relativePath; + + m_tcpSocket->write(metaBlock); + m_tcpSocket->write(block); +} diff --git a/src/Authoring/Studio/remoteproject.h b/src/Authoring/Studio/remoteproject.h new file mode 100644 index 00000000..9aeb096e --- /dev/null +++ b/src/Authoring/Studio/remoteproject.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** 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 REMOTEPROJECT_H +#define REMOTEPROJECT_H + +#include +#include +#include + +class RemoteProject : public QObject +{ + Q_OBJECT +public: + explicit RemoteProject(QWidget *parent); + + void connect(); + void disconnect(); + bool isConnected() const; + + void streamProject(const QString &); + +public Q_SLOTS: + void checkConnection(); + void connectionError(); + +Q_SIGNALS: + void connectionChanged(bool) const; + +private: + QTcpSocket *m_tcpSocket; + QWidget *m_mainWindow; +}; + +#endif // REMOTEPROJECT_H diff --git a/src/Authoring/Studio/res/About Icon.bmp b/src/Authoring/Studio/res/About Icon.bmp new file mode 100644 index 00000000..97764f42 Binary files /dev/null and b/src/Authoring/Studio/res/About Icon.bmp differ diff --git a/src/Authoring/Studio/res/Flippy-Right.bmp b/src/Authoring/Studio/res/Flippy-Right.bmp new file mode 100644 index 00000000..e4471ec6 Binary files /dev/null and b/src/Authoring/Studio/res/Flippy-Right.bmp differ diff --git a/src/Authoring/Studio/res/Flippy-down.bmp b/src/Authoring/Studio/res/Flippy-down.bmp new file mode 100644 index 00000000..4c1dd0d2 Binary files /dev/null and b/src/Authoring/Studio/res/Flippy-down.bmp differ diff --git a/src/Authoring/Studio/res/Studio.ico b/src/Authoring/Studio/res/Studio.ico new file mode 100644 index 00000000..0911ac1f Binary files /dev/null and b/src/Authoring/Studio/res/Studio.ico differ diff --git a/src/Authoring/Studio/res/Studio.manifest b/src/Authoring/Studio/res/Studio.manifest new file mode 100644 index 00000000..6386fac9 --- /dev/null +++ b/src/Authoring/Studio/res/Studio.manifest @@ -0,0 +1,22 @@ + + + +Your app description here + + + + + + diff --git a/src/Authoring/Studio/res/Studio.png b/src/Authoring/Studio/res/Studio.png new file mode 100644 index 00000000..11c6e526 Binary files /dev/null and b/src/Authoring/Studio/res/Studio.png differ diff --git a/src/Authoring/Studio/res/StudioDoc.ico b/src/Authoring/Studio/res/StudioDoc.ico new file mode 100644 index 00000000..0d531110 Binary files /dev/null and b/src/Authoring/Studio/res/StudioDoc.ico differ diff --git a/src/Authoring/Studio/res/Toolbar-00.png b/src/Authoring/Studio/res/Toolbar-00.png new file mode 100644 index 00000000..4111f8f0 Binary files /dev/null and b/src/Authoring/Studio/res/Toolbar-00.png differ diff --git a/src/Authoring/Studio/res/Toolbar-01.png b/src/Authoring/Studio/res/Toolbar-01.png new file mode 100644 index 00000000..76e3b5c2 Binary files /dev/null and b/src/Authoring/Studio/res/Toolbar-01.png differ diff --git a/src/Authoring/Studio/res/Toolbar-02.png b/src/Authoring/Studio/res/Toolbar-02.png new file mode 100644 index 00000000..3cd03094 Binary files /dev/null and b/src/Authoring/Studio/res/Toolbar-02.png differ diff --git a/src/Authoring/Studio/res/Toolbar-03.png b/src/Authoring/Studio/res/Toolbar-03.png new file mode 100644 index 00000000..3cde7c2e Binary files /dev/null and b/src/Authoring/Studio/res/Toolbar-03.png differ diff --git a/src/Authoring/Studio/res/Toolbar-04.png b/src/Authoring/Studio/res/Toolbar-04.png new file mode 100644 index 00000000..3e04587b Binary files /dev/null and b/src/Authoring/Studio/res/Toolbar-04.png differ diff --git a/src/Authoring/Studio/res/Toolbar-05.png b/src/Authoring/Studio/res/Toolbar-05.png new file mode 100644 index 00000000..8b4dbb5c Binary files /dev/null and b/src/Authoring/Studio/res/Toolbar-05.png differ diff --git a/src/Authoring/Studio/res/Toolbar-06.png b/src/Authoring/Studio/res/Toolbar-06.png new file mode 100644 index 00000000..b4cdcc3c Binary files /dev/null and b/src/Authoring/Studio/res/Toolbar-06.png differ diff --git a/src/Authoring/Studio/res/Toolbar-07.png b/src/Authoring/Studio/res/Toolbar-07.png new file mode 100644 index 00000000..27e904f8 Binary files /dev/null and b/src/Authoring/Studio/res/Toolbar-07.png differ diff --git a/src/Authoring/Studio/res/Toolbar.bmp b/src/Authoring/Studio/res/Toolbar.bmp new file mode 100644 index 00000000..8b7a3424 Binary files /dev/null and b/src/Authoring/Studio/res/Toolbar.bmp differ diff --git a/src/Authoring/Studio/res/Tutorial/button_back.png b/src/Authoring/Studio/res/Tutorial/button_back.png new file mode 100644 index 00000000..8113df5b Binary files /dev/null and b/src/Authoring/Studio/res/Tutorial/button_back.png differ diff --git a/src/Authoring/Studio/res/Tutorial/button_back@2x.png b/src/Authoring/Studio/res/Tutorial/button_back@2x.png new file mode 100644 index 00000000..ec6a2f13 Binary files /dev/null and b/src/Authoring/Studio/res/Tutorial/button_back@2x.png differ diff --git a/src/Authoring/Studio/res/Tutorial/button_next.png b/src/Authoring/Studio/res/Tutorial/button_next.png new file mode 100644 index 00000000..857dcada Binary files /dev/null and b/src/Authoring/Studio/res/Tutorial/button_next.png differ diff --git a/src/Authoring/Studio/res/Tutorial/button_next@2x.png b/src/Authoring/Studio/res/Tutorial/button_next@2x.png new file mode 100644 index 00000000..f32c4f26 Binary files /dev/null and b/src/Authoring/Studio/res/Tutorial/button_next@2x.png differ diff --git a/src/Authoring/Studio/res/Tutorial/screens/1.png b/src/Authoring/Studio/res/Tutorial/screens/1.png new file mode 100644 index 00000000..028f939f Binary files /dev/null and b/src/Authoring/Studio/res/Tutorial/screens/1.png differ diff --git a/src/Authoring/Studio/res/Tutorial/screens/2.png b/src/Authoring/Studio/res/Tutorial/screens/2.png new file mode 100644 index 00000000..9ba67e3b Binary files /dev/null and b/src/Authoring/Studio/res/Tutorial/screens/2.png differ diff --git a/src/Authoring/Studio/res/Tutorial/screens/3.png b/src/Authoring/Studio/res/Tutorial/screens/3.png new file mode 100644 index 00000000..849dfce7 Binary files /dev/null and b/src/Authoring/Studio/res/Tutorial/screens/3.png differ diff --git a/src/Authoring/Studio/res/Tutorial/screens/4.png b/src/Authoring/Studio/res/Tutorial/screens/4.png new file mode 100644 index 00000000..4933f401 Binary files /dev/null and b/src/Authoring/Studio/res/Tutorial/screens/4.png differ diff --git a/src/Authoring/Studio/res/Tutorial/screens/5.png b/src/Authoring/Studio/res/Tutorial/screens/5.png new file mode 100644 index 00000000..26adcf4b Binary files /dev/null and b/src/Authoring/Studio/res/Tutorial/screens/5.png differ diff --git a/src/Authoring/Studio/res/Tutorial/screens/6.png b/src/Authoring/Studio/res/Tutorial/screens/6.png new file mode 100644 index 00000000..25b7a5bf Binary files /dev/null and b/src/Authoring/Studio/res/Tutorial/screens/6.png differ diff --git a/src/Authoring/Studio/res/Tutorial/screens/7.png b/src/Authoring/Studio/res/Tutorial/screens/7.png new file mode 100644 index 00000000..9ed864a3 Binary files /dev/null and b/src/Authoring/Studio/res/Tutorial/screens/7.png differ diff --git a/src/Authoring/Studio/res/arrow_down.png b/src/Authoring/Studio/res/arrow_down.png new file mode 100644 index 00000000..b6cfcf77 Binary files /dev/null and b/src/Authoring/Studio/res/arrow_down.png differ diff --git a/src/Authoring/Studio/res/arrow_down@2x.png b/src/Authoring/Studio/res/arrow_down@2x.png new file mode 100644 index 00000000..5c409dcb Binary files /dev/null and b/src/Authoring/Studio/res/arrow_down@2x.png differ diff --git a/src/Authoring/Studio/res/client_tools_grayed_out.bmp b/src/Authoring/Studio/res/client_tools_grayed_out.bmp new file mode 100644 index 00000000..da15cc18 Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_grayed_out.bmp differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-00.png b/src/Authoring/Studio/res/client_tools_hi_color-00.png new file mode 100644 index 00000000..f466a1c3 Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-00.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-00@2x.png b/src/Authoring/Studio/res/client_tools_hi_color-00@2x.png new file mode 100644 index 00000000..0b68e6b3 Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-00@2x.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-01.png b/src/Authoring/Studio/res/client_tools_hi_color-01.png new file mode 100644 index 00000000..aad1b000 Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-01.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-01@2x.png b/src/Authoring/Studio/res/client_tools_hi_color-01@2x.png new file mode 100644 index 00000000..e9589689 Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-01@2x.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-02.png b/src/Authoring/Studio/res/client_tools_hi_color-02.png new file mode 100644 index 00000000..871a5e7d Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-02.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-02@2x.png b/src/Authoring/Studio/res/client_tools_hi_color-02@2x.png new file mode 100644 index 00000000..235d6804 Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-02@2x.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-03.png b/src/Authoring/Studio/res/client_tools_hi_color-03.png new file mode 100644 index 00000000..68a7848a Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-03.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-03@2x.png b/src/Authoring/Studio/res/client_tools_hi_color-03@2x.png new file mode 100644 index 00000000..bc861678 Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-03@2x.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-04.png b/src/Authoring/Studio/res/client_tools_hi_color-04.png new file mode 100644 index 00000000..0a2a7bc9 Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-04.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-04@2x.png b/src/Authoring/Studio/res/client_tools_hi_color-04@2x.png new file mode 100644 index 00000000..bdf10c1f Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-04@2x.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-05.png b/src/Authoring/Studio/res/client_tools_hi_color-05.png new file mode 100644 index 00000000..de315cab Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-05.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-05@2x.png b/src/Authoring/Studio/res/client_tools_hi_color-05@2x.png new file mode 100644 index 00000000..89ba3fba Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-05@2x.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-06.png b/src/Authoring/Studio/res/client_tools_hi_color-06.png new file mode 100644 index 00000000..eeb93638 Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-06.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color-06@2x.png b/src/Authoring/Studio/res/client_tools_hi_color-06@2x.png new file mode 100644 index 00000000..5fe71abb Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color-06@2x.png differ diff --git a/src/Authoring/Studio/res/client_tools_hi_color.bmp b/src/Authoring/Studio/res/client_tools_hi_color.bmp new file mode 100644 index 00000000..50f90ab7 Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_hi_color.bmp differ diff --git a/src/Authoring/Studio/res/client_tools_low_color.bmp b/src/Authoring/Studio/res/client_tools_low_color.bmp new file mode 100644 index 00000000..7dccd64e Binary files /dev/null and b/src/Authoring/Studio/res/client_tools_low_color.bmp differ diff --git a/src/Authoring/Studio/res/cursors.bmp b/src/Authoring/Studio/res/cursors.bmp new file mode 100644 index 00000000..dff7330e Binary files /dev/null and b/src/Authoring/Studio/res/cursors.bmp differ diff --git a/src/Authoring/Studio/res/edit_camera_pan.png b/src/Authoring/Studio/res/edit_camera_pan.png new file mode 100644 index 00000000..9248a875 Binary files /dev/null and b/src/Authoring/Studio/res/edit_camera_pan.png differ diff --git a/src/Authoring/Studio/res/edit_camera_rot.png b/src/Authoring/Studio/res/edit_camera_rot.png new file mode 100644 index 00000000..55c6ddac Binary files /dev/null and b/src/Authoring/Studio/res/edit_camera_rot.png differ diff --git a/src/Authoring/Studio/res/edit_camera_zoom.png b/src/Authoring/Studio/res/edit_camera_zoom.png new file mode 100644 index 00000000..46f69c43 Binary files /dev/null and b/src/Authoring/Studio/res/edit_camera_zoom.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_disabled.bmp b/src/Authoring/Studio/res/editcamera_tools_disabled.bmp new file mode 100644 index 00000000..53709e04 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_disabled.bmp differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-00.png b/src/Authoring/Studio/res/editcamera_tools_hi-00.png new file mode 100644 index 00000000..ad07bf8f Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-00.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-00@2x.png b/src/Authoring/Studio/res/editcamera_tools_hi-00@2x.png new file mode 100644 index 00000000..d8c5fc46 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-00@2x.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-00_disabled.png b/src/Authoring/Studio/res/editcamera_tools_hi-00_disabled.png new file mode 100644 index 00000000..f8499e9d Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-00_disabled.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-00_disabled@2x.png b/src/Authoring/Studio/res/editcamera_tools_hi-00_disabled@2x.png new file mode 100644 index 00000000..96564a1c Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-00_disabled@2x.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-01.png b/src/Authoring/Studio/res/editcamera_tools_hi-01.png new file mode 100644 index 00000000..10b16c6d Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-01.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-01@2x.png b/src/Authoring/Studio/res/editcamera_tools_hi-01@2x.png new file mode 100644 index 00000000..b872a674 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-01@2x.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-01_disabled.png b/src/Authoring/Studio/res/editcamera_tools_hi-01_disabled.png new file mode 100644 index 00000000..ce5d85d2 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-01_disabled.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-01_disabled@2x.png b/src/Authoring/Studio/res/editcamera_tools_hi-01_disabled@2x.png new file mode 100644 index 00000000..a4a93e53 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-01_disabled@2x.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-02.png b/src/Authoring/Studio/res/editcamera_tools_hi-02.png new file mode 100644 index 00000000..77b5a93e Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-02.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-02@2x.png b/src/Authoring/Studio/res/editcamera_tools_hi-02@2x.png new file mode 100644 index 00000000..13b2ce61 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-02@2x.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-02_disabled.png b/src/Authoring/Studio/res/editcamera_tools_hi-02_disabled.png new file mode 100644 index 00000000..a21cea23 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-02_disabled.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-02_disabled@2x.png b/src/Authoring/Studio/res/editcamera_tools_hi-02_disabled@2x.png new file mode 100644 index 00000000..bba1b104 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-02_disabled@2x.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-03.png b/src/Authoring/Studio/res/editcamera_tools_hi-03.png new file mode 100644 index 00000000..c8929b76 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-03.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-03@2x.png b/src/Authoring/Studio/res/editcamera_tools_hi-03@2x.png new file mode 100644 index 00000000..26292608 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-03@2x.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-03_disabled.png b/src/Authoring/Studio/res/editcamera_tools_hi-03_disabled.png new file mode 100644 index 00000000..db8944b2 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-03_disabled.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-03_disabled@2x.png b/src/Authoring/Studio/res/editcamera_tools_hi-03_disabled@2x.png new file mode 100644 index 00000000..15904fee Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-03_disabled@2x.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-04.png b/src/Authoring/Studio/res/editcamera_tools_hi-04.png new file mode 100644 index 00000000..22da1b6d Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-04.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-04@2x.png b/src/Authoring/Studio/res/editcamera_tools_hi-04@2x.png new file mode 100644 index 00000000..9110519b Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-04@2x.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-04_disabled.png b/src/Authoring/Studio/res/editcamera_tools_hi-04_disabled.png new file mode 100644 index 00000000..1d9e0ac0 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-04_disabled.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-04_disabled@2x.png b/src/Authoring/Studio/res/editcamera_tools_hi-04_disabled@2x.png new file mode 100644 index 00000000..0a3f5527 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-04_disabled@2x.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-05.png b/src/Authoring/Studio/res/editcamera_tools_hi-05.png new file mode 100644 index 00000000..147f8e29 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-05.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-05@2x.png b/src/Authoring/Studio/res/editcamera_tools_hi-05@2x.png new file mode 100644 index 00000000..844a61e4 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-05@2x.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-05_disabled.png b/src/Authoring/Studio/res/editcamera_tools_hi-05_disabled.png new file mode 100644 index 00000000..ee55b391 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-05_disabled.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi-05_disabled@2x.png b/src/Authoring/Studio/res/editcamera_tools_hi-05_disabled@2x.png new file mode 100644 index 00000000..072be7ed Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi-05_disabled@2x.png differ diff --git a/src/Authoring/Studio/res/editcamera_tools_hi.bmp b/src/Authoring/Studio/res/editcamera_tools_hi.bmp new file mode 100644 index 00000000..c2b73a43 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_hi.bmp differ diff --git a/src/Authoring/Studio/res/editcamera_tools_low.bmp b/src/Authoring/Studio/res/editcamera_tools_low.bmp new file mode 100644 index 00000000..66bf41a4 Binary files /dev/null and b/src/Authoring/Studio/res/editcamera_tools_low.bmp differ diff --git a/src/Authoring/Studio/res/group_move.png b/src/Authoring/Studio/res/group_move.png new file mode 100644 index 00000000..d7d06770 Binary files /dev/null and b/src/Authoring/Studio/res/group_move.png differ diff --git a/src/Authoring/Studio/res/group_rotate.png b/src/Authoring/Studio/res/group_rotate.png new file mode 100644 index 00000000..23a3eb3e Binary files /dev/null and b/src/Authoring/Studio/res/group_rotate.png differ diff --git a/src/Authoring/Studio/res/group_scale.png b/src/Authoring/Studio/res/group_scale.png new file mode 100644 index 00000000..64024dfe Binary files /dev/null and b/src/Authoring/Studio/res/group_scale.png differ diff --git a/src/Authoring/Studio/res/item_move.png b/src/Authoring/Studio/res/item_move.png new file mode 100644 index 00000000..d7b923bf Binary files /dev/null and b/src/Authoring/Studio/res/item_move.png differ diff --git a/src/Authoring/Studio/res/item_rotate.png b/src/Authoring/Studio/res/item_rotate.png new file mode 100644 index 00000000..514c567c Binary files /dev/null and b/src/Authoring/Studio/res/item_rotate.png differ diff --git a/src/Authoring/Studio/res/item_scale.png b/src/Authoring/Studio/res/item_scale.png new file mode 100644 index 00000000..6ef8acdb Binary files /dev/null and b/src/Authoring/Studio/res/item_scale.png differ diff --git a/src/Authoring/Studio/res/keyframe.bmp b/src/Authoring/Studio/res/keyframe.bmp new file mode 100644 index 00000000..39a5fa17 Binary files /dev/null and b/src/Authoring/Studio/res/keyframe.bmp differ diff --git a/src/Authoring/Studio/res/library_buttons_hi_color.bmp b/src/Authoring/Studio/res/library_buttons_hi_color.bmp new file mode 100644 index 00000000..b648bcae Binary files /dev/null and b/src/Authoring/Studio/res/library_buttons_hi_color.bmp differ diff --git a/src/Authoring/Studio/res/library_buttons_low_color.bmp b/src/Authoring/Studio/res/library_buttons_low_color.bmp new file mode 100644 index 00000000..682f3a2c Binary files /dev/null and b/src/Authoring/Studio/res/library_buttons_low_color.bmp differ diff --git a/src/Authoring/Studio/res/libtoolb.bmp b/src/Authoring/Studio/res/libtoolb.bmp new file mode 100644 index 00000000..2a07520a Binary files /dev/null and b/src/Authoring/Studio/res/libtoolb.bmp differ diff --git a/src/Authoring/Studio/res/menubtn_down.bmp b/src/Authoring/Studio/res/menubtn_down.bmp new file mode 100644 index 00000000..84df200b Binary files /dev/null and b/src/Authoring/Studio/res/menubtn_down.bmp differ diff --git a/src/Authoring/Studio/res/menubtn_normal.bmp b/src/Authoring/Studio/res/menubtn_normal.bmp new file mode 100644 index 00000000..f2357600 Binary files /dev/null and b/src/Authoring/Studio/res/menubtn_normal.bmp differ diff --git a/src/Authoring/Studio/res/menubtn_selected.bmp b/src/Authoring/Studio/res/menubtn_selected.bmp new file mode 100644 index 00000000..7bc4618d Binary files /dev/null and b/src/Authoring/Studio/res/menubtn_selected.bmp differ diff --git a/src/Authoring/Studio/res/menuedit.bmp b/src/Authoring/Studio/res/menuedit.bmp new file mode 100644 index 00000000..de0869ad Binary files /dev/null and b/src/Authoring/Studio/res/menuedit.bmp differ diff --git a/src/Authoring/Studio/res/menutool.bmp b/src/Authoring/Studio/res/menutool.bmp new file mode 100644 index 00000000..73b54017 Binary files /dev/null and b/src/Authoring/Studio/res/menutool.bmp differ diff --git a/src/Authoring/Studio/res/open_dialog.png b/src/Authoring/Studio/res/open_dialog.png new file mode 100644 index 00000000..c7e74ef0 Binary files /dev/null and b/src/Authoring/Studio/res/open_dialog.png differ diff --git a/src/Authoring/Studio/res/playback_tools_grayed.bmp b/src/Authoring/Studio/res/playback_tools_grayed.bmp new file mode 100644 index 00000000..0225b6db Binary files /dev/null and b/src/Authoring/Studio/res/playback_tools_grayed.bmp differ diff --git a/src/Authoring/Studio/res/playback_tools_hi.bmp b/src/Authoring/Studio/res/playback_tools_hi.bmp new file mode 100644 index 00000000..2047ac6b Binary files /dev/null and b/src/Authoring/Studio/res/playback_tools_hi.bmp differ diff --git a/src/Authoring/Studio/res/playback_tools_low-00.png b/src/Authoring/Studio/res/playback_tools_low-00.png new file mode 100644 index 00000000..d7cae98d Binary files /dev/null and b/src/Authoring/Studio/res/playback_tools_low-00.png differ diff --git a/src/Authoring/Studio/res/playback_tools_low-00@2x.png b/src/Authoring/Studio/res/playback_tools_low-00@2x.png new file mode 100644 index 00000000..88d6cf17 Binary files /dev/null and b/src/Authoring/Studio/res/playback_tools_low-00@2x.png differ diff --git a/src/Authoring/Studio/res/playback_tools_low-01.png b/src/Authoring/Studio/res/playback_tools_low-01.png new file mode 100644 index 00000000..bf4d7f59 Binary files /dev/null and b/src/Authoring/Studio/res/playback_tools_low-01.png differ diff --git a/src/Authoring/Studio/res/playback_tools_low-01@2x.png b/src/Authoring/Studio/res/playback_tools_low-01@2x.png new file mode 100644 index 00000000..8230c6e8 Binary files /dev/null and b/src/Authoring/Studio/res/playback_tools_low-01@2x.png differ diff --git a/src/Authoring/Studio/res/playback_tools_low-02.png b/src/Authoring/Studio/res/playback_tools_low-02.png new file mode 100644 index 00000000..471b2573 Binary files /dev/null and b/src/Authoring/Studio/res/playback_tools_low-02.png differ diff --git a/src/Authoring/Studio/res/playback_tools_low-02@2x.png b/src/Authoring/Studio/res/playback_tools_low-02@2x.png new file mode 100644 index 00000000..02370d25 Binary files /dev/null and b/src/Authoring/Studio/res/playback_tools_low-02@2x.png differ diff --git a/src/Authoring/Studio/res/playback_tools_low-03.png b/src/Authoring/Studio/res/playback_tools_low-03.png new file mode 100644 index 00000000..5c5f9018 Binary files /dev/null and b/src/Authoring/Studio/res/playback_tools_low-03.png differ diff --git a/src/Authoring/Studio/res/playback_tools_low-03@2x.png b/src/Authoring/Studio/res/playback_tools_low-03@2x.png new file mode 100644 index 00000000..e6fe8e10 Binary files /dev/null and b/src/Authoring/Studio/res/playback_tools_low-03@2x.png differ diff --git a/src/Authoring/Studio/res/playback_tools_low.bmp b/src/Authoring/Studio/res/playback_tools_low.bmp new file mode 100644 index 00000000..cb9b6b29 Binary files /dev/null and b/src/Authoring/Studio/res/playback_tools_low.bmp differ diff --git a/src/Authoring/Studio/res/prefstab-00.png b/src/Authoring/Studio/res/prefstab-00.png new file mode 100644 index 00000000..8a452d15 Binary files /dev/null and b/src/Authoring/Studio/res/prefstab-00.png differ diff --git a/src/Authoring/Studio/res/prefstab-00@2x.png b/src/Authoring/Studio/res/prefstab-00@2x.png new file mode 100644 index 00000000..5703d0be Binary files /dev/null and b/src/Authoring/Studio/res/prefstab-00@2x.png differ diff --git a/src/Authoring/Studio/res/prefstab-01.png b/src/Authoring/Studio/res/prefstab-01.png new file mode 100644 index 00000000..35c99cea Binary files /dev/null and b/src/Authoring/Studio/res/prefstab-01.png differ diff --git a/src/Authoring/Studio/res/prefstab-01@2x.png b/src/Authoring/Studio/res/prefstab-01@2x.png new file mode 100644 index 00000000..4c35e2b0 Binary files /dev/null and b/src/Authoring/Studio/res/prefstab-01@2x.png differ diff --git a/src/Authoring/Studio/res/prefstab.bmp b/src/Authoring/Studio/res/prefstab.bmp new file mode 100644 index 00000000..3201d15e Binary files /dev/null and b/src/Authoring/Studio/res/prefstab.bmp differ diff --git a/src/Authoring/Studio/res/preview_tools.bmp b/src/Authoring/Studio/res/preview_tools.bmp new file mode 100644 index 00000000..2cfdbfd9 Binary files /dev/null and b/src/Authoring/Studio/res/preview_tools.bmp differ diff --git a/src/Authoring/Studio/res/project-icon-new.bmp b/src/Authoring/Studio/res/project-icon-new.bmp new file mode 100644 index 00000000..01123652 Binary files /dev/null and b/src/Authoring/Studio/res/project-icon-new.bmp differ diff --git a/src/Authoring/Studio/res/project-icon-open.bmp b/src/Authoring/Studio/res/project-icon-open.bmp new file mode 100644 index 00000000..50b279f7 Binary files /dev/null and b/src/Authoring/Studio/res/project-icon-open.bmp differ diff --git a/src/Authoring/Studio/res/qt3ds_header.bmp b/src/Authoring/Studio/res/qt3ds_header.bmp new file mode 100644 index 00000000..cfe81cc2 Binary files /dev/null and b/src/Authoring/Studio/res/qt3ds_header.bmp differ diff --git a/src/Authoring/Studio/res/separator.png b/src/Authoring/Studio/res/separator.png new file mode 100644 index 00000000..c86aac17 Binary files /dev/null and b/src/Authoring/Studio/res/separator.png differ diff --git a/src/Authoring/Studio/res/separator@2x.png b/src/Authoring/Studio/res/separator@2x.png new file mode 100644 index 00000000..052003a4 Binary files /dev/null and b/src/Authoring/Studio/res/separator@2x.png differ diff --git a/src/Authoring/Studio/res/stmtool.bmp b/src/Authoring/Studio/res/stmtool.bmp new file mode 100644 index 00000000..71ed95fc Binary files /dev/null and b/src/Authoring/Studio/res/stmtool.bmp differ diff --git a/src/Authoring/Studio/res/storagep.bmp b/src/Authoring/Studio/res/storagep.bmp new file mode 100644 index 00000000..d784a3dc Binary files /dev/null and b/src/Authoring/Studio/res/storagep.bmp differ diff --git a/src/Authoring/Studio/res/tmchmenu.bmp b/src/Authoring/Studio/res/tmchmenu.bmp new file mode 100644 index 00000000..329bbf96 Binary files /dev/null and b/src/Authoring/Studio/res/tmchmenu.bmp differ diff --git a/src/Authoring/Studio/res/tmlntool.bmp b/src/Authoring/Studio/res/tmlntool.bmp new file mode 100644 index 00000000..6678d093 Binary files /dev/null and b/src/Authoring/Studio/res/tmlntool.bmp differ diff --git a/src/Authoring/Studio/res/tmtbmenu.bmp b/src/Authoring/Studio/res/tmtbmenu.bmp new file mode 100644 index 00000000..ddf00990 Binary files /dev/null and b/src/Authoring/Studio/res/tmtbmenu.bmp differ diff --git a/src/Authoring/Studio/res/weblinkc.bmp b/src/Authoring/Studio/res/weblinkc.bmp new file mode 100644 index 00000000..e9f941b4 Binary files /dev/null and b/src/Authoring/Studio/res/weblinkc.bmp differ diff --git a/src/Authoring/Studio/res/winxp1.bin b/src/Authoring/Studio/res/winxp1.bin new file mode 100644 index 00000000..065c2edf --- /dev/null +++ b/src/Authoring/Studio/res/winxp1.bin @@ -0,0 +1,22 @@ + + + + Test Application + + + + + + diff --git a/src/Authoring/Studio/style.qss b/src/Authoring/Studio/style.qss new file mode 100644 index 00000000..1bb92ddc --- /dev/null +++ b/src/Authoring/Studio/style.qss @@ -0,0 +1,219 @@ +/* General coloring and font size */ +QWidget { + color: #ffffff; + background: #2e2f30; + font-size: 12px; + border: 0px; +} + +/* DockWidget separators */ +QMainWindow::separator { + background: #000000; + width: 1px; /* when vertical */ + height: 1px; /* when horizontal */ +} + +/* Tabs */ +QTabBar::tab:selected { + background: #2e2f30; + padding: 5px; +} + +QTabBar::tab:!selected { + background: #262829; + color: #727476; + padding: 5px; +} + +QTabWidget::pane { + border: 1px solid #404244; +} + +/* Scrollbar */ +QScrollBar:horizontal { + border: 1px solid #262829; + background: #404244; +} + +QScrollBar::handle:horizontal { + background: #727476; +} + +QScrollBar::add-line:horizontal, +QScrollBar::sub-line:horizontal { + width: 0px; +} + +QScrollBar:vertical { + border: 1px solid #262829; + background: #404244; +} + +QScrollBar::handle:vertical { + background: #727476; +} + +QScrollBar::add-line:vertical, +QScrollBar::sub-line:vertical { + height: 0px; +} + +/* Menubar */ +QMenuBar { + background: #404244; + border-top: 1px solid #262829; +} + +QMenuBar::item { + background: transparent; +} + +QMenuBar::item:selected { + background: #46a2da; + border: 1px solid #262829; +} + +/* Menu */ +QMenu { + background: #262829; + border: 1px solid #727476; +} + +QMenu::item { + padding: 4px 20px 4px 20px; +} + +QMenu::item:selected:enabled { + background: #46a2da; +} + +QMenu::item:disabled { + padding: 4px 20px 4px 20px; + color: #727476; +} + +QMenu::separator { + height: 1px; + background: #727476; +} + +/* Toolbar */ +QToolBar { + background: #404244; + border-top: 1px solid #262829; + min-height: 24px; + max-height: 24px; +} + +QToolBar::handle { + image: url(:/res/separator.png); +} + +QToolBar::separator { + background: #727476; + width: 1px; + margin: 3px; +} + +QToolButton:!checked { + min-width: 22px; + min-height: 22px; + background-color: #404244; +} + +QToolButton:checked, QToolButton:hover { + min-width: 22px; + min-height: 22px; + background-color: #262829; +} + +QToolButton:pressed { + min-width: 22px; + min-height: 22px; + background-color: #46a2da; +} + +QComboBox#cameraSelector { + /* We have a specific style for camera selector combobox, as it's in the toolbar and needs to + blend in */ + background: #404244; + border: 0px; + border-radius: 0; + padding: 3px; +} + +/* ToolTip */ +QToolTip { + background: #404244; + color: #ffffff; + font-size: 12px; + border: 1px solid #727476; + border-radius: 2; +} + +/* Dialog widgets */ +QComboBox, +QLineEdit, +QSpinBox, +QTimeEdit { + background: #404244; + border: 1px solid #262829; + border-radius: 2; + padding: 3px; +} + +QComboBox::drop-down { + background: #404244; +} + +QComboBox::down-arrow { + image: url(:/res/arrow_down.png); +} + +QGroupBox { + padding: 14px 0px 0px 0px; + border: 1px solid #262829; +} + +QGroupBox::title { + subcontrol-origin: padding; + margin-top: 2px; + margin-left: 10px; +} + +QPushButton { + background: #404244; + border: 1px solid #262829; + border-radius: 2; + padding: 3px 10px 3px 10px; + min-width: 75; +} + +/* Tutorial Dialog */ +QDialog#StudioTutorialWidget, +QDialog#StudioTutorialWidget QWidget { + color: #ffffff; + background-color: transparent; + border: 0px; +} + +QPushButton:!pressed#studioTutorialOpen, +QPushButton:!pressed#studioTutorialNew { + background: transparent; + border: 1px solid #41cd52; +} + +QPushButton:pressed#studioTutorialOpen, +QPushButton:pressed#studioTutorialNew { + background: #41cd52; + border: 1px solid #41cd52; +} + +/* Startup Dialog */ +QDialog#StartupDlg, +QDialog#StartupDlg QWidget { + color: #ffffff; + background-color: transparent; + border: 0px; + font-size: 16px; +} diff --git a/src/Authoring/Studio/version.h b/src/Authoring/Studio/version.h new file mode 100644 index 00000000..118d95b5 --- /dev/null +++ b/src/Authoring/Studio/version.h @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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_VERSION + +#ifdef WIN32 +#include "..\Build\VersionNumber.h" +#endif + +#endif -- cgit v1.2.3