diff options
author | Pasi Keränen <pasi.keranen@qt.io> | 2019-06-05 13:22:33 +0300 |
---|---|---|
committer | Pasi Keränen <pasi.keranen@qt.io> | 2019-06-10 21:22:35 +0300 |
commit | fa46a1dc716c499b5eefdfd8f0cfcfc8ac303937 (patch) | |
tree | 61f7f6eed72822cf39a52769dfaba24d1bde9522 /src/Authoring/Qt3DStudio/MainFrm.cpp | |
parent | fe7649841f68c6fe99bf08e477df77770c7dffa0 (diff) |
Switch to qt3dstudio/ogl-runtime submodule
Module config change so that ogl-runtime builds from submodule.
Task-number: QT3DS-3600
Change-Id: Ib22fda6aed1cf9336f15b79256b5f9db8774159f
Reviewed-by: Pasi Keränen <pasi.keranen@qt.io>
Diffstat (limited to 'src/Authoring/Qt3DStudio/MainFrm.cpp')
-rw-r--r-- | src/Authoring/Qt3DStudio/MainFrm.cpp | 1932 |
1 files changed, 1932 insertions, 0 deletions
diff --git a/src/Authoring/Qt3DStudio/MainFrm.cpp b/src/Authoring/Qt3DStudio/MainFrm.cpp new file mode 100644 index 00000000..110ada26 --- /dev/null +++ b/src/Authoring/Qt3DStudio/MainFrm.cpp @@ -0,0 +1,1932 @@ +/**************************************************************************** +** +** Copyright (C) 2002 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** 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 "MainFrm.h" +#include "ui_MainFrm.h" +#include "StudioConst.h" +#include "SceneView.h" +#include "StudioApp.h" +#include "IKeyframesManager.h" +#include "Dialogs.h" +#include "StudioPreferencesPropSheet.h" +#include "StudioPreferences.h" +#include "HotKeys.h" +#include "RecentItems.h" +#include "PaletteManager.h" +#include "Core.h" +#include "ITickTock.h" +#include "IStudioRenderer.h" +#include "DataInputListDlg.h" +#include "StudioTutorialWidget.h" +#include "remotedeploymentsender.h" +#include "InspectorControlView.h" +#include "TimelineWidget.h" +#include "ProjectView.h" +#include "RowTree.h" +#include "WidgetControl.h" +#include "SlideView.h" +#include "FilterVariantsDlg.h" +#include "PreviewHelper.h" + +#include <QtGui/qevent.h> +#include <QtGui/qdesktopservices.h> +#include <QtCore/qsettings.h> +#include <QtCore/qurl.h> +#include <QtCore/qprocess.h> +#include <QtGui/qfontdatabase.h> + +// Constants +const long PLAYBACK_TIMER_TIMEOUT = 10; // milliseconds + +CMainFrame::CMainFrame() + : m_ui(new Ui::MainFrame) + , m_remoteDeploymentSender(new RemoteDeploymentSender(this)) + , m_updateUITimer(new QTimer) + , m_playbackTimer(new QTimer) +{ + m_ui->setupUi(this); + + // allow styling this action + m_ui->m_PlaybackToolbar->widgetForAction(m_ui->actionFilterVariants) + ->setObjectName("actionFilterVariants"); + + // Register TitilliumWeb as application font in case user doesn't have it already installed + QFontDatabase::addApplicationFont(QStringLiteral(":/TitilliumWeb-Light.ttf")); + QFontDatabase::addApplicationFont(QStringLiteral(":/TitilliumWeb-Regular.ttf")); + + 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); + + // File Menu + connect(m_ui->action_New_Project, &QAction::triggered, this, &CMainFrame::OnProjectNew); + connect(m_ui->action_New_Presentation, &QAction::triggered, this, &CMainFrame::OnFileNew); + connect(m_ui->action_Open, &QAction::triggered, this, &CMainFrame::OnFileOpen); + connect(m_ui->action_Save, &QAction::triggered, this, &CMainFrame::OnFileSave); + connect(m_ui->action_Save_Project_As, &QAction::triggered, this, &CMainFrame::onProjectSaveAs); + connect(m_ui->action_Duplicate_Presentation, &QAction::triggered, + this, &CMainFrame::onDuplicatePresentation); + connect(m_ui->action_Revert, &QAction::triggered, this, &CMainFrame::OnFileRevert); + connect(m_ui->actionImportAssets, &QAction::triggered, this, &CMainFrame::OnFileImportAssets); + connect(m_ui->actionData_Inputs, &QAction::triggered, this, &CMainFrame::OnFileDataInputs); + connect(m_ui->action_Connect_to_Device, &QAction::triggered, this, + &CMainFrame::OnFileConnectToDevice); + m_recentItems.reset(new CRecentItems(m_ui->menuRecent_Projects)); + connect(m_recentItems.data(), &CRecentItems::openRecent, this, &CMainFrame::OnFileOpenRecent); + connect(m_ui->action_Exit, &QAction::triggered, this, &CMainFrame::close); + + // 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->actionRepeat, &QAction::triggered, this, &CMainFrame::onEditRepeat); // TODO: Implement + connect(m_ui->action_Cut, &QAction::triggered, this, &CMainFrame::OnEditCut); + connect(m_ui->action_Copy, &QAction::triggered, this, &CMainFrame::OnEditCopy); + connect(m_ui->action_Paste, &QAction::triggered, this, &CMainFrame::OnEditPaste); + connect(m_ui->actionPaste_to_Master_Slide, &QAction::triggered, + this, &CMainFrame::onEditPasteToMaster); + connect(m_ui->action_Duplicate_Object, &QAction::triggered, this, &CMainFrame::OnEditDuplicate); + connect(m_ui->actionDelete, &QAction::triggered, this, &CMainFrame::onEditDelete); + connect(m_ui->actionGroup, &QAction::triggered, this, &CMainFrame::onEditGroup); +// connect(m_ui->actionParent, &QAction::triggered, this, &CMainFrame::onEditParent); // TODO: Implement +// connect(m_ui->actionUnparent, &QAction::triggered, this, &CMainFrame::onEditUnparent); // TODO: Implement + connect(m_ui->actionStudio_Preferences, &QAction::triggered, + this, &CMainFrame::OnEditApplicationPreferences); + connect(m_ui->actionPresentation_Settings, &QAction::triggered, + this, &CMainFrame::OnEditPresentationPreferences); + connect(m_ui->menu_Edit, &QMenu::aboutToShow, [this]() { + // macOS doesn't block menubar while startup dialog is being shown, and that causes a + // crash on aboutToShow if it's called before everything is set + if (m_ui->menu_Edit->isEnabled()) { + QString type = g_StudioApp.getDuplicateType(); + QString label = tr("Duplicate %1").arg(type); + m_ui->action_Duplicate_Object->setText(label); + m_ui->action_Duplicate_Object->setEnabled(!type.isEmpty()); + + type = g_StudioApp.getDeleteType(); + label = tr("Delete %1").arg(type); + m_ui->actionDelete->setText(label); + m_ui->actionDelete->setEnabled(!type.isEmpty()); + + if (g_StudioApp.canUngroupSelectedObjects()) { + m_ui->actionGroup->setText(tr("Ungroup Objects")); + m_ui->actionGroup->setEnabled(true); + } else { + m_ui->actionGroup->setText(tr("Group Objects")); + m_ui->actionGroup->setEnabled(g_StudioApp.canGroupSelectedObjects()); + } + } + }); + connect(m_ui->menu_Edit, &QMenu::aboutToHide, [this]() { + // Enable potentially disabled items so hotkeys will work + m_ui->action_Duplicate_Object->setEnabled(true); + m_ui->actionDelete->setEnabled(true); + m_ui->actionGroup->setEnabled(true); + }); + + // View Menu + connect(m_ui->actionReset_layout, &QAction::triggered, this, &CMainFrame::onViewResetLayout); + connect(m_ui->actionFit_Selected, &QAction::triggered, + this, &CMainFrame::OnEditCameraZoomExtent); +// connect(m_ui->actionFit_all, &QAction::triggered, this, &CMainFrame::onViewFitAll); // TODO: Implement + connect(m_ui->actionToggle_hide_unhide_selected, &QAction::triggered, + []() { g_StudioApp.toggleEyeball(); }); +// connect(m_ui->actionToggle_hide_unhide_unselected, &QAction::triggered, +// []() { }); // TODO: Implement? + connect(m_ui->actionAction, &QAction::triggered, this, &CMainFrame::OnViewAction); + connect(m_ui->actionBasic_Objects, &QAction::triggered, this, &CMainFrame::OnViewBasicObjects); + connect(m_ui->actionInspector, &QAction::triggered, this, &CMainFrame::OnViewInspector); + connect(m_ui->actionProject, &QAction::triggered, this, &CMainFrame::OnViewProject); + connect(m_ui->actionSlide, &QAction::triggered, this, &CMainFrame::OnViewSlide); + connect(m_ui->actionTimeline, &QAction::triggered, this, &CMainFrame::OnViewTimeline); + connect(m_ui->actionSceneCamera, &QAction::triggered, this, &CMainFrame::onViewSceneCamera); + 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); + connect(m_ui->actionCamera_Preview, &QAction::triggered, this, &CMainFrame::OnShowEditPreview); + connect(m_ui->actionEdit_Lighting, &QAction::triggered, this, + &CMainFrame::OnEditViewLightingEnabled); +// connect(m_ui->actionFind, &QAction::triggered, this, &CMainFrame::onViewFind); // TODO: Implement + + // Timeline Menu + connect(m_ui->actionSet_Changed_Keyframes, &QAction::triggered, + this, &CMainFrame::OnTimelineSetChangedKeyframe); + connect(m_ui->actionDelete_Selected_Keyframe_s, &QAction::triggered, + [](){ g_StudioApp.DeleteSelectedKeys(); }); + 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->actionAutoset_Keyframes, &QAction::triggered, + this, &CMainFrame::OnToolAutosetkeys); + + // 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); + + // Selection toolbar + connect(m_ui->actionItem_Select_Tool, &QAction::triggered, + m_sceneView.data(), &CSceneView::onToolItemSelection); + connect(m_ui->actionGroup_Select_Tool, &QAction::triggered, + m_sceneView.data(), &CSceneView::onToolGroupSelection); + + // Playback toolbar + connect(m_ui->actionPreview, &QAction::triggered, + this, &CMainFrame::OnPlaybackPreviewOpenGLRuntime); + connect(m_ui->actionFilterVariants, &QAction::triggered, this, &CMainFrame::onFilterVariants); + + connect(m_ui->actionRemote_Preview, &QAction::triggered, + this, &CMainFrame::OnPlaybackPreviewRemote); + + // Only show Qt3D runtime preview if we have appropriate viewer and it's enabled + if (CStudioPreferences::IsLegacyViewerActive() + && QFileInfo(CPreviewHelper::getViewerFilePath(QStringLiteral("q3dsviewer"))).exists()) { + connect(m_ui->actionPreviewQt3DRuntime, &QAction::triggered, + this, &CMainFrame::OnPlaybackPreviewQt3DRuntime); + m_ui->actionPreviewQt3DRuntime->setVisible(true); + } else { + m_ui->actionPreviewQt3DRuntime->setVisible(false); + } + + // Tool mode toolbar + connect(m_ui->actionPosition_Tool, &QAction::triggered, this, + std::bind(&CMainFrame::onTransformToolChanged, this, STUDIO_TOOLMODE_MOVE)); + connect(m_ui->actionRotation_Tool, &QAction::triggered, this, + std::bind(&CMainFrame::onTransformToolChanged, this, STUDIO_TOOLMODE_ROTATE)); + connect(m_ui->actionScale_Tool, &QAction::triggered, this, + std::bind(&CMainFrame::onTransformToolChanged, this, STUDIO_TOOLMODE_SCALE)); + connect(m_ui->actionLocal_Global_Manipulators, &QAction::triggered, + this, &CMainFrame::OnToolGlobalManipulators); + + // Edit Camera toolbar +#if 0 // TODO: Disabled until UX decision is made if these buttons are needed at all or not + 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); +#endif + 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); + + // Others + connect(m_remoteDeploymentSender.data(), &RemoteDeploymentSender::connectionChanged, + this, &CMainFrame::OnConnectionChanged); + + // Hide unimplemented menu items + m_ui->actionRepeat->setVisible(false); + m_ui->actionParent->setVisible(false); + m_ui->actionUnparent->setVisible(false); + m_ui->actionFit_all->setVisible(false); + m_ui->actionToggle_hide_unhide_unselected->setVisible(false); + m_ui->actionFind->setVisible(false); + + // TODO: better solution? + m_updateUITimer->start(500); + connect(m_updateUITimer.data(), &QTimer::timeout, [&]() { + if (QApplication::activeWindow() != this) + return; + + OnUpdateFileSave(); + OnUpdateEditUndo(); + OnUpdateEditRedo(); + OnUpdateEditCopy(); + OnUpdateEditCut(); + OnUpdateToolAutosetkeys(); + OnUpdateEditPaste(); + OnUpdateTimelineDeleteSelectedKeyframes(); + OnUpdateTimelineSetInterpolation(); + OnUpdateTimelineSetTimeBarColor(); + OnUpdateViewBoundingBoxes(); + OnUpdateViewPivotPoint(); + OnUpdateViewWireframe(); + OnUpdateViewTooltips(); + OnUpdateViewTimeline(); + onUpdateViewSceneCamera(); + OnUpdateViewInspector(); + OnUpdateViewAction(); + OnUpdateViewBasicObjects(); + OnUpdateViewProject(); + OnUpdateViewSlide(); + OnUpdateHelpIndex(); + OnUpdatePlaybackPlay(); + OnUpdatePlaybackPreview(); + OnUpdateToolGlobalManipulators(); + OnUpdateToolGroupSelection(); + OnUpdateToolItemSelection(); + OnUpdateCameraZoomExtentAndAuthorZoom(); + OnUpdateEditCameraPan(); + OnUpdateEditCameraRotate(); + OnUpdateEditCameraZoom(); + OnUpdateEditViewFillMode(); + OnUpdateViewGuidesRulers(); + OnUpdateClearGuides(); + OnUpdateLockGuides(); + OnUpdateCameraPreview(); + OnUpdateEditViewLightingEnabled(); + }); + + m_playbackTimer->setInterval(PLAYBACK_TIMER_TIMEOUT); + connect(m_playbackTimer.data(), &QTimer::timeout, this, &CMainFrame::onPlaybackTimeout); + qApp->installEventFilter(this); +} + +CMainFrame::~CMainFrame() +{ + qApp->removeEventFilter(this); + m_playbackTimer->stop(); + m_updateUITimer->stop(); +} + +// Timer callback +void CMainFrame::onPlaybackTimeout() +{ + // Timer callback that drives playback + Q_ASSERT(&g_StudioApp); + g_StudioApp.GetCore()->GetDoc()->ClientStep(); +} + +/** + * Called when the main frame is actually created. Sets up tool bars and default + * views. + */ +void CMainFrame::OnCreate() +{ + m_sceneView.reset(new CSceneView(this)); + connect(m_sceneView.data(), &CSceneView::toolChanged, this, &CMainFrame::OnUpdateToolChange); + + m_sceneView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + // tell the edit camera bar about this scene view + m_ui->m_EditCamerasBar->setSceneView(m_sceneView.data()); + + // 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) { + QString theMostRecentOpen; + if (m_recentItems && m_recentItems->GetItemCount() > 0) + theMostRecentOpen = m_recentItems->GetItem(0); + if (theMostRecentOpen.isEmpty()) // default to exe + theMostRecentOpen = Qt3DSFile::GetApplicationDirectory(); + + theDialogs->ResetSettings(theMostRecentOpen); + } + + // create the variants filtering dialog, singleShot is used so that actionGeom is calculated + // correctly + QTimer::singleShot(0, this, [&] { + QRect actionGeom = m_ui->m_PlaybackToolbar->actionGeometry(m_ui->actionFilterVariants); + auto *actionWidget = m_ui->m_PlaybackToolbar->widgetForAction(m_ui->actionFilterVariants); + m_filterVariantsDlg.reset(new FilterVariantsDlg(this, m_ui->actionFilterVariants, + actionGeom.width(), actionWidget)); + }); + + // Create the view manager + m_paletteManager.reset(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; + + // Disable toolbars and menus until we have a presentation + m_ui->m_ClientToolsBar->setEnabled(false); + m_ui->m_EditCamerasBar->setEnabled(false); + m_ui->m_PlaybackToolbar->setEnabled(false); + m_ui->menu_Edit->setEnabled(false); + m_ui->menu_Timeline->setEnabled(false); + m_ui->menu_View->setEnabled(false); + m_ui->action_Save_Project_As->setEnabled(false); + m_ui->action_Duplicate_Presentation->setEnabled(false); + m_ui->action_Connect_to_Device->setEnabled(false); + m_ui->action_Revert->setEnabled(false); + m_ui->actionImportAssets->setEnabled(false); + m_ui->actionRemote_Preview->setEnabled(false); + m_ui->action_New_Presentation->setEnabled(false); + m_ui->actionData_Inputs->setEnabled(false); + +#if 1 // TODO: Hidden until UX decision is made if these buttons are needed at all or not + m_ui->actionPan_Tool->setVisible(false); + m_ui->actionOrbit_Tool->setVisible(false); + m_ui->actionZoom_Tool->setVisible(false); +#endif + + // Show a message about opening or creating a presentation + m_sceneView.data()->setVisible(false); + setCentralWidget(m_ui->infoText); +} + +/** + * 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() +{ + // Make sure scene is visible + showScene(); + + // Associate the scene object with the scene view + m_ui->m_EditCamerasBar->setupCameras(); + // Enable dockables, toolbars, and menus + m_paletteManager->EnablePalettes(); + m_ui->m_ClientToolsBar->setEnabled(true); + m_ui->m_EditCamerasBar->setEnabled(true); + m_ui->m_PlaybackToolbar->setEnabled(true); + m_ui->menu_Edit->setEnabled(true); + m_ui->menu_Timeline->setEnabled(true); + m_ui->menu_View->setEnabled(true); + m_ui->action_Save_Project_As->setEnabled(true); + m_ui->action_Duplicate_Presentation->setEnabled(true); + m_ui->action_Connect_to_Device->setEnabled(true); + m_ui->action_Revert->setEnabled(true); + m_ui->actionImportAssets->setEnabled(true); + m_ui->action_New_Presentation->setEnabled(true); + m_ui->actionData_Inputs->setEnabled(true); + + // Clear data input list and sub-presentation list + g_StudioApp.m_subpresentations.clear(); + g_StudioApp.m_dataInputDialogItems.clear(); + + // reset the variants filter and preview button's icon + m_filterVariantsDlg->clearFilter(); + updateToolbarVariantsIcons(false); +} + +/** + * 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(); +} + +/** + * 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() +{ + // TODO: Actions cannot currently be copied/cut/pasted via main edit menu + // ActionView handles action copy/cut/paste internally + if (g_StudioApp.CanCopy()) { + QString theDescription = tr("Copy %1\tCtrl+C").arg(g_StudioApp.GetCopyType()); + + m_ui->action_Copy->setText(theDescription); + 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()) { + QString theDescription = tr("Cut %1\tCtrl+X").arg(g_StudioApp.GetCopyType()); + + m_ui->action_Cut->setText(theDescription); + 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(); +} + +void CMainFrame::onEditPasteToMaster() +{ + g_StudioApp.GetCore()->GetDoc()->HandleMasterPaste(); +} + +/** + * 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()) { + QString theUndoDescription = tr("Paste %1\tCtrl+V").arg(g_StudioApp.GetPasteType()); + + m_ui->action_Paste->setText(theUndoDescription); + + m_ui->action_Paste->setEnabled(true); + m_ui->actionPaste_to_Master_Slide->setEnabled(true); + } else { + m_ui->action_Paste->setEnabled(false); + m_ui->actionPaste_to_Master_Slide->setEnabled(false); + } +} + +/** + * 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.GetManipulationMode() + == StudioManipulationModes::Global); + +#if 0 // TODO: Disabled until UX decision is made if these buttons are needed at all or not + 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); +#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() +{ + getTimelineWidget()->openBarColorDialog(); +} + +/** + * 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(); +} + +/** + * 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(getTimelineWidget()->hasSelectedKeyframes()); +} + +/** + * 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(getTimelineWidget()->hasSelectedKeyframes()); +} + +/** + * OnEditDuplicate: Handles the ID_EDIT_DUPLICATE message. + * + * Pass through to the doc. + */ +void CMainFrame::OnEditDuplicate() +{ + g_StudioApp.HandleDuplicateCommand(); +} + +void CMainFrame::onEditDelete() +{ + g_StudioApp.DeleteSelectedObject(); +} + +void CMainFrame::onEditGroup() +{ + if (!g_StudioApp.ungroupSelectedObjects()) + g_StudioApp.groupSelectedObjects(); +} + +/** + * 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 Project As menu option. + */ +void CMainFrame::onProjectSaveAs() +{ + g_StudioApp.onProjectSaveAs(); +} + +/** + * Command handler for the File Duplicate Presentation menu option. + */ +void CMainFrame::onDuplicatePresentation() +{ + g_StudioApp.duplicatePresentation(); +} + +/** + * Command handler for the New Project menu option. + * This will also create a new default presentation. + */ +void CMainFrame::OnProjectNew() +{ + g_StudioApp.OnProjectNew(); +} + +void CMainFrame::OnFileNew() +{ + g_StudioApp.OnFileNew(); +} + +// Ctrl+<1..9> handler, change view +void CMainFrame::onCtrlNPressed() +{ + QAction *action = qobject_cast<QAction *>(sender()); + Q_ASSERT(action); + QKeySequence shortcut = action->shortcut(); + QChar c = shortcut.toString().back(); + if (shortcut.matches(Qt::CTRL | static_cast<Qt::Key>(c.unicode())) == QKeySequence::ExactMatch) + m_ui->m_EditCamerasBar->setCameraIndex(c.digitValue() == 1 ? 9 : c.digitValue() - 2); +} + +/** + * Overrides the close method to prompt if the document is modified. + */ +void CMainFrame::closeEvent(QCloseEvent *event) +{ + handleGeometryAndState(true); + 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; + } else if (theResult == CDialogs::CANCEL_OPERATION) { + // On cancel ditch out of here and abort exit. Abort! Abort! + event->ignore(); + return; + } + } + + // Tell the app to shutdown, do it here so it does not rely on static destructor. + QTimer::singleShot(0, &g_StudioApp, &CStudioApp::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 data input dialog. + */ +void CMainFrame::OnFileDataInputs() +{ + CDataInputListDlg dataInputDlg(&(g_StudioApp.m_dataInputDialogItems)); + dataInputDlg.exec(); + + if (dataInputDlg.result() == QDialog::Accepted) + g_StudioApp.saveDataInputsToProjectFile(); +} + +/** + * 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 + m_propSheet.reset(new CStudioPreferencesPropSheet(tr("Studio Preferences"), this, inPageIndex)); + + // Display the CStudioPreferencesPropSheet + int thePrefsReturn = m_propSheet->exec(); + + m_sceneView->onEditCameraChanged(); + + if (thePrefsReturn == PREFS_RESET_DEFAULTS) { + // Restore default values + g_StudioApp.SetAutosetKeyframes(true); // Sets the preference as well + CStudioPreferences::SetBoundingBoxesOn(true); + CStudioPreferences::SetDisplayPivotPoint(true); + CStudioPreferences::SetWireframeModeOn(true); + CStudioPreferences::SetShowTooltips(true); + CStudioPreferences::SetTimebarDisplayTime(false); + g_StudioApp.GetCore()->GetDoc()->SetDefaultKeyframeInterpolation(true); + CStudioPreferences::SetSnapRange(CStudioPreferences::DEFAULT_SNAPRANGE); + CStudioPreferences::SetDefaultObjectLifetime(CStudioPreferences::DEFAULT_LIFETIME); + CStudioPreferences::SetAdvancePropertyExpandedFlag(false); + CStudioPreferences::SetPreviewConfig(""); + CStudioPreferences::SetPreviewProperty("", ""); + CStudioPreferences::SetDontShowGLVersionDialog(false); + CStudioPreferences::SetDefaultClientSize(CStudioPreferences::DEFAULT_CLIENT_WIDTH, + CStudioPreferences::DEFAULT_CLIENT_HEIGHT); + CStudioPreferences::SetTimeAdvanceAmount(CStudioPreferences::DEFAULT_TIME_ADVANCE); + CStudioPreferences::SetBigTimeAdvanceAmount(CStudioPreferences::DEFAULT_BIG_TIME_ADVANCE); + CStudioPreferences::SetTimelineSnappingGridActive(true); + CStudioPreferences::SetTimelineSnappingGridResolution(SNAPGRID_SECONDS); + CStudioPreferences::SetLegacyViewerActive(true); + CStudioPreferences::SetEditViewFillMode(true); + CStudioPreferences::SetPreferredStartupView( + CStudioPreferences::PREFERREDSTARTUP_DEFAULTINDEX); + CStudioPreferences::SetAutoSaveDelay(CStudioPreferences::DEFAULT_AUTOSAVE_DELAY); + CStudioPreferences::SetAutoSavePreference(true); + CStudioPreferences::setSelectorLineWidth( + (float)CStudioPreferences::DEFAULT_SELECTOR_WIDTH / 10.0f); + CStudioPreferences::setSelectorLineLength( + (float)CStudioPreferences::DEFAULT_SELECTOR_LENGTH); + + RecheckSizingMode(); + + // Save preferences, to make sure we do not lose them on a possible crash + QTimer::singleShot(0, [](){ CStudioPreferences::savePreferences(); }); + } else if (thePrefsReturn == PREFS_RESET_LAYOUT) { + onViewResetLayout(); + } else if (thePrefsReturn == PREFS_SETTINGS_RESTART) { + QTimer::singleShot(0, this, &CMainFrame::handleRestart); + } else if (thePrefsReturn != 0) { + // Save preferences, to make sure we do not lose them on a possible crash + QTimer::singleShot(0, [](){ CStudioPreferences::savePreferences(); }); + } +} + +/** + * 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()); + + // Don't wait for regular update cycle to update the corresponding toolbar/menu checked status + m_ui->actionAutoset_Keyframes->setChecked(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 + Q_EMIT playStateChanged(true); + + if (m_playbackFlag == false) { + m_playbackFlag = true; + 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 + Q_EMIT playStateChanged(false); + + if (m_playbackFlag == true) { + m_playbackFlag = false; + m_playbackTimer->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) +{ +} + +/** + * 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(const QString &viewerExeName, bool remote) +{ + if (remote && m_remoteDeploymentSender->isConnected()) { + g_StudioApp.GetCore()->GetDispatch()->FireOnProgressBegin( + QObject::tr("Deploying to remote device..."), {}); + CPreviewHelper::OnDeploy(*m_remoteDeploymentSender); + g_StudioApp.GetCore()->GetDispatch()->FireOnProgressEnd(); + } else { + CPreviewHelper::OnPreview(viewerExeName); + } +} + +void CMainFrame::OnPlaybackPreviewQt3DRuntime() +{ + OnPlaybackPreview(QStringLiteral("q3dsviewer")); +} + +void CMainFrame::OnPlaybackPreviewOpenGLRuntime() +{ + OnPlaybackPreview(QStringLiteral("Qt3DViewer")); +} + +void CMainFrame::onFilterVariants() +{ + if (m_ui->actionFilterVariants->isChecked()) { + QRect actionGeom = m_ui->m_PlaybackToolbar->actionGeometry(m_ui->actionFilterVariants); + m_filterVariantsDlg->activateWindow(); + m_filterVariantsDlg->raise(); + m_filterVariantsDlg->move(m_ui->m_PlaybackToolbar->pos() + + QPoint(actionGeom.x(), actionGeom.bottom())); + m_filterVariantsDlg->setFocus(); + m_filterVariantsDlg->show(); + } else { + m_filterVariantsDlg->close(); + } +} + +QString CMainFrame::getVariantsFilterStr() const +{ + if (m_filterVariantsDlg) + return m_filterVariantsDlg->filterStr(); + + return {}; +} + +void CMainFrame::updateActionFilterEnableState() +{ + bool enable = false; + const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef(); + const auto keys = variantsDef.keys(); + for (auto &group : keys) { + if (!variantsDef[group].m_tags.isEmpty()) { + enable = true; + break; + } + } + + m_ui->actionFilterVariants->setEnabled(enable); +} + +void CMainFrame::updateToolbarVariantsIcons(bool isFiltered) +{ + if (isFiltered) { + m_ui->actionPreview->setIcon(QIcon(QStringLiteral(":/images/preview-variants.png"))); + m_ui->actionFilterVariants->setIcon(QIcon(QStringLiteral(":/images/filter-colored.png"))); + } else { + m_ui->actionPreview->setIcon(QIcon(QStringLiteral(":/images/preview.png"))); + m_ui->actionFilterVariants->setIcon(QIcon(QStringLiteral(":/images/filter.png"))); + } +} + +void CMainFrame::OnPlaybackPreviewRemote() +{ + OnPlaybackPreview(QStringLiteral("q3dsviewer"), true); +} + +//============================================================================== +/** + * 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(); +} + +//============================================================================== +/** + * 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, QWidget *actionParent) +{ + // Default undo shortcut is Ctrl-Y, which is specified in main form. Let's add the common + // alternate shortcut for redo, CTRL-SHIFT-Z + ADD_GLOBAL_SHORTCUT(actionParent, + QKeySequence(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_Z), + CMainFrame::OnEditRedo); + + ADD_GLOBAL_SHORTCUT(actionParent, + QKeySequence(Qt::Key_Q), + CMainFrame::toggleSelectMode); + + for (int keyN = Qt::Key_1; keyN <= Qt::Key_9; keyN++) { + ADD_GLOBAL_SHORTCUT(actionParent, + QKeySequence(Qt::CTRL | static_cast<Qt::Key>(keyN)), + CMainFrame::onCtrlNPressed); + } +} + +//============================================================================== +/** + * 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.GetManipulationMode(); + + // 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()); +} + +//============================================================================== +/** + * Move, Rotate, or Scale button clicked. Sets the current tool mode and changes the cursor. + * + * @param toolMode the selected tool (move, rotate, or scale) + */ +void CMainFrame::onTransformToolChanged(long toolMode) +{ + g_StudioApp.SetToolMode(toolMode); + m_sceneView->setToolMode(toolMode); + + m_ui->actionPosition_Tool->setChecked(toolMode == STUDIO_TOOLMODE_MOVE); + m_ui->actionRotation_Tool->setChecked(toolMode == STUDIO_TOOLMODE_ROTATE); + m_ui->actionScale_Tool->setChecked(toolMode == STUDIO_TOOLMODE_SCALE); +} + +void CMainFrame::OnToolGlobalManipulators() +{ + if (m_ui->actionLocal_Global_Manipulators->isChecked()) + g_StudioApp.SetManipulationMode(StudioManipulationModes::Global); + else + g_StudioApp.SetManipulationMode(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->setViewCursor(); // Just set cursor, we don't want to update previous tool +} + +//============================================================================== +/** + * 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->setViewCursor(); // Just set cursor, we don't want to update previous tool +} + +//============================================================================== +/** + * 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->setViewCursor(); // Just set cursor, we don't want to update previous tool +} + +//============================================================================== +/** + * 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.data() == 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.data() == 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 0 // TODO: Disabled until UX decision is made if these buttons are needed at all or not + 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); + } +#endif +} + +//============================================================================== +/** + * 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.data() == 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.data() == GetActiveView() && !m_sceneView->isDeploymentView()) { + OnEditViewFillMode(); + bool theEditViewFillMode = g_StudioApp.getRenderer().IsPolygonFillModeEnabled(); + 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().IsPolygonFillModeEnabled(); + g_StudioApp.getRenderer().SetPolygonFillModeEnabled(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.data() == GetActiveView() && !m_sceneView->isDeploymentView()) { + m_ui->actionShading_Mode->setEnabled(true); + m_ui->actionShading_Mode->setChecked(g_StudioApp.getRenderer().IsPolygonFillModeEnabled()); + } 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::OnUpdateCameraPreview() +{ + m_ui->actionCamera_Preview->setChecked(CStudioPreferences::showEditModePreview()); + g_StudioApp.getRenderer().RequestRender(); +} + +void CMainFrame::OnUpdateEditViewLightingEnabled() +{ + m_ui->actionEdit_Lighting->setChecked(CStudioPreferences::editModeLightingEnabled()); + g_StudioApp.getRenderer().RequestRender(); +} + +void CMainFrame::timerEvent(QTimerEvent *event) +{ + if (event->timerId() == WM_STUDIO_TIMER) + g_StudioApp.getTickTock().ProcessMessages(); + QMainWindow::timerEvent(event); +} + +void CMainFrame::onViewResetLayout() +{ + // Ask for a restart + int theChoice = QMessageBox::question(this, + tr("Restart Needed"), + tr("Are you sure that you want to restore Qt 3D Studio " + "layout? \nYour current layout will be lost, and " + "Studio will restart.")); + + // If "Yes" is clicked, delete window geometry and window state keys from QSettings + if (theChoice == QMessageBox::Yes) { + QSettings settings; + QString geoKey = QStringLiteral("mainWindowGeometry") + QString::number(STUDIO_VERSION_NUM); + QString stateKey = QStringLiteral("mainWindowState") + QString::number(STUDIO_VERSION_NUM); + settings.remove(geoKey); + settings.remove(stateKey); + // Prevent saving geometry and state, and exit + m_resettingLayout = true; + QTimer::singleShot(0, this, &CMainFrame::handleRestart); + } +} + +void CMainFrame::OnViewAction() +{ + m_paletteManager->ToggleControl(CPaletteManager::CONTROLTYPE_ACTION); +} + +void CMainFrame::OnUpdateViewAction() +{ + m_ui->actionAction->setChecked( + m_paletteManager->IsControlVisible(CPaletteManager::CONTROLTYPE_ACTION)); +} + +void CMainFrame::OnViewBasicObjects() +{ + m_paletteManager->ToggleControl(CPaletteManager::CONTROLTYPE_BASICOBJECTS); +} + +void CMainFrame::OnUpdateViewBasicObjects() +{ + m_ui->actionBasic_Objects->setChecked(m_paletteManager->IsControlVisible( + CPaletteManager::CONTROLTYPE_BASICOBJECTS)); +} + +void CMainFrame::OnViewInspector() +{ + m_paletteManager->ToggleControl(CPaletteManager::CONTROLTYPE_INSPECTOR); +} + +void CMainFrame::OnUpdateViewInspector() +{ + m_ui->actionInspector->setChecked( + m_paletteManager->IsControlVisible(CPaletteManager::CONTROLTYPE_INSPECTOR)); +} + +void CMainFrame::OnViewProject() +{ + m_paletteManager->ToggleControl(CPaletteManager::CONTROLTYPE_PROJECT); +} + +void CMainFrame::OnUpdateViewProject() +{ + m_ui->actionProject->setChecked( + m_paletteManager->IsControlVisible(CPaletteManager::CONTROLTYPE_PROJECT)); +} + +void CMainFrame::OnViewSlide() +{ + m_paletteManager->ToggleControl(CPaletteManager::CONTROLTYPE_SLIDE); +} + +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); +} + +//============================================================================== +/** + * 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)); +} + +void CMainFrame::onViewSceneCamera() +{ + m_paletteManager->ToggleControl(CPaletteManager::CONTROLTYPE_SCENECAMERA); + onUpdateViewSceneCamera(); +} + +void CMainFrame::onUpdateViewSceneCamera() +{ + const bool cameraVisible = m_paletteManager->IsControlVisible( + CPaletteManager::CONTROLTYPE_SCENECAMERA); + m_ui->actionSceneCamera->setChecked(cameraVisible); + g_StudioApp.getRenderer().setFullSizePreview(cameraVisible); + g_StudioApp.getRenderer().RequestRender(); +} + +//============================================================================== +/** + * 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()); + + // Don't wait for regular update cycle to update the corresponding toolbar/menu checked status + m_ui->actionWireframe->setChecked(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() +{ + QFile theFile(g_StudioApp.m_helpFilePath); + m_ui->action_Reference_Manual->setEnabled(theFile.exists()); +} + +//============================================================================== +/** + * Handles the ID_HELP_INDEX command. Opens the online help for Studio. + */ +void CMainFrame::OnHelpIndex() +{ + QFile theFile(g_StudioApp.m_helpFilePath); + if (theFile.exists()) + QDesktopServices::openUrl(QUrl::fromLocalFile(theFile.fileName())); +} + +//============================================================================== +/** + * Handles the ID_HELP_VISIT_QT command. Opens the Qt Web site. + */ +void CMainFrame::OnHelpVisitQt() +{ + QDesktopServices::openUrl(QUrl(QStringLiteral("https://www.qt.io/3d-studio"))); +} + +//============================================================================== +/** + * Opens the tutorial. + */ +void CMainFrame::OnHelpOpenTutorial() +{ + StudioTutorialWidget tutorial(this); + int welcomeRes = tutorial.exec(); + g_StudioApp.handleWelcomeRes(welcomeRes, false); +} + +//============================================================================== +/** + * Handle the file revert menu option. + */ +void CMainFrame::OnFileRevert() +{ + g_StudioApp.OnRevert(); +} + +void CMainFrame::OnFileImportAssets() +{ + m_paletteManager->projectView()->assetImportAction(0); +} + +void CMainFrame::OnFileConnectToDevice() +{ + if (m_remoteDeploymentSender->isConnected()) { + g_StudioApp.GetCore()->GetDispatch()->FireOnProgressBegin( + QObject::tr("Disconnecting from remote device..."), {}); + m_remoteDeploymentSender->disconnect(); + } else { + QPair<QString, int> info = m_remoteDeploymentSender->initConnection(); + if (!info.first.isEmpty()) { + g_StudioApp.GetCore()->GetDispatch()->FireOnProgressBegin( + QObject::tr("Connecting to remote device..."), {}); + m_remoteDeploymentSender->connect(info); + } else { + m_ui->action_Connect_to_Device->setChecked(false); + } + } +} + +//============================================================================== +/** + * 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 QString &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 QString &inFilename, bool inSucceeded, bool inSaveCopy) +{ + if (!inSaveCopy) + OnOpenDocument(inFilename, inSucceeded); +} + +//============================================================================== +/** + * Callback for when a the doc gets a new path + */ +void CMainFrame::OnDocumentPathChanged(const QString &inNewPath) +{ + QFileInfo info(inNewPath); + QString theTitle = info.fileName(); + if (theTitle.isEmpty()) + theTitle = QObject::tr("Untitled"); + + theTitle.append(QStringLiteral(" - ") + QObject::tr("Qt 3D Studio")); + + // TODO: Move this whole pile to the studio app + setWindowTitle(theTitle); + + if (info.exists()) + m_recentItems->AddRecentItem(inNewPath); +} + +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); +} + +void CMainFrame::OnShowEditPreview() +{ + bool show = CStudioPreferences::showEditModePreview(); + CStudioPreferences::setShowEditModePreview(!show); +} + +void CMainFrame::OnEditViewLightingEnabled() +{ + bool enabled = CStudioPreferences::editModeLightingEnabled(); + CStudioPreferences::setEditModeLightingEnabled(!enabled); +} + +void CMainFrame::OnConnectionChanged(bool connected) +{ + g_StudioApp.GetCore()->GetDispatch()->FireOnProgressEnd(); + m_ui->action_Connect_to_Device->setChecked(connected); + m_ui->actionRemote_Preview->setEnabled(connected); +} + +TimelineWidget *CMainFrame::getTimelineWidget() const +{ + WidgetControl *control = static_cast<WidgetControl *> + (m_paletteManager->GetControl(CPaletteManager::CONTROLTYPE_TIMELINE)->widget()); + return static_cast<TimelineWidget *>(control->getControl()); +} + +SlideView *CMainFrame::getSlideView() const +{ + return static_cast<SlideView *>(m_paletteManager->GetControl(CPaletteManager::CONTROLTYPE_SLIDE) + ->widget()); +} + +InspectorControlView *CMainFrame::getInspectorView() const +{ + return static_cast<InspectorControlView *>(m_paletteManager + ->GetControl(CPaletteManager::CONTROLTYPE_INSPECTOR) + ->widget()); +} + +CRecentItems *CMainFrame::GetRecentItems() const +{ + return m_recentItems.data(); +} + +QWidget *CMainFrame::GetActiveView() const +{ + return centralWidget(); +} + +CPlayerWnd *CMainFrame::GetPlayerWnd() const +{ + return m_sceneView->getPlayerWnd(); +} + +bool CMainFrame::eventFilter(QObject *obj, QEvent *event) +{ + switch (event->type()) { + case QEvent::ToolTip: { + if (CStudioPreferences::ShouldShowTooltips()) + event->ignore(); + else + return true; + break; + } + case QEvent::KeyPress: { + QKeyEvent *ke = static_cast<QKeyEvent *>(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); +} + +void CMainFrame::handleGeometryAndState(bool save) +{ + if (m_resettingLayout) + return; + + QSettings settings; + QString geoKey = QStringLiteral("mainWindowGeometry") + QString::number(STUDIO_VERSION_NUM); + QString stateKey = QStringLiteral("mainWindowState") + QString::number(STUDIO_VERSION_NUM); + if (save) { + settings.setValue(geoKey, saveGeometry()); + settings.setValue(stateKey, saveState(STUDIO_VERSION_NUM)); + } else { + // Restoring geometry and state back to back results in errors in state restoration, so + // let's restore state asynchronously + restoreGeometry(settings.value(geoKey).toByteArray()); + QTimer::singleShot(0, this, [this, stateKey]() { + QSettings settings; + restoreState(settings.value(stateKey).toByteArray(), STUDIO_VERSION_NUM); + }); + } +} + +void CMainFrame::handleRestart() +{ + QStringList presentationFile = QStringList(g_StudioApp.GetCore()->GetDoc()->GetDocumentPath()); + close(); + QProcess::startDetached(qApp->arguments()[0], presentationFile); +} + +void CMainFrame::initializeGeometryAndState() +{ + QSettings settings; + QString stateKey = QStringLiteral("mainWindowState") + QString::number(STUDIO_VERSION_NUM); + if (!settings.contains(stateKey)) { + // On first run, save and restore geometry and state. For some reason they are both needed + // to avoid a bug with palettes resizing to their original size when window is resized or + // something in a palette is edited. + handleGeometryAndState(true); + } + handleGeometryAndState(false); +} + +void CMainFrame::toggleSelectMode() +{ + if (m_ui->actionItem_Select_Tool->isChecked()) + m_sceneView->onToolGroupSelection(); + else + m_sceneView->onToolItemSelection(); +} + +void CMainFrame::showScene() +{ + if (!m_sceneView.data()->isVisible()) { + setCentralWidget(m_sceneView.data()); + m_sceneView.data()->setVisible(true); + } +} |