ProjectButtonWidget.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <ProjectButtonWidget.h>
  9. #include <ProjectManagerDefs.h>
  10. #include <ProjectUtils.h>
  11. #include <ProjectManager_Traits_Platform.h>
  12. #include <ProjectExportController.h>
  13. #include <AzQtComponents/Utilities/DesktopUtilities.h>
  14. #include <AzQtComponents/Components/Widgets/ElidingLabel.h>
  15. #include <AzCore/IO/SystemFile.h>
  16. #include <AzCore/IO/Path/Path.h>
  17. #include <AzCore/PlatformId/PlatformId.h>
  18. #include <QVBoxLayout>
  19. #include <QHBoxLayout>
  20. #include <QEvent>
  21. #include <QResizeEvent>
  22. #include <QLabel>
  23. #include <QPushButton>
  24. #include <QPixmap>
  25. #include <QMenu>
  26. #include <QSpacerItem>
  27. #include <QProgressBar>
  28. #include <QDebug>
  29. #include <QDir>
  30. #include <QFileInfo>
  31. #include <QDesktopServices>
  32. #include <QMessageBox>
  33. #include <QMouseEvent>
  34. #include <QMovie>
  35. namespace O3DE::ProjectManager
  36. {
  37. LabelButton::LabelButton(QWidget* parent)
  38. : QLabel(parent)
  39. {
  40. // Space for content excluding borders
  41. constexpr int contentSpaceWidth = ProjectPreviewImageWidth - 2;
  42. // The height of a third of the button split into 3 sections, top, middle and bottom
  43. constexpr int threeWaySplitHeight = (ProjectPreviewImageHeight - 2) / 3;
  44. setObjectName("labelButton");
  45. // Use GridLayout so widgets can be overlapped
  46. QGridLayout* overlayLayout = new QGridLayout();
  47. overlayLayout->setContentsMargins(0, 0, 0, 0);
  48. overlayLayout->setSpacing(0);
  49. setLayout(overlayLayout);
  50. m_darkenOverlay = new QLabel(this);
  51. m_darkenOverlay->setObjectName("labelButtonOverlay");
  52. m_darkenOverlay->setVisible(true);
  53. overlayLayout->addWidget(m_darkenOverlay, 0, 0);
  54. m_projectOverlayLayout = new QVBoxLayout();
  55. m_projectOverlayLayout->setContentsMargins(0, 0, 0, 0);
  56. m_projectOverlayLayout->setSpacing(0);
  57. m_projectOverlayLayout->setAlignment(Qt::AlignCenter);
  58. // Split the button into 3 fixed size sections so content alignment is easier to manage
  59. // If widgets in other sections are shown or hidden it will not offset alignment in other sections
  60. QWidget* topWidget = new QWidget();
  61. topWidget->setFixedSize(contentSpaceWidth, threeWaySplitHeight);
  62. QVBoxLayout* verticalMessageLayout = new QVBoxLayout();
  63. verticalMessageLayout->setContentsMargins(0, 0, 0, 0);
  64. verticalMessageLayout->setSpacing(4);
  65. verticalMessageLayout->setAlignment(Qt::AlignCenter);
  66. topWidget->setLayout(verticalMessageLayout);
  67. verticalMessageLayout->addSpacing(10);
  68. QHBoxLayout* horizontalWarningMessageLayout = new QHBoxLayout();
  69. horizontalWarningMessageLayout->setContentsMargins(0, 0, 0, 0);
  70. horizontalWarningMessageLayout->setSpacing(0);
  71. horizontalWarningMessageLayout->setAlignment(Qt::AlignRight | Qt::AlignTop);
  72. m_warningSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed);
  73. horizontalWarningMessageLayout->addSpacerItem(m_warningSpacer);
  74. horizontalWarningMessageLayout->addSpacing(10);
  75. m_warningIcon = new QLabel(this);
  76. m_warningIcon->setObjectName("projectWarningIconOverlay");
  77. m_warningIcon->setPixmap(QIcon(":/Warning.svg").pixmap(32, 32));
  78. m_warningIcon->setAlignment(Qt::AlignCenter);
  79. m_warningIcon->setVisible(false);
  80. horizontalWarningMessageLayout->addWidget(m_warningIcon);
  81. m_cloudIcon = new QLabel(this);
  82. m_cloudIcon->setObjectName("projectCloudIconOverlay");
  83. m_cloudIcon->setPixmap(QIcon(":/Download.svg").pixmap(32, 32));
  84. m_cloudIcon->setVisible(false);
  85. horizontalWarningMessageLayout->addWidget(m_cloudIcon);
  86. horizontalWarningMessageLayout->addSpacing(15);
  87. verticalMessageLayout->addLayout(horizontalWarningMessageLayout);
  88. m_messageLabel = new QLabel("", this);
  89. m_messageLabel->setObjectName("projectMessageOverlay");
  90. m_messageLabel->setAlignment(Qt::AlignCenter);
  91. m_messageLabel->setVisible(true);
  92. verticalMessageLayout->addWidget(m_messageLabel);
  93. m_subMessageLabel = new QLabel("", this);
  94. m_subMessageLabel->setObjectName("projectSubMessageOverlay");
  95. m_subMessageLabel->setAlignment(Qt::AlignCenter);
  96. m_subMessageLabel->setVisible(true);
  97. verticalMessageLayout->addWidget(m_subMessageLabel);
  98. verticalMessageLayout->addStretch();
  99. m_projectOverlayLayout->addWidget(topWidget);
  100. QWidget* middleWidget = new QWidget();
  101. middleWidget->setFixedSize(contentSpaceWidth, threeWaySplitHeight);
  102. QVBoxLayout* verticalCenterLayout = new QVBoxLayout();
  103. verticalCenterLayout->setContentsMargins(0, 0, 0, 0);
  104. verticalCenterLayout->setSpacing(0);
  105. verticalCenterLayout->setAlignment(Qt::AlignCenter);
  106. middleWidget->setLayout(verticalCenterLayout);
  107. m_buildingAnimation = new QLabel("", this);
  108. m_buildingAnimation->setObjectName("buildingAnimationOverlay");
  109. m_buildingAnimation->setAlignment(Qt::AlignCenter);
  110. m_buildingAnimation->setVisible(false);
  111. m_buildingAnimation->setMovie(new QMovie(":/SpinningGears.webp"));
  112. m_buildingAnimation->movie()->start();
  113. verticalCenterLayout->addWidget(m_buildingAnimation);
  114. // Download Progress
  115. QWidget* m_downloadProgress = new QWidget(this);
  116. m_progessBar = new QProgressBar(this);
  117. m_progessBar->setVisible(false);
  118. QVBoxLayout* downloadProgressLayout = new QVBoxLayout();
  119. QHBoxLayout* downloadProgressTextLayout = new QHBoxLayout();
  120. m_downloadMessageLabel = new QLabel(tr("Downloading Project"), this);
  121. m_downloadMessageLabel->setAlignment(Qt::AlignCenter);
  122. m_downloadMessageLabel->setVisible(false);
  123. verticalCenterLayout->addWidget(m_downloadMessageLabel);
  124. downloadProgressTextLayout->addSpacing(25);
  125. m_progressMessageLabel = new QLabel(tr("0%"), this);
  126. m_progressMessageLabel->setAlignment(Qt::AlignRight);
  127. m_progressMessageLabel->setVisible(false);
  128. downloadProgressTextLayout->addWidget(m_progressMessageLabel);
  129. downloadProgressTextLayout->addSpacing(25);
  130. verticalCenterLayout->addLayout(downloadProgressTextLayout);
  131. QHBoxLayout* progressbarLayout = new QHBoxLayout();
  132. downloadProgressLayout->addLayout(progressbarLayout);
  133. m_downloadProgress->setLayout(downloadProgressLayout);
  134. progressbarLayout->addSpacing(20);
  135. progressbarLayout->addWidget(m_progessBar);
  136. progressbarLayout->addSpacing(20);
  137. verticalCenterLayout->addWidget(m_downloadProgress);
  138. m_projectOverlayLayout->addWidget(middleWidget);
  139. QWidget* bottomWidget = new QWidget();
  140. bottomWidget->setFixedSize(contentSpaceWidth, threeWaySplitHeight);
  141. QVBoxLayout* verticalButtonLayout = new QVBoxLayout();
  142. verticalButtonLayout->setContentsMargins(0, 0, 0, 0);
  143. verticalButtonLayout->setSpacing(5);
  144. verticalButtonLayout->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
  145. bottomWidget->setLayout(verticalButtonLayout);
  146. m_openEditorButton = new QPushButton(tr("Open Editor"), this);
  147. m_openEditorButton->setObjectName("openEditorButton");
  148. m_openEditorButton->setDefault(true);
  149. m_openEditorButton->setVisible(false);
  150. verticalButtonLayout->addWidget(m_openEditorButton);
  151. m_actionButton = new QPushButton(tr("Project Action"), this);
  152. m_actionButton->setObjectName("projectActionButton");
  153. m_actionButton->setVisible(false);
  154. verticalButtonLayout->addWidget(m_actionButton);
  155. // This button has seperate styling with a red button instead of a blue button as for m_actionButton
  156. // Seperate buttons are used to avoid stutter from reloading style after changing object name
  157. m_actionCancelButton = new QPushButton(tr("Cancel Project Action"), this);
  158. m_actionCancelButton->setObjectName("projectActionCancelButton");
  159. m_actionCancelButton->setProperty("danger", true);
  160. m_actionCancelButton->setVisible(false);
  161. verticalButtonLayout->addWidget(m_actionCancelButton);
  162. m_showLogsButton = new QPushButton(tr("Show logs"), this);
  163. m_showLogsButton->setObjectName("projectShowLogsButton");
  164. m_showLogsButton->setVisible(false);
  165. verticalButtonLayout->addWidget(m_showLogsButton);
  166. verticalButtonLayout->addSpacing(20);
  167. m_projectOverlayLayout->addWidget(bottomWidget);
  168. overlayLayout->addLayout(m_projectOverlayLayout, 0, 0);
  169. }
  170. void LabelButton::mousePressEvent(QMouseEvent* event)
  171. {
  172. emit triggered(event);
  173. }
  174. QLabel* LabelButton::GetMessageLabel()
  175. {
  176. return m_messageLabel;
  177. }
  178. QLabel* LabelButton::GetSubMessageLabel()
  179. {
  180. return m_subMessageLabel;
  181. }
  182. QLabel* LabelButton::GetWarningIcon()
  183. {
  184. return m_warningIcon;
  185. }
  186. QLabel* LabelButton::GetCloudIcon()
  187. {
  188. return m_cloudIcon;
  189. }
  190. QSpacerItem* LabelButton::GetWarningSpacer()
  191. {
  192. return m_warningSpacer;
  193. }
  194. QLabel* LabelButton::GetBuildingAnimationLabel()
  195. {
  196. return m_buildingAnimation;
  197. }
  198. QPushButton* LabelButton::GetOpenEditorButton()
  199. {
  200. return m_openEditorButton;
  201. }
  202. QPushButton* LabelButton::GetActionButton()
  203. {
  204. return m_actionButton;
  205. }
  206. QPushButton* LabelButton::GetActionCancelButton()
  207. {
  208. return m_actionCancelButton;
  209. }
  210. QPushButton* LabelButton::GetShowLogsButton()
  211. {
  212. return m_showLogsButton;
  213. }
  214. QLabel* LabelButton::GetDarkenOverlay()
  215. {
  216. return m_darkenOverlay;
  217. }
  218. QProgressBar* LabelButton::GetProgressBar()
  219. {
  220. return m_progessBar;
  221. }
  222. QLabel* LabelButton::GetProgressPercentage()
  223. {
  224. return m_progressMessageLabel;
  225. }
  226. QLabel* LabelButton::GetDownloadMessageLabel()
  227. {
  228. return m_downloadMessageLabel;
  229. }
  230. ProjectButton::ProjectButton(const ProjectInfo& projectInfo, const EngineInfo& engineInfo, QWidget* parent)
  231. : QFrame(parent)
  232. , m_engineInfo(engineInfo)
  233. , m_projectInfo(projectInfo)
  234. , m_isProjectBuilding(false)
  235. {
  236. setObjectName("projectButton");
  237. QVBoxLayout* vLayout = new QVBoxLayout();
  238. vLayout->setSpacing(0);
  239. vLayout->setContentsMargins(0, 0, 0, 0);
  240. setLayout(vLayout);
  241. m_projectImageLabel = new LabelButton(this);
  242. m_projectImageLabel->setFixedSize(ProjectPreviewImageWidth, ProjectPreviewImageHeight);
  243. m_projectImageLabel->setAlignment(Qt::AlignCenter);
  244. vLayout->addWidget(m_projectImageLabel);
  245. QString projectPreviewPath = QDir(m_projectInfo.m_path).filePath(m_projectInfo.m_iconPath);
  246. QFileInfo doesPreviewExist(projectPreviewPath);
  247. if (!doesPreviewExist.exists() || !doesPreviewExist.isFile())
  248. {
  249. projectPreviewPath = ":/DefaultProjectImage.png";
  250. }
  251. m_projectImageLabel->setPixmap(QPixmap(projectPreviewPath).scaled(m_projectImageLabel->size(), Qt::KeepAspectRatioByExpanding));
  252. QFrame* projectFooter = new QFrame(this);
  253. QVBoxLayout* projectFooterLayout = new QVBoxLayout();
  254. projectFooterLayout->setContentsMargins(0, 0, 0, 0);
  255. projectFooter->setLayout(projectFooterLayout);
  256. {
  257. // row 1
  258. QHBoxLayout* hLayout = new QHBoxLayout();
  259. hLayout->setContentsMargins(0, 0, 0, 0);
  260. QString projectName = m_projectInfo.GetProjectDisplayName();
  261. if (!m_projectInfo.m_version.isEmpty())
  262. {
  263. projectName +=" " + m_projectInfo.m_version;
  264. }
  265. m_projectNameLabel = new AzQtComponents::ElidingLabel(projectName, this);
  266. m_projectNameLabel->setObjectName("projectNameLabel");
  267. m_projectNameLabel->setToolTip(m_projectInfo.m_path);
  268. m_projectNameLabel->refreshStyle();
  269. hLayout->addWidget(m_projectNameLabel);
  270. m_projectMenuButton = new QPushButton(this);
  271. m_projectMenuButton->setObjectName("projectMenuButton");
  272. m_projectMenuButton->setMenu(CreateProjectMenu());
  273. hLayout->addWidget(m_projectMenuButton);
  274. projectFooterLayout->addLayout(hLayout);
  275. // row 2
  276. m_engineNameLabel = new AzQtComponents::ElidingLabel(m_engineInfo.m_name + " " + m_engineInfo.m_version, this);
  277. SetEngine(m_engineInfo);
  278. projectFooterLayout->addWidget(m_engineNameLabel);
  279. }
  280. vLayout->addWidget(projectFooter);
  281. connect(m_projectImageLabel->GetOpenEditorButton(), &QPushButton::clicked, [this]() {
  282. emit OpenProject(m_projectInfo.m_path);
  283. });
  284. connect(m_projectImageLabel, &LabelButton::triggered, [this](QMouseEvent* event) {
  285. if (!m_isProjectBuilding && event->button() == Qt::RightButton)
  286. {
  287. m_projectMenuButton->menu()->move(event->globalPos());
  288. m_projectMenuButton->menu()->show();
  289. }
  290. });
  291. connect(m_projectImageLabel->GetShowLogsButton(), &QPushButton::pressed, this, &ProjectButton::ShowLogs);
  292. SetState(ProjectButtonState::ReadyToLaunch);
  293. }
  294. ProjectButton::~ProjectButton() = default;
  295. QMenu* ProjectButton::CreateProjectMenu()
  296. {
  297. QMenu* menu = new QMenu(this);
  298. menu->addAction(tr("Edit Project Settings..."), this, [this]() { emit EditProject(m_projectInfo.m_path); });
  299. menu->addAction(tr("Configure Gems..."), this, [this]() { emit EditProjectGems(m_projectInfo.m_path); });
  300. menu->addAction(tr("Build"), this, [this]() { emit BuildProject(m_projectInfo); });
  301. menu->addSeparator();
  302. QMenu* exportMenu = menu->addMenu(tr("Export Launcher"));
  303. exportMenu->addAction(AZ_TRAIT_PROJECT_MANAGER_HOST_PLATFORM_NAME , this, [this](){ emit ExportProject(m_projectInfo, "export_source_built_project.py");});
  304. exportMenu->addAction(tr("Android"), this, [this](){ emit ExportProject(m_projectInfo, "export_source_android.py"); });
  305. menu->addAction(tr("Open Export Settings..."), this, [this]() { emit OpenProjectExportSettings(m_projectInfo.m_path); });
  306. menu->addSeparator();
  307. menu->addAction(tr("Open CMake GUI..."), this, [this]() { emit OpenCMakeGUI(m_projectInfo); });
  308. menu->addAction(tr("Open Android Project Generator..."), this, [this]() { emit OpenAndroidProjectGenerator(m_projectInfo.m_path); });
  309. menu->addSeparator();
  310. menu->addAction(tr("Open Project folder..."), this, [this]()
  311. {
  312. AzQtComponents::ShowFileOnDesktop(m_projectInfo.m_path);
  313. });
  314. #if AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT
  315. menu->addAction(tr("Create Editor desktop shortcut..."), this, [this]()
  316. {
  317. AZ::IO::FixedMaxPath editorExecutablePath = ProjectUtils::GetEditorExecutablePath(m_projectInfo.m_path.toUtf8().constData());
  318. const QString shortcutName = QString("%1 Editor").arg(m_projectInfo.m_displayName);
  319. const QString arg = QString("--regset=\"/Amazon/AzCore/Bootstrap/project_path=%1\"").arg(m_projectInfo.m_path);
  320. auto result = ProjectUtils::CreateDesktopShortcut(shortcutName, editorExecutablePath.c_str(), { arg });
  321. if(result.IsSuccess())
  322. {
  323. QMessageBox::information(this, tr("Desktop Shortcut Created"), result.GetValue());
  324. }
  325. else
  326. {
  327. QMessageBox::critical(this, tr("Failed to create shortcut"), result.GetError());
  328. }
  329. });
  330. #endif // AZ_TRAIT_PROJECT_MANAGER_CREATE_DESKTOP_SHORTCUT
  331. menu->addSeparator();
  332. menu->addAction(tr("Duplicate"), this, [this]() { emit CopyProject(m_projectInfo); });
  333. menu->addSeparator();
  334. menu->addAction(tr("Remove from O3DE"), this, [this]() { emit RemoveProject(m_projectInfo.m_path); });
  335. menu->addAction(tr("Delete this Project"), this, [this]() { emit DeleteProject(m_projectInfo.m_path); });
  336. return menu;
  337. }
  338. const ProjectInfo& ProjectButton::GetProjectInfo() const
  339. {
  340. return m_projectInfo;
  341. }
  342. void ProjectButton::ShowLogs()
  343. {
  344. if (!QDesktopServices::openUrl(m_projectInfo.m_logUrl))
  345. {
  346. qDebug() << "QDesktopServices::openUrl failed to open " << m_projectInfo.m_logUrl.toString() << "\n";
  347. }
  348. }
  349. void ProjectButton::SetEngine(const EngineInfo& engine)
  350. {
  351. m_engineInfo = engine;
  352. if (m_engineInfo.m_name.isEmpty() && !m_projectInfo.m_engineName.isEmpty())
  353. {
  354. // this project wants to use an engine that wasn't found, display the qualifier
  355. m_engineInfo.m_name = m_projectInfo.m_engineName;
  356. m_engineInfo.m_version = "";
  357. }
  358. m_engineNameLabel->SetText(m_engineInfo.m_name + " " + m_engineInfo.m_version);
  359. m_engineNameLabel->update();
  360. m_engineNameLabel->setObjectName(m_engineInfo.m_thisEngine ? "thisEngineLabel" : "otherEngineLabel");
  361. m_engineNameLabel->setToolTip(m_engineInfo.m_name + " " + m_engineInfo.m_version + " " + m_engineInfo.m_path);
  362. m_engineNameLabel->refreshStyle(); // important for styles to work correctly
  363. }
  364. void ProjectButton::SetProject(const ProjectInfo& project)
  365. {
  366. m_projectInfo = project;
  367. if (!m_projectInfo.m_version.isEmpty())
  368. {
  369. m_projectNameLabel->SetText(m_projectInfo.GetProjectDisplayName() + " " + m_projectInfo.m_version);
  370. }
  371. else
  372. {
  373. m_projectNameLabel->SetText(m_projectInfo.GetProjectDisplayName());
  374. }
  375. m_projectNameLabel->update();
  376. m_projectNameLabel->setToolTip(m_projectInfo.m_path);
  377. m_projectNameLabel->refreshStyle(); // important for styles to work correctly
  378. }
  379. void ProjectButton::SetState(ProjectButtonState state)
  380. {
  381. m_currentState = state;
  382. ResetButtonWidgets();
  383. switch (state)
  384. {
  385. default:
  386. case ProjectButtonState::ReadyToLaunch:
  387. ShowReadyState();
  388. break;
  389. case ProjectButtonState::Launching:
  390. ShowLaunchingState();
  391. break;
  392. case ProjectButtonState::NeedsToBuild:
  393. ShowBuildRequiredState();
  394. break;
  395. case ProjectButtonState::Building:
  396. ShowBuildingState();
  397. break;
  398. case ProjectButtonState::BuildFailed:
  399. ShowBuildFailedState();
  400. break;
  401. case ProjectButtonState::Exporting:
  402. ShowExportingState();
  403. break;
  404. case ProjectButtonState::ExportFailed:
  405. ShowExportFailedState();
  406. break;
  407. case ProjectButtonState::NotDownloaded:
  408. ShowNotDownloadedState();
  409. break;
  410. case ProjectButtonState::DownloadingBuildQueued:
  411. case ProjectButtonState::Downloading:
  412. ShowDownloadingState();
  413. break;
  414. }
  415. }
  416. void ProjectButton::ShowReadyState()
  417. {
  418. HideContextualLabelButtonWidgets();
  419. if (m_actionButtonConnection)
  420. {
  421. disconnect(m_actionButtonConnection);
  422. }
  423. m_projectMenuButton->setVisible(true);
  424. SetLaunchingEnabled(true);
  425. SetProjectBuilding(false);
  426. }
  427. void ProjectButton::ShowLaunchingState()
  428. {
  429. // Hide button in-case it is still showing
  430. m_projectImageLabel->GetOpenEditorButton()->hide();
  431. SetLaunchingEnabled(false);
  432. ShowMessage(tr("Opening Editor..."));
  433. }
  434. void ProjectButton::ShowBuildRequiredState()
  435. {
  436. ShowBuildButton();
  437. SetProjectBuilding(false);
  438. ShowWarning(tr("Project build required."));
  439. }
  440. void ProjectButton::ShowBuildingState()
  441. {
  442. m_projectImageLabel->GetShowLogsButton()->show();
  443. // Setting project to building also disables launching
  444. SetProjectBuilding(true);
  445. ShowMessage(tr("Building Project..."));
  446. }
  447. void ProjectButton::ShowExportingState()
  448. {
  449. m_projectImageLabel->GetShowLogsButton()->show();
  450. SetProjectExporting(true);
  451. ShowMessage(tr("Exporting Project..."));
  452. }
  453. void ProjectButton::ShowBuildFailedState()
  454. {
  455. ShowBuildButton();
  456. SetProjectBuilding(false);
  457. // Show, show logs button if avaliable
  458. m_projectImageLabel->GetShowLogsButton()->setVisible(!m_projectInfo.m_logUrl.isEmpty());
  459. ShowWarning(tr("Failed to build"));
  460. }
  461. void ProjectButton::ShowExportFailedState()
  462. {
  463. ShowBuildButton();
  464. SetProjectExporting(false);
  465. m_projectImageLabel->GetShowLogsButton()->setVisible(!m_projectInfo.m_logUrl.isEmpty());
  466. ShowWarning(tr(ProjectExportController::LauncherExportFailedMessage));
  467. }
  468. void ProjectButton::ShowNotDownloadedState()
  469. {
  470. m_projectImageLabel->GetCloudIcon()->setVisible(true);
  471. m_projectImageLabel->GetWarningSpacer()->changeSize(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed);
  472. m_projectMenuButton->setVisible(false);
  473. SetLaunchingEnabled(false);
  474. }
  475. void ProjectButton::ShowDownloadingState()
  476. {
  477. m_projectImageLabel->GetCloudIcon()->setVisible(true);
  478. m_projectImageLabel->GetWarningSpacer()->changeSize(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed);
  479. m_projectMenuButton->setVisible(false);
  480. m_projectImageLabel->GetDownloadMessageLabel()->setVisible(true);
  481. m_projectImageLabel->GetProgressPercentage()->setVisible(true);
  482. m_projectImageLabel->GetProgressBar()->setVisible(true);
  483. SetLaunchingEnabled(false);
  484. }
  485. void ProjectButton::SetProjectButtonAction(const QString& text, AZStd::function<void()> lambda)
  486. {
  487. QPushButton* projectActionButton;
  488. QPushButton* projectOtherActionButton;
  489. if (text.contains("Cancel", Qt::CaseInsensitive))
  490. {
  491. // Use red button is action involves cancelling
  492. projectActionButton = m_projectImageLabel->GetActionCancelButton();
  493. projectOtherActionButton = m_projectImageLabel->GetActionButton();
  494. }
  495. else
  496. {
  497. projectActionButton = m_projectImageLabel->GetActionButton();
  498. projectOtherActionButton = m_projectImageLabel->GetActionCancelButton();
  499. }
  500. if (m_actionButtonConnection)
  501. {
  502. disconnect(m_actionButtonConnection);
  503. }
  504. projectActionButton->setVisible(true);
  505. projectOtherActionButton->setVisible(false);
  506. projectActionButton->setText(text);
  507. projectActionButton->setMenu(nullptr);
  508. m_actionButtonConnection = connect(projectActionButton, &QPushButton::clicked, lambda);
  509. }
  510. void ProjectButton::SetBuildLogsLink(const QUrl& logUrl)
  511. {
  512. m_projectInfo.m_logUrl = logUrl;
  513. }
  514. void ProjectButton::SetProgressBarPercentage(const float percent)
  515. {
  516. m_projectImageLabel->GetProgressBar()->setValue(static_cast<int>(percent*100));
  517. m_projectImageLabel->GetProgressPercentage()->setText(QString("%1%").arg(static_cast<int>(percent*100)));
  518. }
  519. void ProjectButton::SetContextualText(const QString& text)
  520. {
  521. if (m_currentState == ProjectButtonState::Building || m_currentState == ProjectButtonState::Exporting)
  522. {
  523. // Don't update for empty build progress messages
  524. if (!text.isEmpty())
  525. {
  526. // Show info about what's currently building
  527. ShowMessage({}, text);
  528. }
  529. }
  530. else
  531. {
  532. ShowMessage(text);
  533. }
  534. }
  535. void ProjectButton::ShowBuildButton()
  536. {
  537. QPushButton* projectActionButton = m_projectImageLabel->GetActionButton();
  538. projectActionButton->setVisible(true);
  539. projectActionButton->setText(tr("Build Project"));
  540. disconnect(m_actionButtonConnection);
  541. QMenu* menu = new QMenu(this);
  542. QAction* autoBuildAction = menu->addAction(tr("Build Now"));
  543. connect( autoBuildAction, &QAction::triggered, this, [this](){ emit BuildProject(m_projectInfo); });
  544. QAction* openCMakeAction = menu->addAction(tr("Open CMake GUI..."));
  545. connect( openCMakeAction, &QAction::triggered, this, [this](){ emit OpenCMakeGUI(m_projectInfo); });
  546. projectActionButton->setMenu(menu);
  547. }
  548. void ProjectButton::ResetButtonWidgets()
  549. {
  550. HideContextualLabelButtonWidgets();
  551. SetProjectBuilding(false);
  552. SetProgressBarPercentage(0);
  553. m_projectImageLabel->GetDownloadMessageLabel()->setVisible(false);
  554. m_projectImageLabel->GetProgressPercentage()->setVisible(false);
  555. m_projectImageLabel->GetProgressBar()->setVisible(false);
  556. }
  557. // Only setting message without setting submessage will hide submessage
  558. void ProjectButton::ShowMessage(const QString& message, const QString& submessage)
  559. {
  560. bool showMessage = !message.isEmpty();
  561. bool showSubmessage = !submessage.isEmpty();
  562. QLabel* messageLabel = m_projectImageLabel->GetMessageLabel();
  563. QLabel* submessageLabel = m_projectImageLabel->GetSubMessageLabel();
  564. if (showMessage || showSubmessage)
  565. {
  566. // Hide any warning text, we cannot show the warning and a message at the same time
  567. ShowWarning();
  568. }
  569. // Keep main message if only submessage is set
  570. if (showMessage || showMessage == showSubmessage)
  571. {
  572. messageLabel->setText(message);
  573. }
  574. submessageLabel->setText(submessage);
  575. // Darken background if there is a message to make it easier to read
  576. m_projectImageLabel->GetDarkenOverlay()->setVisible(showMessage || showSubmessage);
  577. messageLabel->setVisible(showMessage || showSubmessage);
  578. submessageLabel->setVisible(showSubmessage);
  579. }
  580. void ProjectButton::ShowWarning(const QString& warning)
  581. {
  582. bool show = !warning.isEmpty();
  583. QLabel* warningIcon = m_projectImageLabel->GetWarningIcon();
  584. if (show)
  585. {
  586. // Hide any message text, we cannot show the warning and a message at the same time
  587. ShowMessage();
  588. m_projectImageLabel->GetWarningSpacer()->changeSize(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed);
  589. }
  590. else
  591. {
  592. m_projectImageLabel->GetWarningSpacer()->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed);
  593. }
  594. warningIcon->setToolTip(warning);
  595. warningIcon->setVisible(show);
  596. }
  597. void ProjectButton::SetLaunchingEnabled(bool enabled)
  598. {
  599. m_canLaunch = enabled;
  600. }
  601. void ProjectButton::SetProjectBuilding(bool isBuilding)
  602. {
  603. m_isProjectBuilding = isBuilding;
  604. QLabel* buildingAnimation = m_projectImageLabel->GetBuildingAnimationLabel();
  605. if (isBuilding)
  606. {
  607. SetLaunchingEnabled(false);
  608. m_projectImageLabel->GetActionCancelButton()->show();
  609. }
  610. buildingAnimation->movie()->setPaused(!isBuilding);
  611. buildingAnimation->setVisible(isBuilding);
  612. m_projectMenuButton->setVisible(!isBuilding);
  613. }
  614. void ProjectButton::SetProjectExporting(bool isExporting)
  615. {
  616. m_isProjectExporting = isExporting;
  617. if (isExporting)
  618. {
  619. SetLaunchingEnabled(false);
  620. m_projectImageLabel->GetActionCancelButton()->show();
  621. }
  622. if (QLabel* exportingAnimation = m_projectImageLabel->GetBuildingAnimationLabel())
  623. {
  624. exportingAnimation->movie()->setPaused(!isExporting);
  625. exportingAnimation->setVisible(isExporting);
  626. }
  627. m_projectMenuButton->setVisible(!isExporting);
  628. }
  629. void ProjectButton::HideContextualLabelButtonWidgets()
  630. {
  631. ShowMessage();
  632. ShowWarning();
  633. m_projectImageLabel->GetActionButton()->hide();
  634. m_projectImageLabel->GetActionCancelButton()->hide();
  635. m_projectImageLabel->GetShowLogsButton()->hide();
  636. }
  637. void ProjectButton::enterEvent(QEvent* /*event*/)
  638. {
  639. if (m_canLaunch)
  640. {
  641. m_projectImageLabel->GetOpenEditorButton()->setVisible(true);
  642. }
  643. }
  644. void ProjectButton::leaveEvent(QEvent* /*event*/)
  645. {
  646. m_projectImageLabel->GetOpenEditorButton()->setVisible(false);
  647. }
  648. LabelButton* ProjectButton::GetLabelButton()
  649. {
  650. return m_projectImageLabel;
  651. }
  652. } // namespace O3DE::ProjectManager