diff --git a/.github/ISSUE_TEMPLATE/rfc-feature.md b/.github/ISSUE_TEMPLATE/rfc-feature.md deleted file mode 100644 index 31a195f803..0000000000 --- a/.github/ISSUE_TEMPLATE/rfc-feature.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -name: RFC Feature request -about: Create Feature RFC for this project -title: Proposed RFC Feature =description= -labels: 'rfc-feature' -assignees: '' - ---- - -# O3DE RFC Feature Template - -### When using this template, you do not have to fill out every question below. The questions are there for guidance. - -This RFC feature template should be used for any feature that is not a bug or a substantial reorganization of the O3DE product. - -If you submit a pull request to implement a new feature without going through the RFC process, it may be closed with a polite request to submit an RFC first. - -A hastily proposed RFC can hurt its chances of acceptance. Low-quality proposals, proposals for previously-rejected features, or those that don't fit into the near-term roadmap may be quickly rejected, demotivating the unprepared contributor. Laying some groundwork ahead of the RFC can make the process smoother. - -Although there is no single way to prepare for submitting an RFC, it is generally a good idea to pursue feedback from other project developers beforehand to ascertain that the RFC may be desirable; having a consistent impact on the project requires concerted effort toward consensus-building. - -The most common preparations for writing and submitting an RFC include: -- Talking the idea over on our Discord server. -- Discussing the topic on our GitHub RFCs discussions page. -- Occasionally posting "pre-RFCs" on the GitHub RFCs discussion page. -You may file issues in the RFCs repo for discussion, but these are not actively looked at by the teams. - -As a rule of thumb, receiving encouraging feedback from long-standing project developers, and particularly members of the relevant sub-team, is a good indication that the RFC is worth pursuing. - -# ----- DELETE EVERYTHING FROM THE TOP TO THE SUMMARY LINE BELOW WHEN USING TEMPLATE ----- # - -### Summary: -Single paragraph explanation of the feature - -### What is the relevance of this feature? -Why is this important? What are the use cases? What will it do once completed? - -### Feature design description: -- Explain the design of the feature with enough detail that someone familiar with the environment and framework can understand the concept and explain it to others. -- It should include at least one end-to-end example of how a developer will use it along with specific details, including outlying use cases. - -- If there is any new terminology, it should be defined here. - -### Technical design description: -- Explain the technical portion of the work in enough detail that members can implement the feature. - -- Explain any API or process changes required to implement this feature - -- This section should relate to the feature design description by reference and explain in greater detail how it makes the feature design examples work. - -- This should also provide detailed information on compatibility with different hardware platforms. - - -### What are the advantages of the feature? -- Explain the advantages for someone to use this feature - -### What are the disadvantages of the feature? -- Explain any disadvantages for someone to use this feature - -### How will this be implemented or integrated into the O3DE environment? -- Explain how a developer will integrate this into the codebase of O3DE and provide any specific library or technical stack requirements. - -### Are there any alternatives to this feature? -- Provide any other designs that have been considered. Explain what the impact might be of not doing this. -- If there is any prior art or approaches with other frameworks in the same domain, explain how they may have solved this problem or implemented this feature. - -### How will users learn this feature? -- Detail how it can be best presented and how it is used as an extension or a standalone tool used with O3DE. -- Explain if and how it may change how individuals would use the platform and if any documentation must be changed or reorganized. -- Explain how it would be taught to new and existing O3DE users. - -### Are there any open questions? -- What are some of the open questions and potential scenarios that should be considered? diff --git a/.github/ISSUE_TEMPLATE/rfc-suggestion.md b/.github/ISSUE_TEMPLATE/rfc-suggestion.md deleted file mode 100644 index 7c51bbc918..0000000000 --- a/.github/ISSUE_TEMPLATE/rfc-suggestion.md +++ /dev/null @@ -1,61 +0,0 @@ ---- -name: RFC Suggestion request -about: Create Suggestion RFC for this project -title: Proposed RFC Suggestion =description= -labels: 'rfc-suggestion' -assignees: '' - ---- - -# O3DE Suggestion RFC Template - -### When using this template, you do not have to fill out every question below. The questions are there for guidance. - -This RFC template should be used for any suggestion that is not based upon code or content related to the O3DE product itself. This template is for proposing new process models, approaches, or ideas to improve the O3DE community. - -A hastily proposed RFC can hurt its chances of acceptance. Low-quality proposals, proposals for previously rejected features, or those that do not have any substantive value to the project may be quickly rejected, demotivating the unprepared contributor. Laying some groundwork with others in the community ahead of the RFC can make the process much smoother. - -Although there is no single way to prepare for submitting an RFC, it is generally a good idea to pursue feedback from other project members beforehand. Keep in mind that you want other members to contribute and back your suggestion, which can drastically improve the chances of implementation. - -The most common preparations for writing and submitting an RFC include: -- Talking the idea over on our Discord server. -- Creating a discussion on our GitHub RFCs discussions page. -- Occasionally posting "pre-RFCs" on the GitHub RFCs discussion page. -You may file issues in the RFCs repo for discussion, but these are not actively looked at by the teams. - -As a rule of thumb, receiving encouraging feedback from long-standing community members is a good indication that the RFC is worth pursuing. - -# ----- DELETE EVERYTHING FROM THE TOP TO THE SUMMARY LINE BELOW WHEN USING TEMPLATE ----- # - -### Summary: -Single paragraph explanation of the suggestion - -### What is the motivation for this suggestion? -Why is this important? -What are the use cases for this suggestion? -What should the outcome be if this suggestion is implemented? - -### Suggestion design description: -- Explain the suggestion with enough detail that someone familiar with the process and environment of the project can understand the suggestion and explain it to others. -- It should include at least one end-to-end example of how the community will use it along with the specific details with outlying use cases. - -- If there is any new terminology, it should be defined here. - -### What are the advantages of the suggestion? -- Explain the advantages of using this suggestion - -### What are the disadvantages of the suggestion? -- Explain any disadvantages or trade-offs to using this suggestion - -### How will this be work within the O3DE project? -- Explain how this suggestion will be work within the O3DE project. - -### Are there any alternatives to this suggestion? -- Provide any other alternative ways that have been considered. -- Explain what the impact might be of not implementing this suggestion. -- If there are other similar suggestions previously used, list them and explain which parts may have solved some or all of this problem. - -### What is the strategy for adoption? -- Explain how new and existing users will adopt this suggestion. -- Point out any efforts needed if it requires coordination with multiple SIGs or other projects. -- Explain how it would be taught to new and existing O3DE users. diff --git a/AutomatedTesting/Gem/Code/enabled_gems.cmake b/AutomatedTesting/Gem/Code/enabled_gems.cmake index b712fec7ab..dd68e379dd 100644 --- a/AutomatedTesting/Gem/Code/enabled_gems.cmake +++ b/AutomatedTesting/Gem/Code/enabled_gems.cmake @@ -47,8 +47,7 @@ set(ENABLED_GEMS LmbrCentral LyShine HttpRequestor - Atom_AtomBridge - PythonCoverage + Atom AWSCore AWSClientAuth AWSMetrics diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/atom_renderer/CMakeLists.txt index ec150bd186..b851260639 100644 --- a/AutomatedTesting/Gem/PythonTests/atom_renderer/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/CMakeLists.txt @@ -38,7 +38,7 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS AND PAL_TRAIT_BUILD_TESTS_SUPPORTED AND AutomatedT TEST_SUITE main TEST_REQUIRES gpu TEST_SERIAL - TIMEOUT 400 + TIMEOUT 800 PATH ${CMAKE_CURRENT_LIST_DIR}/test_Atom_GPUTests.py RUNTIME_DEPENDENCIES AssetProcessor diff --git a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py index cb5ae709d1..05eff871c1 100644 --- a/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py +++ b/AutomatedTesting/Gem/PythonTests/atom_renderer/test_Atom_GPUTests.py @@ -17,7 +17,7 @@ import editor_python_test_tools.hydra_test_utils as hydra logger = logging.getLogger(__name__) DEFAULT_SUBFOLDER_PATH = 'user/PythonTests/Automated/Screenshots' -EDITOR_TIMEOUT = 300 +EDITOR_TIMEOUT = 600 TEST_DIRECTORY = os.path.join(os.path.dirname(__file__), "atom_hydra_scripts") @@ -77,7 +77,6 @@ class TestAllComponentsIndepthTests(object): unexpected_lines=unexpected_lines, halt_on_unexpected=True, cfg_args=[level], - auto_test_mode=False, null_renderer=False, ) diff --git a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_EditMenuOptions.py b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_EditMenuOptions.py index 26110cd954..c157c995c4 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_EditMenuOptions.py +++ b/AutomatedTesting/Gem/PythonTests/editor/EditorScripts/Menus_EditMenuOptions.py @@ -60,24 +60,7 @@ class TestEditMenuOptions(EditorTestHelper): ("Modify", "Transform Mode", "Rotate"), ("Modify", "Transform Mode", "Scale"), ("Editor Settings", "Global Preferences"), - ("Editor Settings", "Graphics Settings"), ("Editor Settings", "Editor Settings Manager"), - ("Editor Settings", "Graphics Performance", "PC", "Very High"), - ("Editor Settings", "Graphics Performance", "PC", "High"), - ("Editor Settings", "Graphics Performance", "PC", "Medium"), - ("Editor Settings", "Graphics Performance", "PC", "Low"), - ("Editor Settings", "Graphics Performance", "OSX Metal", "Very High"), - ("Editor Settings", "Graphics Performance", "OSX Metal", "High"), - ("Editor Settings", "Graphics Performance", "OSX Metal", "Medium"), - ("Editor Settings", "Graphics Performance", "OSX Metal", "Low"), - ("Editor Settings", "Graphics Performance", "Android", "Very High"), - ("Editor Settings", "Graphics Performance", "Android", "High"), - ("Editor Settings", "Graphics Performance", "Android", "Medium"), - ("Editor Settings", "Graphics Performance", "Android", "Low"), - ("Editor Settings", "Graphics Performance", "iOS", "Very High"), - ("Editor Settings", "Graphics Performance", "iOS", "High"), - ("Editor Settings", "Graphics Performance", "iOS", "Medium"), - ("Editor Settings", "Graphics Performance", "iOS", "Low"), ("Editor Settings", "Keyboard Customization", "Customize Keyboard"), ("Editor Settings", "Keyboard Customization", "Export Keyboard Settings"), ("Editor Settings", "Keyboard Customization", "Import Keyboard Settings"), diff --git a/AutomatedTesting/Gem/PythonTests/editor/test_Menus.py b/AutomatedTesting/Gem/PythonTests/editor/test_Menus.py index 982f3617b5..cc5385f4ba 100644 --- a/AutomatedTesting/Gem/PythonTests/editor/test_Menus.py +++ b/AutomatedTesting/Gem/PythonTests/editor/test_Menus.py @@ -55,12 +55,7 @@ class TestMenus(object): "Rotate Action triggered", "Scale Action triggered", "Global Preferences Action triggered", - "Graphics Settings Action triggered", "Editor Settings Manager Action triggered", - "Very High Action triggered", - "High Action triggered", - "Medium Action triggered", - "Low Action triggered", "Customize Keyboard Action triggered", "Export Keyboard Settings Action triggered", "Import Keyboard Settings Action triggered", diff --git a/AutomatedTesting/Gem/PythonTests/smoke/CMakeLists.txt b/AutomatedTesting/Gem/PythonTests/smoke/CMakeLists.txt index af9fc142e2..73af69b93a 100644 --- a/AutomatedTesting/Gem/PythonTests/smoke/CMakeLists.txt +++ b/AutomatedTesting/Gem/PythonTests/smoke/CMakeLists.txt @@ -51,4 +51,18 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED AND PAL_TRAIT_BUILD_HOST_TOOLS) AutomatedTesting.GameLauncher AutomatedTesting.Assets ) + + ly_add_pytest( + NAME AutomatedTesting::GameLauncherWithGPU + TEST_SUITE sandbox + TEST_REQUIRES gpu + PATH ${CMAKE_CURRENT_LIST_DIR}/test_GameLauncher_EnterExitGameMode_Works.py + TIMEOUT 100 + RUNTIME_DEPENDENCIES + AZ::AssetProcessor + AZ::PythonBindingsExample + Legacy::Editor + AutomatedTesting.GameLauncher + AutomatedTesting.Assets + ) endif() diff --git a/Code/Editor/CMakeLists.txt b/Code/Editor/CMakeLists.txt index 8a5f35fb92..13985cfb5e 100644 --- a/Code/Editor/CMakeLists.txt +++ b/Code/Editor/CMakeLists.txt @@ -111,7 +111,6 @@ ly_add_target( AZ::AzCore AZ::AzToolsFramework Gem::LmbrCentral.Static - Legacy::NewsShared AZ::AWSNativeSDKInit AZ::AtomCore Gem::Atom_RPI.Edit @@ -139,7 +138,6 @@ ly_add_source_properties( ly_add_source_properties( SOURCES Core/LevelEditorMenuHandler.cpp - GraphicsSettingsDialog.cpp MainWindow.cpp PROPERTY COMPILE_DEFINITIONS VALUES ${LY_PAL_TOOLS_DEFINES} diff --git a/Code/Editor/Core/LevelEditorMenuHandler.cpp b/Code/Editor/Core/LevelEditorMenuHandler.cpp index ab1229dc6b..14b33097a7 100644 --- a/Code/Editor/Core/LevelEditorMenuHandler.cpp +++ b/Code/Editor/Core/LevelEditorMenuHandler.cpp @@ -552,49 +552,9 @@ void LevelEditorMenuHandler::PopulateEditMenu(ActionManager::MenuWrapper& editMe // Global Preferences... editorSettingsMenu.AddAction(ID_TOOLS_PREFERENCES); - // Graphics Settings... - editorSettingsMenu.AddAction(ID_GRAPHICS_SETTINGS); - // Editor Settings Manager AddOpenViewPaneAction(editorSettingsMenu, LyViewPane::EditorSettingsManager); - // Graphics Performance - auto graphicPerformanceSubMenu = editorSettingsMenu.AddMenu(QObject::tr("Graphics Performance")); - - auto pcMenu = graphicPerformanceSubMenu.AddMenu(tr("PC")); - pcMenu.AddAction(ID_GAME_PC_ENABLEVERYHIGHSPEC); - pcMenu.AddAction(ID_GAME_PC_ENABLEHIGHSPEC); - pcMenu.AddAction(ID_GAME_PC_ENABLEMEDIUMSPEC); - pcMenu.AddAction(ID_GAME_PC_ENABLELOWSPEC); - - auto osxmetalMenu = graphicPerformanceSubMenu.AddMenu(tr("OSX Metal")); - osxmetalMenu.AddAction(ID_GAME_OSXMETAL_ENABLEVERYHIGHSPEC); - osxmetalMenu.AddAction(ID_GAME_OSXMETAL_ENABLEHIGHSPEC); - osxmetalMenu.AddAction(ID_GAME_OSXMETAL_ENABLEMEDIUMSPEC); - osxmetalMenu.AddAction(ID_GAME_OSXMETAL_ENABLELOWSPEC); - - auto androidMenu = graphicPerformanceSubMenu.AddMenu(tr("Android")); - androidMenu.AddAction(ID_GAME_ANDROID_ENABLEVERYHIGHSPEC); - androidMenu.AddAction(ID_GAME_ANDROID_ENABLEHIGHSPEC); - androidMenu.AddAction(ID_GAME_ANDROID_ENABLEMEDIUMSPEC); - androidMenu.AddAction(ID_GAME_ANDROID_ENABLELOWSPEC); - - auto iosMenu = graphicPerformanceSubMenu.AddMenu(tr("iOS")); - iosMenu.AddAction(ID_GAME_IOS_ENABLEVERYHIGHSPEC); - iosMenu.AddAction(ID_GAME_IOS_ENABLEHIGHSPEC); - iosMenu.AddAction(ID_GAME_IOS_ENABLEMEDIUMSPEC); - iosMenu.AddAction(ID_GAME_IOS_ENABLELOWSPEC); - -#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) -#define AZ_RESTRICTED_PLATFORM_EXPANSION(CodeName, CODENAME, codename, PrivateName, PRIVATENAME, privatename, PublicName, PUBLICNAME, publicname, PublicAuxName1, PublicAuxName2, PublicAuxName3)\ - auto publicname##Menu = graphicPerformanceSubMenu.AddMenu(tr(PublicAuxName2));\ - publicname##Menu.AddAction(ID_GAME_##CODENAME##_ENABLEHIGHSPEC);\ - publicname##Menu.AddAction(ID_GAME_##CODENAME##_ENABLEMEDIUMSPEC);\ - publicname##Menu.AddAction(ID_GAME_##CODENAME##_ENABLELOWSPEC); - AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS -#undef AZ_RESTRICTED_PLATFORM_EXPANSION -#endif - // Keyboard Customization auto keyboardCustomizationMenu = editorSettingsMenu.AddMenu(tr("Keyboard Customization")); keyboardCustomizationMenu.AddAction(ID_TOOLS_CUSTOMIZEKEYBOARD); diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp index 8efd4bc5b3..b0dddc94ae 100644 --- a/Code/Editor/CryEdit.cpp +++ b/Code/Editor/CryEdit.cpp @@ -111,7 +111,6 @@ AZ_POP_DISABLE_WARNING #include "ToolBox.h" #include "LevelInfo.h" #include "EditorPreferencesDialog.h" -#include "GraphicsSettingsDialog.h" #include "AnimationContext.h" #include "GotoPositionDlg.h" @@ -440,7 +439,6 @@ void CCryEditApp::RegisterActionHandlers() ON_COMMAND(ID_CLEAR_REGISTRY, OnClearRegistryData) ON_COMMAND(ID_VALIDATELEVEL, OnValidatelevel) ON_COMMAND(ID_TOOLS_PREFERENCES, OnToolsPreferences) - ON_COMMAND(ID_GRAPHICS_SETTINGS, OnGraphicsSettings) ON_COMMAND(ID_SWITCHCAMERA_DEFAULTCAMERA, OnSwitchToDefaultCamera) ON_COMMAND(ID_SWITCHCAMERA_SEQUENCECAMERA, OnSwitchToSequenceCamera) ON_COMMAND(ID_SWITCHCAMERA_SELECTEDCAMERA, OnSwitchToSelectedcamera) @@ -453,14 +451,6 @@ void CCryEditApp::RegisterActionHandlers() ON_COMMAND(ID_OPEN_TRACKVIEW, OnOpenTrackView) ON_COMMAND(ID_OPEN_UICANVASEDITOR, OnOpenUICanvasEditor) - ON_COMMAND_RANGE(ID_GAME_PC_ENABLELOWSPEC, ID_GAME_PC_ENABLEVERYHIGHSPEC, OnChangeGameSpec) - - ON_COMMAND_RANGE(ID_GAME_OSXMETAL_ENABLELOWSPEC, ID_GAME_OSXMETAL_ENABLEVERYHIGHSPEC, OnChangeGameSpec) - - ON_COMMAND_RANGE(ID_GAME_ANDROID_ENABLELOWSPEC, ID_GAME_ANDROID_ENABLEVERYHIGHSPEC, OnChangeGameSpec) - - ON_COMMAND_RANGE(ID_GAME_IOS_ENABLELOWSPEC, ID_GAME_IOS_ENABLEVERYHIGHSPEC, OnChangeGameSpec) - #if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) #define AZ_RESTRICTED_PLATFORM_EXPANSION(CodeName, CODENAME, codename, PrivateName, PRIVATENAME, privatename, PublicName, PUBLICNAME, publicname, PublicAuxName1, PublicAuxName2, PublicAuxName3)\ ON_COMMAND_RANGE(ID_GAME_##CODENAME##_ENABLELOWSPEC, ID_GAME_##CODENAME##_ENABLEHIGHSPEC, OnChangeGameSpec) @@ -3674,13 +3664,6 @@ void CCryEditApp::OnToolsPreferences() dlg.exec(); } -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::OnGraphicsSettings() -{ - GraphicsSettingsDialog dlg(MainWindow::instance()); - dlg.exec(); -} - ////////////////////////////////////////////////////////////////////////// void CCryEditApp::OnSwitchToDefaultCamera() { @@ -3815,91 +3798,6 @@ void CCryEditApp::OnOpenUICanvasEditor() QtViewPaneManager::instance()->OpenPane(LyViewPane::UiEditor); } -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::SetGameSpecCheck(ESystemConfigSpec spec, ESystemConfigPlatform platform, int &nCheck, bool &enable) -{ - if (GetIEditor()->GetEditorConfigSpec() == spec && GetIEditor()->GetEditorConfigPlatform() == platform) - { - nCheck = 1; - } - enable = spec <= GetIEditor()->GetSystem()->GetMaxConfigSpec(); -} - -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::OnUpdateGameSpec(QAction* action) -{ - Q_ASSERT(action->isCheckable()); - int nCheck = 0; - bool enable = true; - switch (action->data().toInt()) - { - case ID_GAME_PC_ENABLELOWSPEC: - SetGameSpecCheck(CONFIG_LOW_SPEC, CONFIG_PC, nCheck, enable); - break; - case ID_GAME_PC_ENABLEMEDIUMSPEC: - SetGameSpecCheck(CONFIG_MEDIUM_SPEC, CONFIG_PC, nCheck, enable); - break; - case ID_GAME_PC_ENABLEHIGHSPEC: - SetGameSpecCheck(CONFIG_HIGH_SPEC, CONFIG_PC, nCheck, enable); - break; - case ID_GAME_PC_ENABLEVERYHIGHSPEC: - SetGameSpecCheck(CONFIG_VERYHIGH_SPEC, CONFIG_PC, nCheck, enable); - break; - case ID_GAME_OSXMETAL_ENABLELOWSPEC: - SetGameSpecCheck(CONFIG_LOW_SPEC, CONFIG_OSX_METAL, nCheck, enable); - break; - case ID_GAME_OSXMETAL_ENABLEMEDIUMSPEC: - SetGameSpecCheck(CONFIG_MEDIUM_SPEC, CONFIG_OSX_METAL, nCheck, enable); - break; - case ID_GAME_OSXMETAL_ENABLEHIGHSPEC: - SetGameSpecCheck(CONFIG_HIGH_SPEC, CONFIG_OSX_METAL, nCheck, enable); - break; - case ID_GAME_OSXMETAL_ENABLEVERYHIGHSPEC: - SetGameSpecCheck(CONFIG_VERYHIGH_SPEC, CONFIG_OSX_METAL, nCheck, enable); - break; - case ID_GAME_ANDROID_ENABLELOWSPEC: - SetGameSpecCheck(CONFIG_LOW_SPEC, CONFIG_ANDROID, nCheck, enable); - break; - case ID_GAME_ANDROID_ENABLEMEDIUMSPEC: - SetGameSpecCheck(CONFIG_MEDIUM_SPEC, CONFIG_ANDROID, nCheck, enable); - break; - case ID_GAME_ANDROID_ENABLEHIGHSPEC: - SetGameSpecCheck(CONFIG_HIGH_SPEC, CONFIG_ANDROID, nCheck, enable); - break; - case ID_GAME_ANDROID_ENABLEVERYHIGHSPEC: - SetGameSpecCheck(CONFIG_VERYHIGH_SPEC, CONFIG_ANDROID, nCheck, enable); - break; - case ID_GAME_IOS_ENABLELOWSPEC: - SetGameSpecCheck(CONFIG_LOW_SPEC, CONFIG_IOS, nCheck, enable); - break; - case ID_GAME_IOS_ENABLEMEDIUMSPEC: - SetGameSpecCheck(CONFIG_MEDIUM_SPEC, CONFIG_IOS, nCheck, enable); - break; - case ID_GAME_IOS_ENABLEHIGHSPEC: - SetGameSpecCheck(CONFIG_HIGH_SPEC, CONFIG_IOS, nCheck, enable); - break; - case ID_GAME_IOS_ENABLEVERYHIGHSPEC: - SetGameSpecCheck(CONFIG_VERYHIGH_SPEC, CONFIG_IOS, nCheck, enable); - break; -#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) -#define AZ_RESTRICTED_PLATFORM_EXPANSION(CodeName, CODENAME, codename, PrivateName, PRIVATENAME, privatename, PublicName, PUBLICNAME, publicname, PublicAuxName1, PublicAuxName2, PublicAuxName3)\ - case ID_GAME_##CODENAME##_ENABLELOWSPEC:\ - SetGameSpecCheck(CONFIG_LOW_SPEC, CONFIG_##CODENAME, nCheck, enable);\ - break;\ - case ID_GAME_##CODENAME##_ENABLEMEDIUMSPEC:\ - SetGameSpecCheck(CONFIG_MEDIUM_SPEC, CONFIG_##CODENAME, nCheck, enable);\ - break;\ - case ID_GAME_##CODENAME##_ENABLEHIGHSPEC:\ - SetGameSpecCheck(CONFIG_HIGH_SPEC, CONFIG_##CODENAME, nCheck, enable);\ - break; - AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS -#undef AZ_RESTRICTED_PLATFORM_EXPANSION -#endif - } - action->setChecked(nCheck); - action->setEnabled(enable); -} - ////////////////////////////////////////////////////////////////////////// RecentFileList* CCryEditApp::GetRecentFileList() { diff --git a/Code/Editor/CryEdit.h b/Code/Editor/CryEdit.h index 0628289897..5de8aa5e6c 100644 --- a/Code/Editor/CryEdit.h +++ b/Code/Editor/CryEdit.h @@ -403,7 +403,6 @@ private: void OnClearRegistryData(); void OnValidatelevel(); void OnToolsPreferences(); - void OnGraphicsSettings(); void OnSwitchToDefaultCamera(); void OnUpdateSwitchToDefaultCamera(QAction* action); void OnSwitchToSequenceCamera(); @@ -416,9 +415,6 @@ private: void OnOpenTrackView(); void OnOpenAudioControlsEditor(); void OnOpenUICanvasEditor(); - void OnChangeGameSpec(UINT nID); - void SetGameSpecCheck(ESystemConfigSpec spec, ESystemConfigPlatform platform, int &nCheck, bool &enable); - void OnUpdateGameSpec(QAction* action); void OnOpenQuickAccessBar(); public: diff --git a/Code/Editor/CryEditPy.cpp b/Code/Editor/CryEditPy.cpp index 02833a84e0..2e414da277 100644 --- a/Code/Editor/CryEditPy.cpp +++ b/Code/Editor/CryEditPy.cpp @@ -407,78 +407,6 @@ inline namespace Commands } } -////////////////////////////////////////////////////////////////////////// -void CCryEditApp::OnChangeGameSpec(UINT nID) -{ - switch (nID) - { - case ID_GAME_PC_ENABLELOWSPEC: - Commands::PySetConfigSpec(CONFIG_LOW_SPEC, CONFIG_PC); - break; - case ID_GAME_PC_ENABLEMEDIUMSPEC: - Commands::PySetConfigSpec(CONFIG_MEDIUM_SPEC, CONFIG_PC); - break; - case ID_GAME_PC_ENABLEHIGHSPEC: - Commands::PySetConfigSpec(CONFIG_HIGH_SPEC, CONFIG_PC); - break; - case ID_GAME_PC_ENABLEVERYHIGHSPEC: - Commands::PySetConfigSpec(CONFIG_VERYHIGH_SPEC, CONFIG_PC); - break; - case ID_GAME_OSXMETAL_ENABLELOWSPEC: - Commands::PySetConfigSpec(CONFIG_LOW_SPEC, CONFIG_OSX_METAL); - break; - case ID_GAME_OSXMETAL_ENABLEMEDIUMSPEC: - Commands::PySetConfigSpec(CONFIG_MEDIUM_SPEC, CONFIG_OSX_METAL); - break; - case ID_GAME_OSXMETAL_ENABLEHIGHSPEC: - Commands::PySetConfigSpec(CONFIG_HIGH_SPEC, CONFIG_OSX_METAL); - break; - case ID_GAME_OSXMETAL_ENABLEVERYHIGHSPEC: - Commands::PySetConfigSpec(CONFIG_VERYHIGH_SPEC, CONFIG_OSX_METAL); - break; - case ID_GAME_ANDROID_ENABLELOWSPEC: - Commands::PySetConfigSpec(CONFIG_LOW_SPEC, CONFIG_ANDROID); - break; - case ID_GAME_ANDROID_ENABLEMEDIUMSPEC: - Commands::PySetConfigSpec(CONFIG_MEDIUM_SPEC, CONFIG_ANDROID); - break; - case ID_GAME_ANDROID_ENABLEHIGHSPEC: - Commands::PySetConfigSpec(CONFIG_HIGH_SPEC, CONFIG_ANDROID); - break; - case ID_GAME_ANDROID_ENABLEVERYHIGHSPEC: - Commands::PySetConfigSpec(CONFIG_VERYHIGH_SPEC, CONFIG_ANDROID); - break; - case ID_GAME_IOS_ENABLELOWSPEC: - Commands::PySetConfigSpec(CONFIG_LOW_SPEC, CONFIG_IOS); - break; - case ID_GAME_IOS_ENABLEMEDIUMSPEC: - Commands::PySetConfigSpec(CONFIG_MEDIUM_SPEC, CONFIG_IOS); - break; - case ID_GAME_IOS_ENABLEHIGHSPEC: - Commands::PySetConfigSpec(CONFIG_HIGH_SPEC, CONFIG_IOS); - break; - case ID_GAME_IOS_ENABLEVERYHIGHSPEC: - Commands::PySetConfigSpec(CONFIG_VERYHIGH_SPEC, CONFIG_IOS); - break; -#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) -#define AZ_RESTRICTED_PLATFORM_EXPANSION(CodeName, CODENAME, codename, PrivateName, PRIVATENAME, privatename, PublicName, PUBLICNAME, publicname, PublicAuxName1, PublicAuxName2, PublicAuxName3)\ - case ID_GAME_##CODENAME##_ENABLELOWSPEC:\ - Commands::PySetConfigSpec(CONFIG_LOW_SPEC, CONFIG_##CODENAME);\ - break;\ - case ID_GAME_##CODENAME##_ENABLEMEDIUMSPEC:\ - Commands::PySetConfigSpec(CONFIG_MEDIUM_SPEC, CONFIG_##CODENAME);\ - break;\ - case ID_GAME_##CODENAME##_ENABLEHIGHSPEC:\ - Commands::PySetConfigSpec(CONFIG_HIGH_SPEC, CONFIG_##CODENAME);\ - break; - AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS -#undef AZ_RESTRICTED_PLATFORM_EXPANSION -#endif - } -} - - - namespace AzToolsFramework { void CryEditPythonHandler::Reflect(AZ::ReflectContext* context) diff --git a/Code/Editor/EditorViewportWidget.cpp b/Code/Editor/EditorViewportWidget.cpp index 1b461e1356..3f86260f8d 100644 --- a/Code/Editor/EditorViewportWidget.cpp +++ b/Code/Editor/EditorViewportWidget.cpp @@ -458,25 +458,7 @@ void EditorViewportWidget::Update() SetFOV(cameraState.m_fovOrZoom); m_Camera.SetZRange(cameraState.m_nearClip, cameraState.m_farClip); } - else if (!ed_useNewCameraSystem) - { - m_renderViewport->GetViewportContext()->SetCameraTransform(LYTransformToAZTransform(m_Camera.GetMatrix())); - } - // Don't override the game mode FOV - if (!GetIEditor()->IsInGameMode()) - { - AZ::Matrix4x4 clipMatrix; - AZ::MakePerspectiveFovMatrixRH( - clipMatrix, - GetFOV(), - aznumeric_cast(width()) / aznumeric_cast(height()), - m_Camera.GetNearPlane(), - m_Camera.GetFarPlane(), - true - ); - m_renderViewport->GetViewportContext()->SetCameraProjectionMatrix(clipMatrix); - } // Reset the camera update flag now that we're finished updating our viewport context m_updateCameraPositionNextTick = false; @@ -632,7 +614,6 @@ void EditorViewportWidget::SetViewEntity(const AZ::EntityId& viewEntityId, bool void EditorViewportWidget::ResetToViewSourceType(const ViewSourceType& viewSourceType) { LockCameraMovement(true); - m_pCameraFOVVariable = nullptr; m_viewEntityId.SetInvalid(); m_cameraObjectId = GUID_NULL; m_viewSourceType = viewSourceType; @@ -2547,13 +2528,26 @@ void EditorViewportWidget::CenterOnSliceInstance() ////////////////////////////////////////////////////////////////////////// void EditorViewportWidget::SetFOV(float fov) { - if (m_pCameraFOVVariable) + if (m_viewEntityId.IsValid()) { - m_pCameraFOVVariable->Set(fov); + Camera::CameraRequestBus::Event(m_viewEntityId, &Camera::CameraComponentRequests::SetFov, AZ::RadToDeg(fov)); } else { m_camFOV = fov; + // Set the active camera's FOV + { + AZ::Matrix4x4 clipMatrix; + AZ::MakePerspectiveFovMatrixRH( + clipMatrix, + GetFOV(), + aznumeric_cast(width()) / aznumeric_cast(height()), + m_Camera.GetNearPlane(), + m_Camera.GetFarPlane(), + true + ); + m_renderViewport->GetViewportContext()->SetCameraProjectionMatrix(clipMatrix); + } } if (m_viewPane) @@ -2580,13 +2574,7 @@ float EditorViewportWidget::GetFOV() const } } - if (m_pCameraFOVVariable) - { - float fov; - m_pCameraFOVVariable->Get(fov); - return fov; - } - else if (m_viewEntityId.IsValid()) + if (m_viewEntityId.IsValid()) { float fov = AZ::RadToDeg(m_camFOV); Camera::CameraRequestBus::EventResult(fov, m_viewEntityId, &Camera::CameraComponentRequests::GetFov); @@ -2970,7 +2958,12 @@ void EditorViewportWidget::RestoreViewportAfterGameMode() { Matrix34 preGameModeViewTM = m_preGameModeViewTM; - QString text = QString("You are exiting Game Mode. Would you like to restore the camera in the viewport to where it was before you entered Game Mode?

This option can always be changed in the General Preferences tab of the Editor Settings, by toggling the \"%1\" option.

").arg(EditorPreferencesGeneralRestoreViewportCameraSettingName); + QString text = + QString( + tr("When leaving \" Game Mode \" the engine will automatically restore your camera position to the default position before you " + "had entered Game mode.

If you dislike this setting you can always change this anytime in the global " + "preferences.

")) + .arg(EditorPreferencesGeneralRestoreViewportCameraSettingName); QString restoreOnExitGameModePopupDisabledRegKey("Editor/AutoHide/ViewportCameraRestoreOnExitGameMode"); // Read the popup disabled registry value @@ -2985,6 +2978,7 @@ void EditorViewportWidget::RestoreViewportAfterGameMode() messageBox.setDefaultButton(QMessageBox::Yes); QCheckBox* checkBox = new QCheckBox(QStringLiteral("Do not show this message again")); + checkBox->setChecked(true); messageBox.setCheckBox(checkBox); // Unconstrain the system cursor and make it visible before we show the dialog box, otherwise the user can't see the cursor. diff --git a/Code/Editor/EditorViewportWidget.h b/Code/Editor/EditorViewportWidget.h index a395ef50a4..69015dcc79 100644 --- a/Code/Editor/EditorViewportWidget.h +++ b/Code/Editor/EditorViewportWidget.h @@ -506,7 +506,6 @@ protected: CPredefinedAspectRatios m_predefinedAspectRatios; - IVariable* m_pCameraFOVVariable = nullptr; bool m_bCursorHidden = false; void OnMenuResolutionCustom(); diff --git a/Code/Editor/GraphicsSettingsDialog.cpp b/Code/Editor/GraphicsSettingsDialog.cpp deleted file mode 100644 index dbd7a7fc1a..0000000000 --- a/Code/Editor/GraphicsSettingsDialog.cpp +++ /dev/null @@ -1,1392 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ -#include -#include -#include -#include "ProjectDefines.h" -#include "EditorDefs.h" - -#include "GraphicsSettingsDialog.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -// AzFramework -#include -#include -#include -#include - -// Editor -#include "Util/AutoDirectoryRestoreFileDialog.h" - -AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING -#include "ui_graphicssettingsdialog.h" -AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING - -QString groupNames[] = -{ - "Game Effects", - "Light", - "Object Detail", - "Particles", - "Physics", - "Post Processing", - "Quality", - "Shading", - "Shadows", - "Sound", - "Texture", - "Texture Resolution", - "Volumetric Effects", - "Water", - "Miscellaneous" -}; - -GraphicsSettingsDialog::GraphicsSettingsDialog(QWidget* parent /* = nullptr */) - : QDialog(parent) - , m_ui(new Ui::GraphicsSettingsDialog()) -{ - //Update qlabel color when disabled - setStyleSheet("QLabel::disabled{color: gray;}"); - - // Start initialization the dialog - m_ui->setupUi(this); - setWindowTitle("Graphics Settings"); - m_ui->m_applyButton->setDefault(true); - m_headerView = new GraphicsSettingsHeaderView(this, Qt::Horizontal); - m_headerView->setMouseTracking(true); - m_ui->m_graphicsSettingsTreeView->setHeader(m_headerView); - ///////////////////////////////////////////// - - m_currentPlatform = GetISystem()->GetConfigPlatform(); - m_currentSpecIndex = 0; - m_dirtyCVarCount = 0; - - m_showCustomSpec = true; - ShowCustomSpecOption(false); - - // Show categories, disable apply button - m_showCategories = true; - m_ui->m_applyButton->setEnabled(false); - - m_graphicsSettingsModel = new GraphicsSettingsModel(this); - m_ui->m_graphicsSettingsTreeView->setModel(m_graphicsSettingsModel); - - m_cfgFiles[CONFIG_PC].push_back("pc_low.cfg"); - m_cfgFiles[CONFIG_PC].push_back("pc_medium.cfg"); - m_cfgFiles[CONFIG_PC].push_back("pc_high.cfg"); - m_cfgFiles[CONFIG_PC].push_back("pc_veryhigh.cfg"); - m_cfgFiles[CONFIG_OSX_METAL].push_back("osx_metal_low.cfg"); - m_cfgFiles[CONFIG_OSX_METAL].push_back("osx_metal_medium.cfg"); - m_cfgFiles[CONFIG_OSX_METAL].push_back("osx_metal_high.cfg"); - m_cfgFiles[CONFIG_OSX_METAL].push_back("osx_metal_veryhigh.cfg"); - m_cfgFiles[CONFIG_ANDROID].push_back("android_low.cfg"); - m_cfgFiles[CONFIG_ANDROID].push_back("android_medium.cfg"); - m_cfgFiles[CONFIG_ANDROID].push_back("android_high.cfg"); - m_cfgFiles[CONFIG_ANDROID].push_back("android_veryhigh.cfg"); - m_cfgFiles[CONFIG_IOS].push_back("ios_low.cfg"); - m_cfgFiles[CONFIG_IOS].push_back("ios_medium.cfg"); - m_cfgFiles[CONFIG_IOS].push_back("ios_high.cfg"); - m_cfgFiles[CONFIG_IOS].push_back("ios_veryhigh.cfg"); -#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) -#define AZ_RESTRICTED_PLATFORM_EXPANSION(CodeName, CODENAME, codename, PrivateName, PRIVATENAME, privatename, PublicName, PUBLICNAME, publicname, PublicAuxName1, PublicAuxName2, PublicAuxName3)\ - m_cfgFiles[CONFIG_##CODENAME].push_back(#publicname "_low.cfg");\ - m_cfgFiles[CONFIG_##CODENAME].push_back(#publicname "_medium.cfg");\ - m_cfgFiles[CONFIG_##CODENAME].push_back(#publicname "_high.cfg"); - AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS -#undef AZ_RESTRICTED_PLATFORM_EXPANSION -#endif - // Since the layout order is set by the .ui file we need to match the order here so that tabbing works correctly. - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_gameeffects.cfg"); - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_light.cfg"); - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_objectdetail.cfg"); - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_particles.cfg"); - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_physics.cfg"); - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_postprocessing.cfg"); - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_quality.cfg"); - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_shading.cfg"); - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_shadows.cfg"); - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_sound.cfg"); - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_texture.cfg"); - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_textureresolution.cfg"); - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_volumetriceffects.cfg"); - m_cvarGroupOrder.push_back("Config/CVarGroups/sys_spec_water.cfg"); - m_cvarGroupOrder.push_back("miscellaneous"); - - m_platformStrings.push_back(AZStd::make_pair("PC", CONFIG_PC)); - m_platformStrings.push_back(AZStd::make_pair("OSX Metal", CONFIG_OSX_METAL)); - m_platformStrings.push_back(AZStd::make_pair("Android", CONFIG_ANDROID)); - m_platformStrings.push_back(AZStd::make_pair("iOS", CONFIG_IOS)); -#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) -#define AZ_RESTRICTED_PLATFORM_EXPANSION(CodeName, CODENAME, codename, PrivateName, PRIVATENAME, privatename, PublicName, PUBLICNAME, publicname, PublicAuxName1, PublicAuxName2, PublicAuxName3)\ - m_platformStrings.push_back(AZStd::make_pair(PublicAuxName2, CONFIG_##CODENAME)); - AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS -#undef AZ_RESTRICTED_PLATFORM_EXPANSION -#endif - m_platformStrings.push_back(AZStd::make_pair("Custom", CONFIG_INVALID_PLATFORM)); - - for (auto& platformString : m_platformStrings) - { - QString platform = platformString.first.c_str(); - m_ui->m_platformEntry->addItem(platform); - } - - QSettings settings("O3DE", "O3DE"); - settings.beginGroup("GraphicsSettingsDialog"); - - if (settings.contains("Platform")) - { - QString platformName = settings.value("Platform").toString(); - AZStd::string azPlatform = platformName.toUtf8().data(); - m_currentPlatform = GetConfigPlatformFromName(azPlatform); - if (m_currentPlatform == CONFIG_INVALID_PLATFORM) - { - ShowCustomSpecOption(true); - } - } - - settings.endGroup(); - - SetPlatformEntry(m_currentPlatform); - - BuildUI(); - - connect(m_ui->m_graphicsSettingsTreeView, &QTreeView::collapsed, this, [&](const QModelIndex& index) { SetCollapsed(index, true); }); - connect(m_ui->m_graphicsSettingsTreeView, &QTreeView::expanded, this, [&](const QModelIndex& index) { SetCollapsed(index, false); }); - - AzQtComponents::StyleManager::setStyleSheet(this, "style:GraphicsSettingsDialog.qss"); -} - -GraphicsSettingsDialog::~GraphicsSettingsDialog() -{ - QSettings settings("O3DE", "O3DE"); - settings.beginGroup("GraphicsSettingsDialog"); - - auto platformCheck = [this](AZStd::pair& stringConfigPair) { return stringConfigPair.second == m_currentPlatform; }; - auto platformStringsIterator = AZStd::find_if(m_platformStrings.begin(), m_platformStrings.end(), platformCheck); - if (platformStringsIterator != m_platformStrings.end()) - { - settings.setValue("Platform", platformStringsIterator->first.c_str()); - } - else - { - settings.remove("Platform"); - } - - settings.beginGroup("cvarGroup"); - - for (auto& collapseIterator : m_uiCollapseGroup) - { - settings.setValue(collapseIterator->m_groupName, collapseIterator->m_isCollapsed); - } - - settings.endGroup(); - settings.endGroup(); - settings.sync(); - - for (CollapseGroup* group : m_uiCollapseGroup) - { - // Destructor of CollapseGroup will set the members - // pointing to nullptr. The actually destruction of the - // widgets will be done on destruction of m_ui - delete group; - } - - for (ParameterWidget* widget : m_parameterWidgets) - { - // Destructor of ParameterWidget will set the members - // pointing to nullptr. The actually destruction of the - // widgets will be done on destruction of m_ui - delete widget; - } - - // Delete m_ui will destruct all the UI elements with in the ui file - // Since m_ui is a QScopedPointer which will cleanup itself on the end - // of the scope. -} - -void GraphicsSettingsDialog::SetSettingsTree(int numColumns) -{ - m_graphicsSettingsModel->clear(); - m_uiCollapseGroup.clear(); - m_graphicsSettingsModel->setColumnCount(numColumns); - - for (int i = 1; i < numColumns; ++i) - { - m_ui->m_graphicsSettingsTreeView->header()->setSectionResizeMode(i, QHeaderView::Stretch); - } - - m_ui->m_graphicsSettingsTreeView->setColumnWidth(0, 200); - m_ui->m_graphicsSettingsTreeView->header()->setMinimumSectionSize(100); - - m_graphicsSettingsModel->setHeaderData(0, Qt::Horizontal, "Properties"); - - auto parentItem = m_graphicsSettingsModel->invisibleRootItem(); - - for (int i = 0; i < aznumeric_cast(GraphicsSettings::numSettings); ++i) - { - QStandardItem* row = new QStandardItem(); - row->setData(groupNames[i], Qt::DisplayRole); - parentItem->appendRow(row); - SetCollapsedLayout(groupNames[i].replace(" ", ""), row); - } - m_numColumns = numColumns; - - m_cvarGroupData["Config/CVarGroups/sys_spec_gameeffects.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::GameEffects)); - m_cvarGroupData["Config/CVarGroups/sys_spec_light.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::Light)); - m_cvarGroupData["Config/CVarGroups/sys_spec_objectdetail.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::ObjectDetail)); - m_cvarGroupData["Config/CVarGroups/sys_spec_particles.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::Particles)); - m_cvarGroupData["Config/CVarGroups/sys_spec_physics.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::Physics)); - m_cvarGroupData["Config/CVarGroups/sys_spec_postprocessing.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::PostProcessing)); - m_cvarGroupData["Config/CVarGroups/sys_spec_quality.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::Quality)); - m_cvarGroupData["Config/CVarGroups/sys_spec_shading.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::Shading)); - m_cvarGroupData["Config/CVarGroups/sys_spec_shadows.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::Shadows)); - m_cvarGroupData["Config/CVarGroups/sys_spec_sound.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::Sound)); - m_cvarGroupData["Config/CVarGroups/sys_spec_texture.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::Texture)); - m_cvarGroupData["Config/CVarGroups/sys_spec_textureresolution.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::TextureResolution)); - m_cvarGroupData["Config/CVarGroups/sys_spec_volumetriceffects.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::VolumetricEffects)); - m_cvarGroupData["Config/CVarGroups/sys_spec_water.cfg"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::Water)); - m_cvarGroupData["miscellaneous"].m_treeRowItem = m_graphicsSettingsModel->item(aznumeric_cast(GraphicsSettings::Miscellaneous)); -} - -void GraphicsSettingsDialog::OnLoadConfigurationEntry(const char* strKey, const char* strValue, const char* strGroup) -{ - AZStd::string key = strKey; - ICVar* cvar = gEnv->pConsole->GetCVar(strKey); - - if (cvar) - { - AZStd::transform(key.begin(), key.end(), key.begin(), tolower); - if (azstricmp(key.c_str(), "sys_spec_full") == 0 || key.find("sys_spec_") == key.npos) - { - int type = cvar->GetType(); - AZStd::any val; - if (type == CVAR_INT) - { - val = atoi(strValue); - } - else if (type == CVAR_FLOAT) - { - val = static_cast(atof(strValue)); - } - else - { - val = AZStd::string(strValue); - } - - // Platform cfg file (ex. pc_veryhigh.cfg) - if (strGroup[0] == '\0') - { - // New cvar loaded into map - if (m_cVarTracker.find(key) == m_cVarTracker.end()) - { - m_cVarTracker[key].type = type; - m_cVarTracker[key].cvarGroup = "miscellaneous"; - AZStd::any empty; - if (type == CVAR_INT) - { - empty = 0; - } - else if (type == CVAR_FLOAT) - { - empty = 0.0f; - } - else - { - empty = AZStd::string(""); - } - m_cVarTracker[key].fileVals.resize(m_numSpecLevels, CVarFileStatus(empty, empty, empty)); - } - - m_cVarTracker[key].fileVals[m_currentSpecIndex].editedValue = val; - m_cVarTracker[key].fileVals[m_currentSpecIndex].overwrittenValue = val; - } - // default group in sys_spec cfg file - else if (azstricmp(strGroup, "default") == 0) - { - CVarFileStatus defaultVal(val, val, val); - if (m_cVarTracker.find(key) == m_cVarTracker.end()) - { - // New cvar loaded into map - CVarInfo& currentCVar = m_cVarTracker[key]; - currentCVar.type = cvar->GetType(); - currentCVar.fileVals.resize(m_numSpecLevels, defaultVal); - } - else - { - // Reset values, if there's a platform override it always follows the sys_spec_*.cfg files. - // Resetting avoids the issue where some spec levels are never set because of an extra platform - // override load happening earlier just to store the value of sys_spec_full. - for (int specLevel = 0; specLevel < m_numSpecLevels; ++specLevel) - { - m_cVarTracker[key].fileVals[specLevel] = defaultVal; - } - } - // Overwrite miscellaneous if mentioned in platform config file - m_cVarTracker[key].cvarGroup = m_currentConfigFilename; - } - // specific index in sys_spec cfg file - else - { - int group = 0; - - if (azsscanf(strGroup, "%d", &group) == 1) - { - auto sysSpecFull = m_cVarTracker.find("sys_spec_full"); - if (sysSpecFull != m_cVarTracker.end()) - { - CVarFileStatus indexAssignment(val, val, val); - for (int specLevel = 0; specLevel < m_numSpecLevels; ++specLevel) - { - // Only apply cvar change to configurations with sys_spec_Full matching the index - int overwrittenValue = 0; - if (AZStd::any_numeric_cast(&sysSpecFull->second.fileVals[specLevel].overwrittenValue, overwrittenValue) && group == overwrittenValue) - { - m_cVarTracker[key].fileVals[specLevel] = indexAssignment; - } - } - } - } - } - } - } -} - -// Loads UI column for specific cfg file (ex. pc_low.cfg) -void GraphicsSettingsDialog::BuildColumn(int specLevel) -{ - if (specLevel < 0 || specLevel >= m_numSpecLevels) - { - return; - } - - for (auto& it : m_cvarGroupData) - { - it.second.m_currentRow = 0; - } - - for (auto& it : m_cVarTracker) - { - QString str = it.first.c_str(); - QWidget* input = nullptr; - if (it.second.type == CVAR_INT) - { - AzQtComponents::SpinBox* intval = new AzQtComponents::SpinBox(nullptr); - intval->setFocusPolicy(Qt::StrongFocus); - intval->setMaximum(INT32_MAX); - intval->setMinimum(INT32_MIN); - int editedValue; - if (AZStd::any_numeric_cast(&it.second.fileVals[specLevel].editedValue, editedValue)) - { - intval->setValue(editedValue); - } - m_cvarGroupData[it.second.cvarGroup].m_cvarSpinBoxes.push_back(intval); - connect(intval, SIGNAL(valueChanged(int)), this, SLOT(CVarChanged(int))); - input = intval; - } - else if (it.second.type == CVAR_FLOAT) - { - AzQtComponents::DoubleSpinBox* doubleval = new AzQtComponents::DoubleSpinBox(nullptr); - doubleval->setFocusPolicy(Qt::StrongFocus); - doubleval->setMaximum(FLT_MAX); - doubleval->setMinimum(-FLT_MAX); - float editedValue; - if (AZStd::any_numeric_cast(&it.second.fileVals[specLevel].editedValue, editedValue)) - { - doubleval->setValue(editedValue); - } - m_cvarGroupData[it.second.cvarGroup].m_cvarDoubleSpinBoxes.push_back(doubleval); - connect(doubleval, SIGNAL(valueChanged(double)), this, SLOT(CVarChanged(double))); - input = doubleval; - } - else - { - QLineEdit* stringval = new QLineEdit(nullptr); - AZStd::string* editedValue = AZStd::any_cast(&it.second.fileVals[specLevel].editedValue); - stringval->setText(editedValue->c_str()); - m_cvarGroupData[it.second.cvarGroup].m_cvarLineEdits.push_back(stringval); - connect(stringval, SIGNAL(textChanged(const QString&)), this, SLOT(CVarChanged(const QString&))); - input = stringval; - } - - if (input) - { - input->setObjectName(str); - input->setProperty("specLevel", specLevel); - QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - sizePolicy.setHeightForWidth(input->sizePolicy().hasHeightForWidth()); - input->setSizePolicy(sizePolicy); - input->setMinimumSize(QSize(INPUT_MIN_WIDTH, INPUT_MIN_HEIGHT)); - QStandardItem* parentItem = m_cvarGroupData[it.second.cvarGroup].m_treeRowItem; - QModelIndex parentIndex = parentItem->index(); - QModelIndex thisIndex = m_graphicsSettingsModel->index(m_cvarGroupData[it.second.cvarGroup].m_currentRow++, specLevel + CVAR_VALUE_COLUMN_OFFSET, parentIndex); - m_ui->m_graphicsSettingsTreeView->setIndexWidget(thisIndex, input); - m_parameterWidgets.push_back(new ParameterWidget(input, it.first.c_str())); - m_cvarGroupData[it.second.cvarGroup].m_widgetInsertOrder.push_back(input); - } - } -} - -void GraphicsSettingsDialog::LoadPlatformConfigurations() -{ - const int numColumns = m_cfgFiles[m_currentPlatform].size() + 1; - SetSettingsTree(numColumns); - - for (ParameterWidget* widget : m_parameterWidgets) - { - delete widget; - } - m_parameterWidgets.clear(); - - m_ui->m_applyButton->setEnabled(false); - m_dirtyCVarCount = 0; - - // Load platform cfg files to load in sys_spec_Full - for (size_t cfgFileIndex = 0; cfgFileIndex < m_cfgFiles[m_currentPlatform].size(); ++cfgFileIndex) - { - m_currentSpecIndex = cfgFileIndex; - m_currentConfigFilename = m_cfgFiles[m_currentPlatform][cfgFileIndex]; - GetISystem()->LoadConfiguration(m_currentConfigFilename.c_str(), this, true); - } - - if (m_cVarTracker.find("sys_spec_full") == m_cVarTracker.end()) - { - m_cVarTracker.clear(); - CleanUI(); - ShowCategories(false); - QMessageBox::warning(this, "Warning", "Invalid custom spec file (missing sys_spec_full).", - QMessageBox::Ok); - return; - } - - // Load sys_spec cfgs based on sys_spec_Full values - LoadCVarGroupDirectory(m_cvarGroupsFolder); - - setUpdatesEnabled(false); - - // Reload platform cfg files to override sys_spec index assignments and load rows with filenames of given platform - for (size_t cfgFileIndex = 0; cfgFileIndex < m_cfgFiles[m_currentPlatform].size(); ++cfgFileIndex) - { - m_currentSpecIndex = cfgFileIndex; - m_currentConfigFilename = m_cfgFiles[m_currentPlatform][cfgFileIndex]; - GetISystem()->LoadConfiguration(m_currentConfigFilename.c_str(), this, true); - - /*CVarGroupInfo& specFileGroup =*/ m_cvarGroupData["SpecFile"]; - m_graphicsSettingsModel->setHeaderData(cfgFileIndex + CVAR_VALUE_COLUMN_OFFSET, Qt::Horizontal, QApplication::translate("GraphicsSettingsDialog", m_cfgFiles[m_currentPlatform][cfgFileIndex].c_str())); - } - - // Loads column of cvar names - for (auto& it : m_cVarTracker) - { - QLabel* cVarLabel = new QLabel(nullptr); - QString str = it.first.c_str(); - QString strLabel = str + "Label"; - cVarLabel->setObjectName(strLabel); - QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - sizePolicy.setHeightForWidth(cVarLabel->sizePolicy().hasHeightForWidth()); - cVarLabel->setSizePolicy(sizePolicy); - cVarLabel->setMinimumSize(QSize(INPUT_MIN_WIDTH, INPUT_MIN_HEIGHT)); - cVarLabel->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); - QStandardItem* cVarItem = new QStandardItem(); - cVarItem->setData(QApplication::translate("GraphicsSettingsDialog", it.first.c_str(), 0), Qt::DisplayRole); - QList items{ cVarItem }; - for (int i = 1; i < numColumns; ++i) - { - items << new QStandardItem(); - } - m_cvarGroupData[it.second.cvarGroup].m_treeRowItem->appendRow(items); - cVarLabel->setText(QApplication::translate("GraphicsSettingsDialog", it.first.c_str(), 0)); - m_cvarGroupData[it.second.cvarGroup].m_cvarLabels.push_back(cVarLabel); - - if (ICVar* cvar = gEnv->pConsole->GetCVar(it.first.c_str())) - { - cVarLabel->setToolTip(cvar->GetHelp()); - } - } - - // Loads columns of cvar values for each platform cfg file - for (int cfgFileIndex = 0; cfgFileIndex < m_cfgFiles[m_currentPlatform].size(); ++cfgFileIndex) - { - BuildColumn(cfgFileIndex); - } - - // Remove any section that has no visible controls - for (auto& it : m_cvarGroupData) - { - int totalControlCount = 0; - CVarGroupInfo& currentCvarGroupInfo = it.second; - totalControlCount += currentCvarGroupInfo.m_cvarDoubleSpinBoxes.size(); - totalControlCount += currentCvarGroupInfo.m_cvarSpinBoxes.size(); - totalControlCount += currentCvarGroupInfo.m_cvarLineEdits.size(); - totalControlCount += currentCvarGroupInfo.m_platformLabels.size(); - - if (totalControlCount == 0) - { - if (currentCvarGroupInfo.m_treeRowItem) - { - int i = 0; - for (auto& collapseIterator : m_uiCollapseGroup) - { - if (collapseIterator->m_groupRow == currentCvarGroupInfo.m_treeRowItem) - { - m_uiCollapseGroup.remove(i); - break; - } - ++i; - } - m_graphicsSettingsModel->removeRow(currentCvarGroupInfo.m_treeRowItem->row()); - } - } - } - - setUpdatesEnabled(true); - - QSettings settings("O3DE", "O3DE"); - settings.beginGroup("GraphicsSettingsDialog"); - settings.beginGroup("cvarGroup"); - - for (auto& collapseIterator : m_uiCollapseGroup) - { - bool groupCollapsed = settings.value(collapseIterator->m_groupName, collapseIterator->m_isCollapsed).toBool(); - if (collapseIterator->m_isCollapsed != groupCollapsed) - { - collapseIterator->ToggleCollapsed(); - } - } - - settings.endGroup(); - settings.endGroup(); -} - -void GraphicsSettingsDialog::LoadCVarGroupDirectory(const AZStd::string& path) -{ - AZ::IO::LocalFileIO::FindFilesCallbackType fileFinderCb; - fileFinderCb = [&](const char* fullPath) -> bool - { - if (gEnv->pFileIO->IsDirectory(fullPath)) - { - // recurse into subdirectory - gEnv->pFileIO->FindFiles(fullPath, "*.cfg", fileFinderCb); - } - else - { - m_currentConfigFilename = fullPath; - GetISystem()->LoadConfiguration(fullPath, this, false); - } - - return true; // keep searching - }; - - gEnv->pFileIO->FindFiles(path.c_str(), "*.cfg", fileFinderCb); -} - -//Build UI, link signals and set the data for device list. -void GraphicsSettingsDialog::BuildUI() -{ - connect(m_ui->m_cancelButton, &QPushButton::clicked, this, &GraphicsSettingsDialog::reject); - connect(m_ui->m_applyButton, &QPushButton::clicked, this, &GraphicsSettingsDialog::accept); - connect(m_ui->m_platformEntry, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(PlatformChanged(const QString&))); - connect(m_ui->m_selectCustomSpecButton, &QPushButton::clicked, this, &GraphicsSettingsDialog::OpenCustomSpecDialog); - - if (!m_cfgFiles[m_currentPlatform].empty()) - { - LoadPlatformConfigurations(); - } - else - { - m_cVarTracker.clear(); - CleanUI(); - ShowCategories(false); - } -} - -void GraphicsSettingsDialog::CleanUI() -{ - setUpdatesEnabled(false); - - QSettings settings("O3DE", "O3DE"); - settings.beginGroup("GraphicsSettingsDialog"); - settings.beginGroup("cvarGroup"); - - for (auto& collapseIterator : m_uiCollapseGroup) - { - settings.setValue(collapseIterator->m_groupName, collapseIterator->m_isCollapsed); - } - - settings.endGroup(); - settings.endGroup(); - settings.sync(); - - m_cVarTracker.clear(); - - // Uncollapse groups - for (auto& collapseIt : m_uiCollapseGroup) - { - if (collapseIt->m_isCollapsed) - { - collapseIt->ToggleCollapsed(); - } - } - - setUpdatesEnabled(true); -} - -void GraphicsSettingsDialog::ShowCategories(bool show) -{ - if (m_showCategories == show) - { - return; - } - - m_showCategories = show; - m_ui->m_graphicsSettingsTreeView->setVisible(show); -} - -void GraphicsSettingsDialog::ShowCustomSpecOption(bool show) -{ - if (m_showCustomSpec == show) - { - return; - } - - m_showCustomSpec = show; - m_ui->m_selectCustomSpecButton->setVisible(m_showCustomSpec); - m_ui->m_lineSpacer->setVisible(m_showCustomSpec); -} - -void GraphicsSettingsDialog::PlatformChanged(const QString& platform) -{ - bool change = true; - if (m_dirtyCVarCount > 0 && !SendUnsavedChangesWarning(false)) - { - change = false; - } - - if (change) - { - AZStd::string azPlatform = platform.toStdString().c_str(); - - m_currentPlatform = GetConfigPlatformFromName(azPlatform); - if (m_currentPlatform == CONFIG_INVALID_PLATFORM) // "Custom" selected - { - ShowCustomSpecOption(true); - CleanUI(); - if (m_cfgFiles[CONFIG_INVALID_PLATFORM].empty()) // if we don't have a custom spec - { - ShowCategories(false); - m_ui->m_applyButton->setEnabled(false); - m_dirtyCVarCount = 0; - } - else - { - ShowCategories(true); - LoadPlatformConfigurations(); - } - } - else - { - ShowCustomSpecOption(false); - ShowCategories(true); - CleanUI(); - LoadPlatformConfigurations(); - } - } - else - { - m_ui->m_platformEntry->blockSignals(true); - SetPlatformEntry(m_currentPlatform); - m_ui->m_platformEntry->blockSignals(false); - } -} - -bool GraphicsSettingsDialog::SendUnsavedChangesWarning(bool cancel) -{ - int result = QMessageBox::Yes; - - if (cancel) - { - result = QMessageBox::question(this, "Warning", "There are currently unsaved changed. Are you sure you want to cancel?", - QMessageBox::Yes, QMessageBox::No); - } - else - { - result = QMessageBox::question(this, "Warning", "There are currently unsaved changed. Are you sure you want to change configurations?", - QMessageBox::Yes, QMessageBox::No); - } - - return (result == QMessageBox::Yes); -} - -bool GraphicsSettingsDialog::CVarChanged(AZStd::any val, const char* cvarName, int specLevel) -{ - // Checking if the edited value (before change) is equal to the overwritten value - bool dirtyBefore = false; - AZStd::string azcvarName = cvarName; - AZStd::pair cvarInfo = AZStd::make_pair(azcvarName, m_cVarTracker[cvarName]); - if (CheckCVarStatesForDiff(&cvarInfo, specLevel, EDITED_OVERWRITTEN_COMPARE)) - { - dirtyBefore = true; - } - - if (azstricmp(cvarName, "sys_spec_full") == 0) - { - //Pop out the warning dialog for sys_spec_Full since all cvars will be changed - int result = QMessageBox::Ok; - - result = QMessageBox::question(this, "Warning", "Modifying sys_spec_full will override any unsaved changes.", - QMessageBox::Ok, QMessageBox::Cancel); - - // Cancel - Change sys_spec_full qspinbox value back - if (result == QMessageBox::Cancel) - { - return false; - } - else // OK - reload column - { - // Updating sys_spec_full for when adding cvargroup directory - m_cVarTracker[cvarName].fileVals[specLevel].editedValue = val; - gEnv->pSystem->AddCVarGroupDirectory(m_cvarGroupsFolder); - m_currentConfigFilename = m_cfgFiles[m_currentPlatform][specLevel]; - m_currentSpecIndex = specLevel; - GetISystem()->LoadConfiguration(m_currentConfigFilename.c_str(), this, true); - // Updating sys_spec_full since overwritten from loading platform cfg - m_cVarTracker[cvarName].fileVals[specLevel].editedValue = val; - BuildColumn(specLevel); - } - } - else - { - m_cVarTracker[cvarName].fileVals[specLevel].editedValue = val; - } - - // Checking if the newly edited value is equal to the overwritten value - cvarInfo = AZStd::make_pair(azcvarName, m_cVarTracker[cvarName]); - if (CheckCVarStatesForDiff(&cvarInfo, specLevel, EDITED_OVERWRITTEN_COMPARE)) - { - if (!dirtyBefore) - { - m_ui->m_applyButton->setEnabled(true); - m_dirtyCVarCount++; - } - } - else - { - if (dirtyBefore) - { - m_dirtyCVarCount--; - if (m_dirtyCVarCount == 0) - { - m_ui->m_applyButton->setEnabled(false); - } - } - } - - return true; -} - -void GraphicsSettingsDialog::CVarChanged(int i) -{ - AzQtComponents::SpinBox* box = static_cast(sender()); - QString str = box->objectName(); - QByteArray ba = str.toUtf8(); - const char* cvarName = ba.data(); - - int specLevel = box->property("specLevel").toInt(); - - AZStd::any val; - val = i; - - if (!CVarChanged(val, cvarName, specLevel)) - { - // sys_spec_full warning cancelled - box->blockSignals(true); - int editedValue; - if (AZStd::any_numeric_cast(&m_cVarTracker[cvarName].fileVals[specLevel].editedValue, editedValue)) - { - box->setValue(editedValue); - } - box->blockSignals(false); - } -} - -void GraphicsSettingsDialog::CVarChanged(double d) -{ - AzQtComponents::DoubleSpinBox* box = static_cast(sender()); - QString str = box->objectName(); - QByteArray ba = str.toUtf8(); - const char* cvarName = ba.data(); - - AZStd::any val; - val = d; - - int specLevel = box->property("specLevel").toInt(); - - if (!CVarChanged(val, cvarName, specLevel)) - { - // only can return false from sys_spec_full, which is an int cvar - } -} - -void GraphicsSettingsDialog::CVarChanged(const QString& s) -{ - QLineEdit* box = qobject_cast(sender()); - QString str = box->objectName(); - QByteArray ba = str.toUtf8(); - const char* cvarName = ba.data(); - - AZStd::any val; - val = AZStd::string(s.toStdString().c_str()); - - int specLevel = box->property("specLevel").toInt(); - - if (!CVarChanged(val, cvarName, specLevel)) - { - // only can return false from sys_spec_full, which is an int cvar - } -} - -// Returns true if there is a difference between the two cvar states -bool GraphicsSettingsDialog::CheckCVarStatesForDiff(AZStd::pair* it, int cfgFileIndex, CVarStateComparison cmp) -{ - if (it->second.type == CVAR_INT) - { - int editedVal, overwrittenVal, originalVal; - if (AZStd::any_numeric_cast(&it->second.fileVals[cfgFileIndex].editedValue, editedVal) && - AZStd::any_numeric_cast(&it->second.fileVals[cfgFileIndex].overwrittenValue, overwrittenVal) && - AZStd::any_numeric_cast(&it->second.fileVals[cfgFileIndex].originalValue, originalVal)) - { - if ((cmp == EDITED_OVERWRITTEN_COMPARE && editedVal != overwrittenVal) || - (cmp == EDITED_ORIGINAL_COMPARE && editedVal != originalVal) || - (cmp == OVERWRITTEN_ORIGINAL_COMPARE && overwrittenVal != originalVal)) - { - return true; - } - } - } - else if (it->second.type == CVAR_FLOAT) - { - float editedVal, overwrittenVal, originalVal; - if (AZStd::any_numeric_cast(&it->second.fileVals[cfgFileIndex].editedValue, editedVal) && - AZStd::any_numeric_cast(&it->second.fileVals[cfgFileIndex].overwrittenValue, overwrittenVal) && - AZStd::any_numeric_cast(&it->second.fileVals[cfgFileIndex].originalValue, originalVal)) - { - if ((cmp == EDITED_OVERWRITTEN_COMPARE && editedVal != overwrittenVal) || - (cmp == EDITED_ORIGINAL_COMPARE && editedVal != originalVal) || - (cmp == OVERWRITTEN_ORIGINAL_COMPARE && overwrittenVal != originalVal)) - { - return true; - } - } - } - else - { - AZStd::string editedVal = *AZStd::any_cast(&it->second.fileVals[cfgFileIndex].editedValue); - AZStd::string overwrittenVal = *AZStd::any_cast(&it->second.fileVals[cfgFileIndex].overwrittenValue); - AZStd::string originalVal = *AZStd::any_cast(&it->second.fileVals[cfgFileIndex].originalValue); - if ((cmp == EDITED_OVERWRITTEN_COMPARE && editedVal.compare(overwrittenVal) != 0) || - (cmp == EDITED_ORIGINAL_COMPARE && editedVal.compare(originalVal) != 0) || - (cmp == OVERWRITTEN_ORIGINAL_COMPARE && overwrittenVal.compare(originalVal) != 0)) - { - return true; - } - } - return false; -} - -/////////////////////////////////////////////////////////////////////// -// settings file management -void GraphicsSettingsDialog::reject() -{ - if (m_dirtyCVarCount > 0) - { - if (SendUnsavedChangesWarning(true)) - { - QDialog::reject(); - } - } - else - { - QDialog::reject(); - } -} - -void GraphicsSettingsDialog::accept() -{ - int result = QMessageBox::Yes; - - //Pop out the warning dialog for customized setting - result = QMessageBox::question(this, "Warning", "A non-tested setting could potentially crash the game if the setting does not match the device. Are you sure you want to apply the customized setting?", - QMessageBox::Yes, QMessageBox::No); - - //Save and exit - if (result == QMessageBox::Yes) - { - SaveSystemSettings(); - } -} - -void GraphicsSettingsDialog::OpenCustomSpecDialog() -{ - AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); - projectPath /= SETTINGS_FILE_PATH.toUtf8().constData(); - QString settingsPath = QString::fromUtf8(projectPath.c_str(), aznumeric_cast(projectPath.Native().size())); - - CAutoDirectoryRestoreFileDialog importCustomSpecDialog(QFileDialog::AcceptOpen, QFileDialog::ExistingFile, ".cfg", settingsPath, CFG_FILEFILTER, {}, {}, this); - - if (importCustomSpecDialog.exec()) - { - QString file = importCustomSpecDialog.selectedFiles().first(); - if (!file.isEmpty()) - { - ApplyCustomSpec(file); - } - } -} - -void GraphicsSettingsDialog::ApplyCustomSpec(const QString& customFilePath) -{ - if (customFilePath.isEmpty()) - { - return; - } - - QFile customFile(customFilePath); - if (!customFile.exists()) - { - QMessageBox::warning(this, "Warning", "Could not find custom spec file.", - QMessageBox::Ok); - return; - } - - bool change = true; - if (m_dirtyCVarCount > 0 && !SendUnsavedChangesWarning(false)) - { - change = false; - } - - if (change) - { - AZStd::string filename = customFilePath.toStdString().c_str(); - filename = filename.substr(filename.find_last_of('/') + 1); - - m_currentPlatform = CONFIG_INVALID_PLATFORM; - - bool alreadyLoaded = IsCustomSpecAlreadyLoaded(filename); - if (m_cfgFiles[CONFIG_INVALID_PLATFORM].size() < m_numSpecLevels && !alreadyLoaded) - { - m_cfgFiles[CONFIG_INVALID_PLATFORM].push_back(filename); - } - else if (alreadyLoaded) - { - QMessageBox::warning(this, "Warning", "The selected custom spec file is already loaded. No changes have been made.", - QMessageBox::Ok); - return; - } - - if (m_cfgFiles[CONFIG_INVALID_PLATFORM].size() == m_numSpecLevels) - { - m_ui->m_selectCustomSpecButton->setEnabled(false); - } - - ShowCategories(true); - - CleanUI(); - - LoadPlatformConfigurations(); - } -} - -void GraphicsSettingsDialog::UnloadCustomSpec(int specLevel) -{ - if (specLevel < 0 || specLevel >= m_cfgFiles[CONFIG_INVALID_PLATFORM].size()) - { - return; - } - - bool shouldUnload = m_dirtyCVarCount <= 0 || SendUnsavedChangesWarning(false); - - if (shouldUnload) - { - m_cfgFiles[CONFIG_INVALID_PLATFORM].erase(m_cfgFiles[CONFIG_INVALID_PLATFORM].begin() + specLevel); - - CleanUI(); - - if (!m_cfgFiles[CONFIG_INVALID_PLATFORM].empty()) - { - LoadPlatformConfigurations(); - } - else - { - ShowCategories(false); - } - } -} - -bool GraphicsSettingsDialog::IsCustomSpecAlreadyLoaded(const AZStd::string& filename) const -{ - auto& customConfigFilenames = m_cfgFiles.at(CONFIG_INVALID_PLATFORM); - const auto& findResult = AZStd::find(customConfigFilenames.begin(), customConfigFilenames.end(), filename.c_str()); - - return findResult != customConfigFilenames.end(); -} - -void GraphicsSettingsDialog::SetCollapsedLayout(const QString& groupName, QStandardItem* groupRow) -{ - CollapseGroup* cgroup = new CollapseGroup(m_ui->m_graphicsSettingsTreeView); - cgroup->m_groupName = groupName; - cgroup->m_groupRow = groupRow; - m_uiCollapseGroup.push_back(cgroup); -} - -void GraphicsSettingsDialog::SetPlatformEntry(ESystemConfigPlatform platform) -{ - auto platformCheck = [&platform](AZStd::pair& stringConfigPair) { return stringConfigPair.second == platform; }; - auto platformStringsIterator = AZStd::find_if(m_platformStrings.begin(), m_platformStrings.end(), platformCheck); - if (platformStringsIterator != m_platformStrings.end()) - { - int platformIndex = m_ui->m_platformEntry->findText(platformStringsIterator->first.c_str()); - m_ui->m_platformEntry->setCurrentIndex(platformIndex); - } - else - { - AZ_Assert(false, "Platform not found in platform strings vector."); - } -} - -ESystemConfigPlatform GraphicsSettingsDialog::GetConfigPlatformFromName(const AZStd::string& platformName) -{ - ESystemConfigPlatform configPlatform = CONFIG_INVALID_PLATFORM; - - auto platformNameCheck = [&platformName](AZStd::pair& stringConfigPair) { return (stringConfigPair.first == platformName); }; - auto configPlatformIterator = AZStd::find_if(m_platformStrings.begin(), m_platformStrings.end(), platformNameCheck); - if (configPlatformIterator != m_platformStrings.end()) - { - configPlatform = configPlatformIterator->second; - } - else - { - AZ_Assert(false, "Platform name not found in platform strings vector."); - } - - return configPlatform; -} - -// Save the current UI options to system qsettings -void GraphicsSettingsDialog::SaveSystemSettings() -{ - AZStd::vector successFiles; - AZStd::vector nochangeFiles; - - for (int cfgFileIndex = 0; cfgFileIndex < m_cfgFiles[m_currentPlatform].size(); ++cfgFileIndex) - { - const QString eq = " = "; - const QString cvarGroupString1 = "\n------------------------\n-- "; - const QString cvarGroupString2 = "\n------------------------\n"; - QString commandList = ""; - - int sysSpecFull; - if (AZStd::any_numeric_cast(&m_cVarTracker["sys_spec_full"].fileVals[cfgFileIndex].editedValue, sysSpecFull)) - { - commandList += "sys_spec_full" + eq + QString::number(sysSpecFull) + '\n'; - } - - QMap cvarGroupStrings; - - // Set to true as soon as cvar is found which is unique from current cfg file and index assignment - bool saveOut = false; - - // Adding any dirty cvars not equal to sys_spec_full or any cvar in miscellaneous to command list - for (auto& it : m_cVarTracker) - { - if ((CheckCVarStatesForDiff(&it, cfgFileIndex, EDITED_ORIGINAL_COMPARE) || it.second.cvarGroup == "miscellaneous") && azstricmp(it.first.c_str(), "sys_spec_full")) - { - AZStd::string cvarGroup = it.second.cvarGroup; - if (azstricmp(cvarGroup.c_str(), "miscellaneous") != 0) - { - int fileIndex = cvarGroup.find_last_of('/') + 1; - cvarGroup = cvarGroup.substr(fileIndex, cvarGroup.size() - fileIndex - 4); - } - QString qcvarGroup = cvarGroup.c_str(); - if (cvarGroupStrings.find(qcvarGroup) == cvarGroupStrings.end()) - { - cvarGroupStrings[qcvarGroup] = cvarGroupString1 + qcvarGroup + cvarGroupString2; - } - - if (it.second.type == CVAR_INT) - { - int val; - if (AZStd::any_numeric_cast(&it.second.fileVals[cfgFileIndex].editedValue, val)) - { - cvarGroupStrings[qcvarGroup] += it.first.c_str() + eq + QString::number(val) + '\n'; - } - } - else if (it.second.type == CVAR_FLOAT) - { - float val; - if (AZStd::any_numeric_cast(&it.second.fileVals[cfgFileIndex].editedValue, val)) - { - cvarGroupStrings[qcvarGroup] += it.first.c_str() + eq + QString::number(val) + '\n'; - } - } - else - { - cvarGroupStrings[qcvarGroup] += it.first.c_str() + eq + AZStd::any_cast(it.second.fileVals[cfgFileIndex].editedValue).c_str() + '\n'; - } - } - - if (!saveOut) - { - saveOut = CheckCVarStatesForDiff(&it, cfgFileIndex, EDITED_OVERWRITTEN_COMPARE); - } - } - - // Adding the project name to the path so that the file is created there if it doesn't already exist - // as we don't want to modify the version in Engine/config. - AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath(); - projectPath /= SETTINGS_FILE_PATH.toUtf8().constData(); - QString settingsPath = QString::fromUtf8(projectPath.c_str(), aznumeric_cast(projectPath.Native().size())); - - QString settingsFile = settingsPath + m_cfgFiles[m_currentPlatform][cfgFileIndex].c_str(); - - // Check if current settings differ from existing cfg - if (saveOut) - { - // Adding any dirty cvars not equal to sys_spec_full to command list - for (auto& it : cvarGroupStrings) - { - commandList += it; - } - - if (CFileUtil::OverwriteFile(settingsFile.toStdString().c_str())) - { - if (!CFileUtil::CreateDirectory(settingsPath.toStdString().c_str())) - { - QMessageBox::warning(this, "Warning", "Could not create the directory for file \"" + settingsFile + "\". Failed to apply Graphics Setting.", - QMessageBox::Ok); - continue; - } - - QByteArray dataArray = commandList.toUtf8().data(); - - QFile file(settingsFile); - if (!file.open(QIODevice::WriteOnly) || file.write(dataArray) != dataArray.size()) - { - QMessageBox::warning(this, "Warning", "Could not write settings to file \"" + settingsFile + ". Failed to apply Graphics Setting.", - QMessageBox::Ok); - file.close(); - continue; - } - - successFiles.push_back(settingsFile); - - // Update platform cvars to reflect new values - for (auto& it : m_cVarTracker) - { - it.second.fileVals[cfgFileIndex].overwrittenValue = it.second.fileVals[cfgFileIndex].editedValue; - } - - file.close(); - } - else - { - QMessageBox::warning(this, "Warning", "Could not check out or make file writable: \"" + settingsFile + "\". Failed to apply Graphics Setting.", - QMessageBox::Ok); - } - } - else - { - nochangeFiles.push_back(settingsFile); - } - } - - // Print list of files which had no changes made - if (nochangeFiles.size() > 0) - { - QString message = "No changes have been made to the following files:\n"; - for (int i = 0; i < nochangeFiles.size(); ++i) - { - message += nochangeFiles[i] + "\n"; - } - QMessageBox::information(this, "Log", message, QMessageBox::Ok); - } - - // Print list of files which were successfully saved - if (successFiles.size() > 0) - { - QString message = "Updated the graphics setting correctly for the following files:\n"; - for (int i = 0; i < successFiles.size(); ++i) - { - message += successFiles[i] + "\n"; - } - QMessageBox::information(this, "Log", message, QMessageBox::Ok); - } - - // if we saved all of the files that we needed to then disable the save button again - if (nochangeFiles.size() + successFiles.size() == m_cfgFiles[m_currentPlatform].size()) - { - m_dirtyCVarCount = 0; - m_ui->m_applyButton->setEnabled(false); - } -} - -void GraphicsSettingsDialog::SetCollapsed(const QModelIndex& index, bool flags) -{ - QStandardItem* item = m_graphicsSettingsModel->itemFromIndex(index); - - for (auto& collapseIterator : m_uiCollapseGroup) - { - if (collapseIterator->m_groupRow == item) - { - collapseIterator->m_isCollapsed = flags; - break; - } - } -} - -///////////////////////////////////////////////////////////////////////// -// Collapse Group -GraphicsSettingsDialog::CollapseGroup::CollapseGroup(QTreeView* treeView) - : m_treeView(treeView) - , m_isCollapsed(true) -{ -} - -void GraphicsSettingsDialog::CollapseGroup::ToggleCollapsed() -{ - m_isCollapsed = !m_isCollapsed; - const QModelIndex index = m_groupRow->index(); - if (m_isCollapsed) - { - m_treeView->collapse(index); - } - else - { - m_treeView->expand(index); - } -} - -/////////////////////////////////////////////////////////////////// -// ParameterWidget -GraphicsSettingsDialog::ParameterWidget::ParameterWidget(QWidget* widget, QString parameterName) - : m_widget(widget) - , m_parameterName(parameterName) -{ - m_widget->setToolTip(GetToolTip()); -} - -QString GraphicsSettingsDialog::ParameterWidget::GetToolTip() const -{ - if (!m_parameterName.isEmpty()) - { - QString tooltipText = QString(PARAMETER_TOOLTIP).arg(m_parameterName); - return tooltipText; - } - return ""; -} - -GraphicsSettingsTreeView::GraphicsSettingsTreeView(QWidget* parent) - : QTreeView(parent) -{ -} - -GraphicsSettingsHeaderView::GraphicsSettingsHeaderView(GraphicsSettingsDialog* dialog, Qt::Orientation orientation, QWidget* parent) - : QHeaderView(orientation, parent) - , m_dialog(dialog) -{ - setDefaultAlignment(Qt::AlignLeft); -} - -bool GraphicsSettingsHeaderView::event(QEvent* e) -{ - if (m_dialog->IsCustom()) - { - GraphicsSettingsTreeView* treeView = qobject_cast(parent()); - if (treeView) - { - switch (e->type()) - { - case QEvent::Enter: - m_index = logicalIndexAt(static_cast(e)->pos()); - if (m_index > 0) - { - treeView->setSortingEnabled(true); - treeView->sortByColumn(m_index, Qt::AscendingOrder); - } - break; - case QEvent::Leave: - treeView->setSortingEnabled(false); - break; - } - } - } - return QHeaderView::event(e); -} - -void GraphicsSettingsHeaderView::mouseReleaseEvent(QMouseEvent* e) -{ - AZ_UNUSED(e); - if (QMessageBox::question( - this, QObject::tr("Unload Resource"), - QObject::tr("Are you sure you want to unload the resource?"), - QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Yes) - { - m_dialog->UnloadCustomSpec(m_index - 1); - } - -} - -void GraphicsSettingsHeaderView::mouseMoveEvent(QMouseEvent* e) -{ - AZ_UNUSED(e); - if (m_dialog->IsCustom()) - { - GraphicsSettingsTreeView* treeView = qobject_cast(parent()); - int index = logicalIndexAt(e->pos()); - if (index != m_index) - { - m_index = index; - if (m_index > 0) - { - treeView->setSortingEnabled(true); - treeView->sortByColumn(m_index, Qt::AscendingOrder); - } - else - { - treeView->setSortingEnabled(false); - } - } - } -} - -GraphicsSettingsModel::GraphicsSettingsModel(QObject* parent) - : QStandardItemModel(parent) -{ -} - -Qt::ItemFlags GraphicsSettingsModel::flags(const QModelIndex& index) const -{ - Qt::ItemFlags flags = Qt::NoItemFlags; - - if (index.column() == 0) - { - flags |= Qt::ItemIsSelectable | Qt::ItemIsEnabled; - } - return flags; -} - -#include diff --git a/Code/Editor/GraphicsSettingsDialog.h b/Code/Editor/GraphicsSettingsDialog.h deleted file mode 100644 index 66a498cd10..0000000000 --- a/Code/Editor/GraphicsSettingsDialog.h +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#include - -#include -#include -#include - -#include -#endif - -class QGridLayout; -class QLabel; - -namespace Ui -{ - class GraphicsSettingsDialog; -} - -// Description: -// Status of cvar for a specifc platform and spec level -// editedValue - current setting within Graphics Settings Dialog box -// overwrittenValue - original setting from platform config file (set to originalValue if not found) -// originalValue - original settings from sys_spec config file index - -struct CVarFileStatus -{ - AZStd::any editedValue; - AZStd::any overwrittenValue; - AZStd::any originalValue; - CVarFileStatus(AZStd::any edit, AZStd::any over, AZStd::any orig) : editedValue(edit), overwrittenValue(over), originalValue(orig) {} -}; - -// Description: -// Status of specific cvar for Editor mapping -// type - CVAR_INT / CVAR_FLOAT / CVAR_STRING -// cvarGroup - source of cvar (sys_spec_particles, sys_spec_physics, etc.) or "miscellaneous" if only specified in platform config file -// fileVals = CVarFileStatus for each spec level of a specific platform - -struct CVarInfo -{ - int type; - AZStd::string cvarGroup; - AZStd::vector fileVals; -}; - -enum class GraphicsSettings -{ - GameEffects, - Light, - ObjectDetail, - Particles, - Physics, - PostProcessing, - Quality, - Shading, - Shadows, - Sound, - Texture, - TextureResolution, - VolumetricEffects, - Water, - Miscellaneous, - numSettings -}; - -class GraphicsSettingsHeaderView; - -class GraphicsSettingsTreeView - : public QTreeView -{ - Q_OBJECT - -public: - GraphicsSettingsTreeView(QWidget* parent = nullptr); - -}; - -class GraphicsSettingsModel - : public QStandardItemModel -{ - Q_OBJECT - -public: - explicit GraphicsSettingsModel(QObject* parent = 0); - - Qt::ItemFlags flags(const QModelIndex& index) const override; -}; - -class GraphicsSettingsDialog - : public QDialog, - public ILoadConfigurationEntrySink -{ - Q_OBJECT - -public: - - explicit GraphicsSettingsDialog(QWidget* parent = nullptr); - virtual ~GraphicsSettingsDialog(); - - bool IsCustom(void) { return m_showCustomSpec; } - void UnloadCustomSpec(int specLevel); - - // ILoadConfigurationEntrySink - void OnLoadConfigurationEntry(const char* szKey, const char* szValue, const char* szGroup) override; - -public slots: - //Accept and reject - void reject() override; - void accept() override; - -private slots: - //Update UIs - void PlatformChanged(const QString& platform); - bool CVarChanged(AZStd::any val, const char* cvarName, int specLevel); - void CVarChanged(int i); - void CVarChanged(double d); - void CVarChanged(const QString& s); - -private: - - // The struct ParameterWidget is used to store the parameter widget - // m_parameterName will be the name of the parameter the widget represent. - struct ParameterWidget - { - ParameterWidget(QWidget* widget, QString parameterName = ""); - - QString GetToolTip() const; - - const char* PARAMETER_TOOLTIP = "The variable will update render parameter \"%1\"."; - QWidget* m_widget; - QString m_parameterName; - }; - - struct CollapseGroup - { - QString m_groupName; - QStandardItem* m_groupRow; - QTreeView* m_treeView; - bool m_isCollapsed; - - CollapseGroup(QTreeView* treeView); - - void ToggleCollapsed(); - }; - - void OpenCustomSpecDialog(); - void ApplyCustomSpec(const QString& customFilePath); - bool IsCustomSpecAlreadyLoaded(const AZStd::string& filename) const; - void SetSettingsTree(int numColumns); - void SetCollapsed(const QModelIndex& index, bool flag); - - enum CVarStateComparison - { - EDITED_OVERWRITTEN_COMPARE = 1, - EDITED_ORIGINAL_COMPARE = 2, - OVERWRITTEN_ORIGINAL_COMPARE = 3, - - END_CVARSTATE_COMPARE, - }; - - bool CheckCVarStatesForDiff(AZStd::pair* it, int cfgFileIndex, CVarStateComparison cmp); - - // Save out settings into project-level cfg files - void SaveSystemSettings(); - - // Load in project-level cfg files for current platform - void LoadPlatformConfigurations(); - // Build UI column for spec level of current platform - void BuildColumn(int specLevel); - // Initial UI building - void BuildUI(); - // Cleaning out UI before loading new platform information - void CleanUI(); - // Shows/hides custom spec option - void ShowCustomSpecOption(bool show); - // Shows/hides category labels and dropdowns - void ShowCategories(bool show); - // Warns about unsaved changes (returns true if accepted) - bool SendUnsavedChangesWarning(bool cancel); - - void LoadCVarGroupDirectory(const AZStd::string& path); - - ///////////////////////////////////////////// - // UI help functions - - // Setup collapsed buttons - void SetCollapsedLayout(const QString& groupName, QStandardItem* groupItem); - // Sets the platform entry index for the given platform - void SetPlatformEntry(ESystemConfigPlatform platform); - // Gets the platform enum given the platform name - ESystemConfigPlatform GetConfigPlatformFromName(const AZStd::string& platformName); - - //////////////////////////////////////////// - // Members - - // Qt values - const int INPUT_MIN_WIDTH = 100; - const int INPUT_MIN_HEIGHT = 20; - const int INPUT_ROW_SPAN = 1; - const int INPUT_COLUMN_SPAN = 1; - const int CVAR_ROW_OFFSET = 2; - const int CVAR_VALUE_COLUMN_OFFSET = 1; - const int PLATFORM_LABEL_ROW = 1; - const int CVAR_LABEL_COLUMN = 1; - - // Tool tips - const QString SETTINGS_FILE_PATH = "Config/spec/"; - const char* CFG_FILEFILTER = "Cfg File(*.cfg);;All files(*)"; - - const int m_numSpecLevels = 4; - - bool m_showCustomSpec; - bool m_showCategories; - GraphicsSettingsModel* m_graphicsSettingsModel; - GraphicsSettingsHeaderView* m_headerView; - int m_numColumns{ 0 }; - - const char* m_cvarGroupsFolder = "Config/CVarGroups"; - - QScopedPointer m_ui; - - QVector m_uiCollapseGroup; - - QVector m_parameterWidgets; - - AZStd::string m_currentConfigFilename; - size_t m_currentSpecIndex; - - // cvar name --> pair(type, CVarStatus for each file) - AZStd::unordered_map m_cVarTracker; - - AZStd::unordered_map > m_cfgFiles; - - AZStd::vector > m_platformStrings; - - struct CVarGroupInfo - { - QVector m_platformLabels; - QVector m_cvarLabels; - QVector m_cvarSpinBoxes; - QVector m_cvarDoubleSpinBoxes; - QVector m_cvarLineEdits; - QVector m_specFileArea; - QVector m_widgetInsertOrder; - QStandardItem* m_treeRowItem; - int m_currentRow; - }; - - AZStd::unordered_map m_cvarGroupData; - AZStd::vector m_cvarGroupOrder; - - ESystemConfigPlatform m_currentPlatform; - - int m_dirtyCVarCount; -}; - -class GraphicsSettingsHeaderView - : public QHeaderView -{ - Q_OBJECT -public: - GraphicsSettingsHeaderView(GraphicsSettingsDialog* dialog, Qt::Orientation orientation, QWidget* parent = nullptr); - -private: - bool event(QEvent* e) override; - void mouseMoveEvent(QMouseEvent* e) override; - void mouseReleaseEvent(QMouseEvent* e) override; - - GraphicsSettingsDialog* m_dialog; - int m_index{ -1 }; -}; - - diff --git a/Code/Editor/MainWindow.cpp b/Code/Editor/MainWindow.cpp index 261fab48d1..c7e32fb82a 100644 --- a/Code/Editor/MainWindow.cpp +++ b/Code/Editor/MainWindow.cpp @@ -41,6 +41,7 @@ AZ_POP_DISABLE_WARNING // AzToolsFramework #include +#include #include #include #include @@ -93,6 +94,8 @@ AZ_POP_DISABLE_WARNING #include "AssetEditor/AssetEditorWindow.h" #include "ActionManager.h" +#include + using namespace AZ; using namespace AzQtComponents; using namespace AzToolsFramework; @@ -489,6 +492,16 @@ void MainWindow::Initialize() ActionOverrideRequestBus::Event( GetEntityContextId(), &ActionOverrideRequests::SetupActionOverrideHandler, this); + if (auto imGuiManager = AZ::Interface::Get()) + { + auto handleImGuiStateChangeFn = [](bool enabled) + { + EditorWindowUIRequestBus::Broadcast(&EditorWindowUIRequests::SetEditorUiEnabled, enabled); + }; + m_handleImGuiStateChangeHandler = ImGui::IImGuiManager::ImGuiSetEnabledEvent::Handler(handleImGuiStateChangeFn); + imGuiManager->ConnectImGuiSetEnabledChangedHandler(m_handleImGuiStateChangeHandler); + } + AzToolsFramework::EditorEventsBus::Broadcast(&AzToolsFramework::EditorEvents::NotifyMainWindowInitialized, this); } @@ -674,49 +687,6 @@ void MainWindow::InitActions() am->AddAction(ID_FILE_PROJECT_MANAGER_SETTINGS, tr("Edit Project Settings...")); am->AddAction(ID_FILE_PROJECT_MANAGER_NEW, tr("New Project...")); am->AddAction(ID_FILE_PROJECT_MANAGER_OPEN, tr("Open Project...")); - am->AddAction(ID_GAME_PC_ENABLEVERYHIGHSPEC, tr("Very High")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_PC_ENABLEHIGHSPEC, tr("High")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_PC_ENABLEMEDIUMSPEC, tr("Medium")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_PC_ENABLELOWSPEC, tr("Low")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_OSXMETAL_ENABLEVERYHIGHSPEC, tr("Very High")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_OSXMETAL_ENABLEHIGHSPEC, tr("High")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_OSXMETAL_ENABLEMEDIUMSPEC, tr("Medium")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_OSXMETAL_ENABLELOWSPEC, tr("Low")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_ANDROID_ENABLEVERYHIGHSPEC, tr("Very High")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_ANDROID_ENABLEHIGHSPEC, tr("High")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_ANDROID_ENABLEMEDIUMSPEC, tr("Medium")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_ANDROID_ENABLELOWSPEC, tr("Low")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_IOS_ENABLEVERYHIGHSPEC, tr("Very High")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_IOS_ENABLEHIGHSPEC, tr("High")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_IOS_ENABLEMEDIUMSPEC, tr("Medium")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); - am->AddAction(ID_GAME_IOS_ENABLELOWSPEC, tr("Low")).SetCheckable(true) - .RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateGameSpec); -#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS) -#if defined(TOOLS_SUPPORT_JASPER) -#include AZ_RESTRICTED_FILE_EXPLICIT(MainWindow_cpp, jasper) -#endif -#if defined(TOOLS_SUPPORT_PROVO) -#include AZ_RESTRICTED_FILE_EXPLICIT(MainWindow_cpp, provo) -#endif -#if defined(TOOLS_SUPPORT_SALEM) -#include AZ_RESTRICTED_FILE_EXPLICIT(MainWindow_cpp, salem) -#endif -#endif am->AddAction(ID_TOOLS_CUSTOMIZEKEYBOARD, tr("Customize &Keyboard...")) .Connect(&QAction::triggered, this, &MainWindow::ShowKeyboardCustomization); am->AddAction(ID_TOOLS_EXPORT_SHORTCUTS, tr("&Export Keyboard Settings...")) @@ -724,7 +694,6 @@ void MainWindow::InitActions() am->AddAction(ID_TOOLS_IMPORT_SHORTCUTS, tr("&Import Keyboard Settings...")) .Connect(&QAction::triggered, this, &MainWindow::ImportKeyboardShortcuts); am->AddAction(ID_TOOLS_PREFERENCES, tr("Global Preferences...")); - am->AddAction(ID_GRAPHICS_SETTINGS, tr("&Graphics Settings...")); for (int i = ID_FILE_MRU_FIRST; i <= ID_FILE_MRU_LAST; ++i) { diff --git a/Code/Editor/MainWindow.h b/Code/Editor/MainWindow.h index 34b121537d..99af2ea326 100644 --- a/Code/Editor/MainWindow.h +++ b/Code/Editor/MainWindow.h @@ -249,6 +249,7 @@ private: QPointer m_toolbarCustomizationDialog; QScopedPointer m_sourceControlNotifHandler; + AZ::Event::Handler m_handleImGuiStateChangeHandler; AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING static MainWindow* m_instance; diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt b/Code/Editor/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt index 4744b4e174..5aab2a2056 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt @@ -27,6 +27,7 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE 3rdParty::Qt::Core + 3rdParty::Qt::Widgets AZ::AzCore AZ::AzToolsFramework Legacy::CryCommon diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerDisplayOptionsMenu.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerDisplayOptionsMenu.cpp index c1af8d76d7..a6c1ed6598 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerDisplayOptionsMenu.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerDisplayOptionsMenu.cpp @@ -66,3 +66,5 @@ namespace EntityOutliner emit OnOptionToggled(DisplayOption::AutoExpand, checked); } } + +#include diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerSortFilterProxyModel.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerSortFilterProxyModel.cpp index 660ea137cf..89cd361fb6 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerSortFilterProxyModel.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerSortFilterProxyModel.cpp @@ -32,7 +32,24 @@ bool OutlinerSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelI bool OutlinerSortFilterProxyModel::lessThan(const QModelIndex& leftIndex, const QModelIndex& rightIndex) const { - return sourceModel()->data(leftIndex).toString() < sourceModel()->data(rightIndex).toString(); + if (leftIndex.isValid() && rightIndex.isValid()) + { + QVariant leftData = sourceModel()->data(leftIndex); + QVariant rightData = sourceModel()->data(rightIndex); + + // make sure to compare the correct data types for sorting the current column + AZ_Assert(leftData.type() == rightData.type(), "OutlinerSortFilterProxyModel::lessThan types do not agree!"); + if (static_cast(leftData.type()) == QMetaType::QString) + { + return leftData.toString() < rightData.toString(); + } + else if (static_cast(leftData.type()) == QMetaType::ULongLong) + { + return leftData.toULongLong() < rightData.toULongLong(); + } + AZ_Error("Editor", false, "Error! Unhandled type \"%s\" in OutlinerSortFilterProxyModel::lessThan", leftData.typeName()); + } + return false; } void OutlinerSortFilterProxyModel::sort(int /*column*/, Qt::SortOrder /*order*/) diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp index d69480b169..02dabb8b20 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.cpp @@ -269,10 +269,12 @@ OutlinerWidget::OutlinerWidget(QWidget* pParent, Qt::WindowFlags flags) AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusConnect( AzToolsFramework::GetEntityContextId()); AzToolsFramework::EditorEntityInfoNotificationBus::Handler::BusConnect(); + AzToolsFramework::EditorWindowUIRequestBus::Handler::BusConnect(); } OutlinerWidget::~OutlinerWidget() { + AzToolsFramework::EditorWindowUIRequestBus::Handler::BusDisconnect(); AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorEntityInfoNotificationBus::Handler::BusDisconnect(); AzToolsFramework::EditorPickModeNotificationBus::Handler::BusDisconnect(); @@ -1321,16 +1323,25 @@ static void SetEntityOutlinerState(Ui::OutlinerWidgetUI* entityOutlinerUi, const AzQtComponents::SetWidgetInteractEnabled(entityOutlinerUi->m_searchWidget, on); } +void OutlinerWidget::EnableUi(bool enable) +{ + SetEntityOutlinerState(m_gui, enable); + setEnabled(enable); +} + +void OutlinerWidget::SetEditorUiEnabled(bool enable) +{ + EnableUi(enable); +} + void OutlinerWidget::EnteredComponentMode([[maybe_unused]] const AZStd::vector& componentModeTypes) { - SetEntityOutlinerState(m_gui, false); - setEnabled(false); + EnableUi(false); } void OutlinerWidget::LeftComponentMode([[maybe_unused]] const AZStd::vector& componentModeTypes) { - setEnabled(true); - SetEntityOutlinerState(m_gui, true); + EnableUi(true); } void OutlinerWidget::OnSliceInstantiated(const AZ::Data::AssetId& /*sliceAssetId*/, AZ::SliceComponent::SliceInstanceAddress& sliceAddress, const AzFramework::SliceInstantiationTicket& /*ticket*/) diff --git a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.hxx b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.hxx index 75991424bb..aff305e0fe 100644 --- a/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.hxx +++ b/Code/Editor/Plugins/ComponentEntityEditorPlugin/UI/Outliner/OutlinerWidget.hxx @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -57,6 +58,7 @@ class OutlinerWidget , private AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler , private AzToolsFramework::EditorEntityInfoNotificationBus::Handler , private AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler + , private AzToolsFramework::EditorWindowUIRequestBus::Handler { Q_OBJECT; public: @@ -106,6 +108,9 @@ private: void EnteredComponentMode(const AZStd::vector& componentModeTypes) override; void LeftComponentMode(const AZStd::vector& componentModeTypes) override; + // EditorWindowUIRequestBus overrides + void SetEditorUiEnabled(bool enable) override; + // Build a selection object from the given entities. Entities already in the Widget's selection buffers are ignored. template QItemSelection BuildSelectionFromEntities(const EntityIdCollection& entityIds); @@ -171,6 +176,7 @@ private: AZ::EntityId GetEntityIdFromIndex(const QModelIndex& index) const; QModelIndex GetIndexFromEntityId(const AZ::EntityId& entityId) const; void ExtractEntityIdsFromSelection(const QItemSelection& selection, AzToolsFramework::EntityIdList& entityIdList) const; + void EnableUi(bool enable); // AzToolsFramework::OutlinerModelNotificationBus::Handler // Receive notification from the outliner model that we should scroll diff --git a/Code/Editor/Plugins/FFMPEGPlugin/CMakeLists.txt b/Code/Editor/Plugins/FFMPEGPlugin/CMakeLists.txt index 342151f24a..909ec193f3 100644 --- a/Code/Editor/Plugins/FFMPEGPlugin/CMakeLists.txt +++ b/Code/Editor/Plugins/FFMPEGPlugin/CMakeLists.txt @@ -23,6 +23,7 @@ ly_add_target( . BUILD_DEPENDENCIES PRIVATE + 3rdParty::Qt::Core AZ::AzCore Legacy::CryCommon Legacy::EditorLib diff --git a/Code/Editor/Plugins/FFMPEGPlugin/FFMPEGPlugin_precompiled.h b/Code/Editor/Plugins/FFMPEGPlugin/FFMPEGPlugin_precompiled.h index 3b015dd9a5..33ca3390f1 100644 --- a/Code/Editor/Plugins/FFMPEGPlugin/FFMPEGPlugin_precompiled.h +++ b/Code/Editor/Plugins/FFMPEGPlugin/FFMPEGPlugin_precompiled.h @@ -17,19 +17,8 @@ ///////////////////////////////////////////////////////////////////////////// #include - -///////////////////////////////////////////////////////////////////////////// -// STL -///////////////////////////////////////////////////////////////////////////// -#include -#include -#include -#include -#include - ///////////////////////////////////////////////////////////////////////////// // CRY Stuff //////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// #include -#include "Util/EditorUtils.h" #include "EditorCoreAPI.h" diff --git a/Code/Editor/Plugins/PerforcePlugin/CMakeLists.txt b/Code/Editor/Plugins/PerforcePlugin/CMakeLists.txt index 15a1147166..bd4661fa0f 100644 --- a/Code/Editor/Plugins/PerforcePlugin/CMakeLists.txt +++ b/Code/Editor/Plugins/PerforcePlugin/CMakeLists.txt @@ -31,6 +31,8 @@ ly_add_target( . BUILD_DEPENDENCIES PRIVATE + 3rdParty::Qt::Core + 3rdParty::Qt::Widgets AZ::AzCore Legacy::CryCommon Legacy::EditorLib diff --git a/Code/Editor/QtViewPaneManager.cpp b/Code/Editor/QtViewPaneManager.cpp index 35b2160a1f..9f2b9f9cf8 100644 --- a/Code/Editor/QtViewPaneManager.cpp +++ b/Code/Editor/QtViewPaneManager.cpp @@ -525,6 +525,7 @@ QtViewPaneManager::QtViewPaneManager(QObject* parent) // view pane manager is interested when we enter/exit ComponentMode m_componentModeNotifications.BusConnect(AzToolsFramework::GetEntityContextId()); + m_windowRequest.BusConnect(); m_componentModeNotifications.SetEnteredComponentModeFunc( [this](const AZStd::vector& /*componentModeTypes*/) @@ -545,10 +546,23 @@ QtViewPaneManager::QtViewPaneManager(QObject* parent) AzQtComponents::SetWidgetInteractEnabled(widget, on); }); }); + + m_windowRequest.SetEnableEditorUiFunc( + [this](bool enable) + { + // gray out panels when entering ImGui mode + SetDefaultActionsEnabled( + enable, m_registeredPanes, + [](QWidget* widget, bool on) + { + AzQtComponents::SetWidgetInteractEnabled(widget, on); + }); + }); } QtViewPaneManager::~QtViewPaneManager() { + m_windowRequest.BusDisconnect(); m_componentModeNotifications.BusDisconnect(); } diff --git a/Code/Editor/QtViewPaneManager.h b/Code/Editor/QtViewPaneManager.h index aa382c41c0..2b3412aad6 100644 --- a/Code/Editor/QtViewPaneManager.h +++ b/Code/Editor/QtViewPaneManager.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -249,8 +250,12 @@ private: QPointer m_advancedDockManager; using EditorComponentModeNotificationBusImpl = AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBusImpl; - EditorComponentModeNotificationBusImpl m_componentModeNotifications; /**< Helper for EditorComponentModeNotificationBus so - * QtViewPaneManager does not need to inherit directly from it. */ + EditorComponentModeNotificationBusImpl m_componentModeNotifications; //!< Helper for EditorComponentModeNotificationBus so + //!< QtViewPaneManager does not need to inherit directly from it. */ + + using EditorWindowRequestBusImpl = AzToolsFramework::EditorWindowRequestBusImpl; + EditorWindowRequestBusImpl m_windowRequest; //!< Helper for EditorWindowRequestBus so + //!< QtViewPaneManager does not need to inherit directly from it. */ AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING }; diff --git a/Code/Editor/RenderViewport.cpp b/Code/Editor/RenderViewport.cpp index 8d6bcf021b..bb269ba298 100644 --- a/Code/Editor/RenderViewport.cpp +++ b/Code/Editor/RenderViewport.cpp @@ -4083,7 +4083,12 @@ void CRenderViewport::RestoreViewportAfterGameMode() { Matrix34 preGameModeViewTM = m_preGameModeViewTM; - QString text = QString("You are exiting Game Mode. Would you like to restore the camera in the viewport to where it was before you entered Game Mode?

This option can always be changed in the General Preferences tab of the Editor Settings, by toggling the \"%1\" option.

").arg(EditorPreferencesGeneralRestoreViewportCameraSettingName); + QString text = + QString( + tr("When leaving \" Game Mode \" the engine will automatically restore your camera position to the default position before you " + "had entered Game mode.

If you dislike this setting you can always change this anytime in the global " + "preferences.

")) + .arg(EditorPreferencesGeneralRestoreViewportCameraSettingName); QString restoreOnExitGameModePopupDisabledRegKey("Editor/AutoHide/ViewportCameraRestoreOnExitGameMode"); // Read the popup disabled registry value @@ -4098,6 +4103,7 @@ void CRenderViewport::RestoreViewportAfterGameMode() messageBox.setDefaultButton(QMessageBox::Yes); QCheckBox* checkBox = new QCheckBox(QStringLiteral("Do not show this message again")); + checkBox->setChecked(true); messageBox.setCheckBox(checkBox); // Unconstrain the system cursor and make it visible before we show the dialog box, otherwise the user can't see the cursor. diff --git a/Code/Editor/Resource.h b/Code/Editor/Resource.h index 22bbece700..3ae1024550 100644 --- a/Code/Editor/Resource.h +++ b/Code/Editor/Resource.h @@ -187,7 +187,6 @@ #define ID_SWITCHCAMERA_SEQUENCECAMERA 33701 #define ID_SWITCHCAMERA_SELECTEDCAMERA 33702 #define ID_TV_RECORD_AUTO 33703 -#define ID_GRAPHICS_SETTINGS 33705 #define ID_VIEW_OPENVIEWPANE 33709 #define ID_VIEW_OPENPANE_FIRST 33712 #define ID_VIEW_OPENPANE_LAST 33811 @@ -219,10 +218,6 @@ #define ID_SPLINE_SNAP_GRID_X 33933 #define ID_SPLINE_SNAP_GRID_Y 33934 #define ID_FREEZE_TANGENTS 33935 -#define ID_GAME_PC_ENABLELOWSPEC 33960 -#define ID_GAME_PC_ENABLEMEDIUMSPEC 33961 -#define ID_GAME_PC_ENABLEHIGHSPEC 33962 -#define ID_GAME_PC_ENABLEVERYHIGHSPEC 33963 #define ID_PANEL_VEG_CREATE_SEL 33990 #define ID_TOOLS_UPDATEPROCEDURALVEGETATION 33999 #define ID_DISPLAY_GOTOPOSITION 34004 @@ -287,14 +282,6 @@ #define ID_CLEAR_REGISTRY 34470 #define ID_SOUND_STOPALLSOUNDS 34476 #define ID_AUDIO_REFRESH_AUDIO_SYSTEM 34477 -#define ID_GAME_ANDROID_ENABLELOWSPEC 34490 -#define ID_GAME_ANDROID_ENABLEMEDIUMSPEC 34491 -#define ID_GAME_ANDROID_ENABLEHIGHSPEC 34492 -#define ID_GAME_ANDROID_ENABLEVERYHIGHSPEC 34493 -#define ID_GAME_IOS_ENABLELOWSPEC 34494 -#define ID_GAME_IOS_ENABLEMEDIUMSPEC 34495 -#define ID_GAME_IOS_ENABLEHIGHSPEC 34496 -#define ID_GAME_IOS_ENABLEVERYHIGHSPEC 34497 #define ID_OPEN_AUDIO_CONTROLS_BROWSER 34580 #define ID_CREATE_GLOBAL_FG_MODULE_FROM_SELECTION 35076 #define ID_CREATE_LEVEL_FG_MODULE_FROM_SELECTION 35077 @@ -324,19 +311,6 @@ #define ID_DOCUMENTATION_FEEDBACK 36043 #define ID_OPEN_SUBSTANCE_EDITOR 36060 #define ID_IMPORT_ASSET 36069 -#define ID_GAME_PROVO_ENABLELOWSPEC 34603 -#define ID_GAME_PROVO_ENABLEMEDIUMSPEC 34604 -#define ID_GAME_PROVO_ENABLEHIGHSPEC 34605 -#define ID_GAME_OSXMETAL_ENABLELOWSPEC 34606 -#define ID_GAME_OSXMETAL_ENABLEMEDIUMSPEC 34607 -#define ID_GAME_OSXMETAL_ENABLEHIGHSPEC 34608 -#define ID_GAME_OSXMETAL_ENABLEVERYHIGHSPEC 34609 -#define ID_GAME_SALEM_ENABLELOWSPEC 34610 -#define ID_GAME_SALEM_ENABLEMEDIUMSPEC 34611 -#define ID_GAME_SALEM_ENABLEHIGHSPEC 34612 -#define ID_GAME_JASPER_ENABLELOWSPEC 34613 -#define ID_GAME_JASPER_ENABLEMEDIUMSPEC 34614 -#define ID_GAME_JASPER_ENABLEHIGHSPEC 34615 #define ID_FILE_RESAVESLICES 36210 #define FIRST_QT_ACTION 50000 #define ID_VIEW_CONSOLEWINDOW 50001 diff --git a/Code/Editor/Style/GraphicsSettingsDialog.qss b/Code/Editor/Style/GraphicsSettingsDialog.qss deleted file mode 100644 index 3af8c4c05b..0000000000 --- a/Code/Editor/Style/GraphicsSettingsDialog.qss +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#GraphicsSettingsDialog QHeaderView::section -{ - background: #2D2D2D; -} - -#GraphicsSettingsDialog QHeaderView::down-arrow -{ - width: 14px; - height: 14px; - image: url(:/Gallery/Delete.svg); -} - -#GraphicsSettingsDialog QHeaderView::up-arrow -{ - width: 14px; - height: 14px; - image: url(:/Gallery/Delete.svg); -} diff --git a/Code/Editor/Style/resources.qrc b/Code/Editor/Style/resources.qrc index aec7e2cf68..24682d2be3 100644 --- a/Code/Editor/Style/resources.qrc +++ b/Code/Editor/Style/resources.qrc @@ -3,6 +3,5 @@ Editor.qss EditorPreferencesDialog.qss LayoutConfigDialog.qss - GraphicsSettingsDialog.qss diff --git a/Code/Editor/WelcomeScreen/WelcomeScreenDialog.cpp b/Code/Editor/WelcomeScreen/WelcomeScreenDialog.cpp index f9560aef55..49d9c58159 100644 --- a/Code/Editor/WelcomeScreen/WelcomeScreenDialog.cpp +++ b/Code/Editor/WelcomeScreen/WelcomeScreenDialog.cpp @@ -40,10 +40,6 @@ #include "CryEdit.h" #include "LevelFileDialog.h" -// NewsShared -#include // for News::ResourceManifest -#include // for News::ArticleViewContainer - AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING #include AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING diff --git a/Code/Editor/WelcomeScreen/WelcomeScreenDialog.h b/Code/Editor/WelcomeScreen/WelcomeScreenDialog.h index 4338a8250f..39c0ad6316 100644 --- a/Code/Editor/WelcomeScreen/WelcomeScreenDialog.h +++ b/Code/Editor/WelcomeScreen/WelcomeScreenDialog.h @@ -8,8 +8,6 @@ #if !defined(Q_MOC_RUN) #include -#include "NewsShared/LogType.h" -#include "NewsShared/ErrorCodes.h" #endif namespace News { @@ -62,9 +60,6 @@ private: void OnRecentLevelTableItemClicked(const QModelIndex& index); void OnCloseBtnClicked(bool checked); - void SyncFail(News::ErrorCode error); - void SyncSuccess(); - private Q_SLOTS: void previewAreaScrolled(); }; diff --git a/Code/Editor/editor_lib_files.cmake b/Code/Editor/editor_lib_files.cmake index fc1694240e..3181474b35 100644 --- a/Code/Editor/editor_lib_files.cmake +++ b/Code/Editor/editor_lib_files.cmake @@ -583,9 +583,6 @@ set(FILES SettingsManager.h SettingsManagerDialog.h SettingsManagerDialog.ui - GraphicsSettingsDialog.h - GraphicsSettingsDialog.cpp - graphicssettingsdialog.ui AboutDialog.cpp ErrorReportTableModel.h ErrorReportTableModel.cpp diff --git a/Code/Editor/graphicssettingsdialog.ui b/Code/Editor/graphicssettingsdialog.ui deleted file mode 100644 index ca8770e9e3..0000000000 --- a/Code/Editor/graphicssettingsdialog.ui +++ /dev/null @@ -1,270 +0,0 @@ - - - GraphicsSettingsDialog - - - - 0 - 0 - 1292 - 565 - - - - - 0 - 0 - - - - - 800 - 400 - - - - - 16777215 - 16777215 - - - - Graphics Settings - - - - - - - 0 - - - 6 - - - - - - 0 - 0 - - - - - 0 - 20 - - - - - 16777215 - 20 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - 100 - 0 - - - - - 16777215 - 20 - - - - Add Resource - - - - - - - - 0 - 0 - - - - - 60 - 20 - - - - Platform - - - Qt::AlignCenter - - - - - - - - 13 - 0 - - - - Qt::Vertical - - - - - - - - - - Qt::Horizontal - - - - - - - - 0 - 0 - - - - true - - - - - 0 - 0 - 1272 - 452 - - - - - 0 - 0 - - - - - - - - 0 - 0 - - - - 8 - - - false - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - background-color: rgb(233, 118, 17); - - - Save - - - - - - - - 0 - 0 - - - - Cancel - - - - - - - - - Qt::Horizontal - - - - - line - m_scrollArea - line_2 - widget - - - - GraphicsSettingsTreeView - QTreeView -
GraphicsSettingsDialog.h
-
-
- - m_cancelButton - m_applyButton - m_scrollArea - - - -
diff --git a/Code/Framework/AzCore/AzCore/EBus/Event.inl b/Code/Framework/AzCore/AzCore/EBus/Event.inl index 006ff81e34..493dea4a3f 100644 --- a/Code/Framework/AzCore/AzCore/EBus/Event.inl +++ b/Code/Framework/AzCore/AzCore/EBus/Event.inl @@ -27,11 +27,17 @@ namespace AZ template EventHandler::EventHandler(const EventHandler& rhs) : m_callback(rhs.m_callback) + , m_event(rhs.m_event) { - // Copy the callback function, then perform a Connect with the new event - if (rhs.m_event) + // Copy the callback and event, then perform a Connect to the event + if (m_callback && m_event) + { + m_event->Connect(*this); + } + else { - rhs.m_event->Connect(*this); + // It was not possible to connect to the event, set it to nullptr + m_event = nullptr; } } @@ -65,9 +71,16 @@ namespace AZ { Disconnect(); m_callback = rhs.m_callback; - if (rhs.m_event) + m_event = rhs.m_event; + // Copy the callback and event, then perform a Connect to the event + if (m_callback && m_event) + { + m_event->Connect(*this); + } + else { - rhs.m_event->Connect(*this); + // It was not possible to connect to the event, set it to nullptr + m_event = nullptr; } } diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.cpp b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.cpp index efbc0eaa1f..5a709f9324 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.cpp +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.cpp @@ -32,6 +32,15 @@ namespace AZ { if (m_hashes.size() < m_hashes.max_size()) { + constexpr size_t MaxTagSize = TagName{}.max_size(); + if (specialization.size() > MaxTagSize) + { + AZ_Error("Settings Registry", false, R"(Cannot append Specialization tag of "%.*s.")" + " It is longer than the MaxTagNameSize of %zu", AZ_STRING_ARG(specialization), + MaxTagSize); + return false; + } + m_names.push_back(TagName{ specialization }); TagName& tag = m_names.back(); AZStd::to_lower(tag.begin(), tag.end()); diff --git a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h index baeca89636..f0077db2ca 100644 --- a/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h +++ b/Code/Framework/AzCore/AzCore/Settings/SettingsRegistry.h @@ -49,7 +49,7 @@ namespace AZ class Specializations { public: - static constexpr size_t MaxTagNameSize = 32; + static constexpr size_t MaxTagNameSize = 64; static constexpr size_t MaxCount = 15; static constexpr size_t NotFound = static_cast(-1); using TagName = AZStd::fixed_string; diff --git a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp index 9b2ccbe754..39f6c02bde 100644 --- a/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp +++ b/Code/Framework/AzCore/Platform/Windows/AzCore/Debug/StackTracer_Windows.cpp @@ -146,7 +146,7 @@ namespace AZ { AZStd::mutex g_dbgLoadingMutex; HANDLE g_currentProcess = 0; /// We deal with only one process for now. CRITICAL_SECTION g_csDbgHelpDll; /// All dbg help functions are single threaded, so we need to control the access. - AZStd::fixed_vector g_moduleInfo; + AZStd::fixed_vector g_moduleInfo; // reserve 4k of scratch space so that we can get some callstack information without any allocations and as little stack frame usage as possible. const size_t g_scratchSpaceSize = 2048; diff --git a/Code/Framework/AzCore/Tests/EventTests.cpp b/Code/Framework/AzCore/Tests/EventTests.cpp index 7640201e0d..571bdd5345 100644 --- a/Code/Framework/AzCore/Tests/EventTests.cpp +++ b/Code/Framework/AzCore/Tests/EventTests.cpp @@ -257,6 +257,48 @@ namespace UnitTest EXPECT_FALSE(testEvent1.HasHandlerConnected()); EXPECT_TRUE(testEvent2.HasHandlerConnected()); } + + TEST_F(EventTests, TestHandlerCopyConstructorOperator) + { + int32_t invokedCounter = 0; + + AZ::Event<> testEvent; + AZ::Event<>::Handler testHandler([&invokedCounter]() { invokedCounter++; }); + + testHandler.Connect(testEvent); + + AZ::Event<>::Handler testHandler2(testHandler); + + EXPECT_TRUE(testHandler.IsConnected()); + EXPECT_TRUE(testHandler2.IsConnected()); + + EXPECT_TRUE(invokedCounter == 0); + testEvent.Signal(); + EXPECT_TRUE(invokedCounter == 2); + } + + TEST_F(EventTests, TestHandlerCopyAssignmentOperator) + { + int32_t invokedCounter = 0; + + AZ::Event<> testEvent; + AZ::Event<>::Handler testHandler([&invokedCounter]() { invokedCounter++; }); + + testHandler.Connect(testEvent); + + AZ::Event<>::Handler testHandler2; + + EXPECT_TRUE(testHandler.IsConnected()); + EXPECT_FALSE(testHandler2.IsConnected()); + + testHandler2 = testHandler; + + EXPECT_TRUE(testHandler2.IsConnected()); + + EXPECT_TRUE(invokedCounter == 0); + testEvent.Signal(); + EXPECT_TRUE(invokedCounter == 2); + } } #if defined(HAVE_BENCHMARK) diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Character.cpp b/Code/Framework/AzFramework/AzFramework/Physics/Character.cpp index 59f492359d..df66442b11 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Character.cpp +++ b/Code/Framework/AzFramework/AzFramework/Physics/Character.cpp @@ -84,7 +84,7 @@ namespace Physics if (serializeContext) { serializeContext->Class() - ->Version(2) + ->Version(3) ->Field("CollisionLayer", &CharacterConfiguration::m_collisionLayer) ->Field("CollisionGroupId", &CharacterConfiguration::m_collisionGroupId) ->Field("Material", &CharacterConfiguration::m_materialSelection) @@ -94,6 +94,7 @@ namespace Physics ->Field("MinDistance", &CharacterConfiguration::m_minimumMovementDistance) ->Field("MaxSpeed", &CharacterConfiguration::m_maximumSpeed) ->Field("ColliderTag", &CharacterConfiguration::m_colliderTag) + ->Field("ApplyMoveOnPhysicsTick", &CharacterConfiguration::m_applyMoveOnPhysicsTick) ; if (AZ::EditContext* editContext = serializeContext->GetEditContext()) @@ -127,6 +128,9 @@ namespace Physics ->Attribute(AZ::Edit::Attributes::Step, 1.0f) ->DataElement(AZ::Edit::UIHandlers::Default, &CharacterConfiguration::m_colliderTag, "Collider Tag", "Used to identify the collider associated with the character controller") + ->DataElement(AZ::Edit::UIHandlers::Default, &CharacterConfiguration::m_applyMoveOnPhysicsTick, + "Apply Move On Tick", "Requests to add velocity will be accumulated and applied once on the physics pre-simulation tick " + "If unticked, explicit call to apply requested velocity is required") ; } } diff --git a/Code/Framework/AzFramework/AzFramework/Physics/Character.h b/Code/Framework/AzFramework/AzFramework/Physics/Character.h index ac46120879..e822736fd8 100644 --- a/Code/Framework/AzFramework/AzFramework/Physics/Character.h +++ b/Code/Framework/AzFramework/AzFramework/Physics/Character.h @@ -76,6 +76,7 @@ namespace Physics AZStd::string m_colliderTag; //!< Used to identify the collider associated with the character controller. AZStd::shared_ptr m_shapeConfig; //!< The shape to use when creating the character controller. AZStd::vector> m_colliders; //!< The list of colliders to attach to the character controller. + bool m_applyMoveOnPhysicsTick = true; //!< Should accumulated velocity be applied on the physics tick. }; /// Basic implementation of common character-style needs as a WorldBody. Is not a full-functional ship-ready diff --git a/Code/Framework/AzFramework/Platform/Linux/AzFramework/AzFramework_Traits_Linux.h b/Code/Framework/AzFramework/Platform/Linux/AzFramework/AzFramework_Traits_Linux.h index 98893e2d01..2cf5b3f87e 100644 --- a/Code/Framework/AzFramework/Platform/Linux/AzFramework/AzFramework_Traits_Linux.h +++ b/Code/Framework/AzFramework/Platform/Linux/AzFramework/AzFramework_Traits_Linux.h @@ -12,5 +12,5 @@ #define AZ_TRAIT_AZFRAMEWORK_USE_ERRNO_T_TYPEDEF 1 #define AZ_TRAIT_AZFRAMEWORK_USE_POSIX_LOCALTIME_R 0 #define AZ_TRAIT_AZFRAMEWORK_PYTHON_SHELL "python.sh" -#define AZ_TRAIT_AZFRAMEWORK_USE_PROJECT_MANAGER 0 +#define AZ_TRAIT_AZFRAMEWORK_USE_PROJECT_MANAGER 1 #define AZ_TRAIT_AZFRAMEWORK_PROCESSLAUNCH_DEFAULT 0 diff --git a/Code/Framework/AzFramework/Platform/Mac/AzFramework/AzFramework_Traits_Mac.h b/Code/Framework/AzFramework/Platform/Mac/AzFramework/AzFramework_Traits_Mac.h index 6af4294a5c..73f6d212d4 100644 --- a/Code/Framework/AzFramework/Platform/Mac/AzFramework/AzFramework_Traits_Mac.h +++ b/Code/Framework/AzFramework/Platform/Mac/AzFramework/AzFramework_Traits_Mac.h @@ -12,5 +12,5 @@ #define AZ_TRAIT_AZFRAMEWORK_USE_ERRNO_T_TYPEDEF 0 #define AZ_TRAIT_AZFRAMEWORK_USE_POSIX_LOCALTIME_R 1 #define AZ_TRAIT_AZFRAMEWORK_PYTHON_SHELL "python.sh" -#define AZ_TRAIT_AZFRAMEWORK_USE_PROJECT_MANAGER 0 +#define AZ_TRAIT_AZFRAMEWORK_USE_PROJECT_MANAGER 1 #define AZ_TRAIT_AZFRAMEWORK_PROCESSLAUNCH_DEFAULT 0 diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorWindowRequestBus.h b/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorWindowRequestBus.h index 03bb76b03a..ef4d2deb5e 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorWindowRequestBus.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/API/EditorWindowRequestBus.h @@ -36,8 +36,47 @@ namespace AzToolsFramework /// Retrieve the main application window. virtual QWidget* GetAppMainWindow() { return nullptr; } }; - using EditorWindowRequestBus = AZ::EBus; + + class EditorWindowUIRequests : public AZ::EBusTraits + { + public: + using Bus = AZ::EBus; + + ////////////////////////////////////////////////////////////////////////// + // EBusTraits overrides + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + ////////////////////////////////////////////////////////////////////////// + + /// Enable/Disable the Editor UI. + virtual void SetEditorUiEnabled([[maybe_unused]] bool enable) {} + }; + using EditorWindowUIRequestBus = AZ::EBus; + + using EnableUiFunction = AZStd::function; + + /// Helper for EditorWindowRequests to be used as a + /// member instead of inheriting from EBus directly. + class EditorWindowRequestBusImpl + : public EditorWindowUIRequestBus::Handler + { + public: + /// Set the function to be called when entering ImGui Mode. + void SetEnableEditorUiFunc(const EnableUiFunction enableEditorUiFunc) + { + m_enableEditorUiFunc = AZStd::move(enableEditorUiFunc); + } + + private: + // EditorWindowRequestBus + void SetEditorUiEnabled( [[maybe_unused]] bool enable) override + { + m_enableEditorUiFunc(enable); + } + + EnableUiFunction m_enableEditorUiFunc; ///< Function to call when entering ImGui Mode. + }; + } // namespace AzToolsFramework #endif // AZTOOLSFRAMEWORK_EDITORWINDOWREQUESTBUS_H diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.cpp index 73139b5a67..90274bc734 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerSortFilterProxyModel.cpp @@ -34,7 +34,24 @@ namespace AzToolsFramework bool EntityOutlinerSortFilterProxyModel::lessThan(const QModelIndex& leftIndex, const QModelIndex& rightIndex) const { - return sourceModel()->data(leftIndex).toString() < sourceModel()->data(rightIndex).toString(); + if (leftIndex.isValid() && rightIndex.isValid()) + { + QVariant leftData = sourceModel()->data(leftIndex); + QVariant rightData = sourceModel()->data(rightIndex); + + // make sure to compare the correct data types for sorting the current column + AZ_Assert(leftData.type() == rightData.type(), "EntityOutlinerSortFilterProxyModel::lessThan types do not agree!"); + if (static_cast(leftData.type()) == QMetaType::QString) + { + return leftData.toString() < rightData.toString(); + } + else if (static_cast(leftData.type()) == QMetaType::ULongLong) + { + return leftData.toULongLong() < rightData.toULongLong(); + } + AZ_Error("Editor", false, "Error! Unhandled type \"%s\" in EntityOutlinerSortFilterProxyModel::lessThan", leftData.typeName()); + } + return false; } void EntityOutlinerSortFilterProxyModel::sort(int /*column*/, Qt::SortOrder /*order*/) diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp index 96479bb54c..03784343f5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.cpp @@ -291,10 +291,12 @@ namespace AzToolsFramework GetEntityContextId()); EditorEntityInfoNotificationBus::Handler::BusConnect(); Prefab::PrefabPublicNotificationBus::Handler::BusConnect(); + EditorWindowUIRequestBus::Handler::BusConnect(); } EntityOutlinerWidget::~EntityOutlinerWidget() { + EditorWindowUIRequestBus::Handler::BusDisconnect(); Prefab::PrefabPublicNotificationBus::Handler::BusDisconnect(); ComponentModeFramework::EditorComponentModeNotificationBus::Handler::BusDisconnect(); EditorEntityInfoNotificationBus::Handler::BusDisconnect(); @@ -1106,16 +1108,25 @@ namespace AzToolsFramework AzQtComponents::SetWidgetInteractEnabled(entityOutlinerUi->m_searchWidget, on); } + void EntityOutlinerWidget::EnableUi(bool enable) + { + SetEntityOutlinerState(m_gui, enable); + setEnabled(enable); + } + + void EntityOutlinerWidget::SetEditorUiEnabled(bool enable) + { + EnableUi(enable); + } + void EntityOutlinerWidget::EnteredComponentMode([[maybe_unused]] const AZStd::vector& componentModeTypes) { - SetEntityOutlinerState(m_gui, false); - setEnabled(false); + EnableUi(false); } void EntityOutlinerWidget::LeftComponentMode([[maybe_unused]] const AZStd::vector& componentModeTypes) { - setEnabled(true); - SetEntityOutlinerState(m_gui, true); + EnableUi(true); } void EntityOutlinerWidget::OnPrefabInstancePropagationBegin() diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx index 68f538c3ff..e3f9ad2135 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/Outliner/EntityOutlinerWidget.hxx @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -58,6 +59,7 @@ namespace AzToolsFramework , private EditorEntityInfoNotificationBus::Handler , private ComponentModeFramework::EditorComponentModeNotificationBus::Handler , private Prefab::PrefabPublicNotificationBus::Handler + , private EditorWindowUIRequestBus::Handler { Q_OBJECT; public: @@ -105,6 +107,9 @@ namespace AzToolsFramework void OnPrefabInstancePropagationBegin() override; void OnPrefabInstancePropagationEnd() override; + // EditorWindowUIRequestBus overrides + void SetEditorUiEnabled(bool enable) override; + // Build a selection object from the given entities. Entities already in the Widget's selection buffers are ignored. template QItemSelection BuildSelectionFromEntities(const EntityIdCollection& entityIds); @@ -155,6 +160,7 @@ namespace AzToolsFramework AZ::EntityId GetEntityIdFromIndex(const QModelIndex& index) const; QModelIndex GetIndexFromEntityId(const AZ::EntityId& entityId) const; void ExtractEntityIdsFromSelection(const QItemSelection& selection, EntityIdList& entityIdList) const; + void EnableUi(bool enable); // OutlinerModelNotificationBus::Handler // Receive notification from the outliner model that we should scroll diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp index 6a399ad816..5d1ec93fda 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.cpp @@ -376,6 +376,7 @@ namespace AzToolsFramework ToolsApplicationEvents::Bus::Handler::BusConnect(); AZ::EntitySystemBus::Handler::BusConnect(); EntityPropertyEditorRequestBus::Handler::BusConnect(); + EditorWindowUIRequestBus::Handler::BusConnect(); m_spacer = nullptr; m_emptyIcon = QIcon(); @@ -421,6 +422,7 @@ namespace AzToolsFramework { qApp->removeEventFilter(this); + EditorWindowUIRequestBus::Handler::BusDisconnect(); EntityPropertyEditorRequestBus::Handler::BusDisconnect(); ToolsApplicationEvents::Bus::Handler::BusDisconnect(); AZ::EntitySystemBus::Handler::BusDisconnect(); @@ -4961,6 +4963,27 @@ namespace AzToolsFramework EnableDisableComponentActions(widget, actions, false); } + void EntityPropertyEditor::SetEditorUiEnabled(bool enable) + { + if (enable) + { + EnableComponentActions(this, m_entityComponentActions); + } + else + { + DisableComponentActions(this, m_entityComponentActions); + } + m_disabled = !enable; + SetPropertyEditorState(m_gui, enable); + + for (auto componentEditor : m_componentEditors) + { + AzQtComponents::SetWidgetInteractEnabled(componentEditor, enable); + } + // record the selected state after entering/leaving component mode + SaveComponentEditorState(); + } + void EntityPropertyEditor::EnteredComponentMode(const AZStd::vector& componentModeTypes) { DisableComponentActions(this, m_entityComponentActions); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx index b15e27e41a..f2ff4eb927 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -108,6 +109,7 @@ namespace AzToolsFramework , public EditorInspectorComponentNotificationBus::MultiHandler , private AzToolsFramework::ComponentModeFramework::EditorComponentModeNotificationBus::Handler , public AZ::EntitySystemBus::Handler + , private EditorWindowUIRequestBus::Handler { Q_OBJECT; public: @@ -208,6 +210,9 @@ namespace AzToolsFramework void GetSelectedEntities(EntityIdList& selectedEntityIds) override; void SetNewComponentId(AZ::ComponentId componentId) override; + // EditorWindowRequestBus overrides + void SetEditorUiEnabled(bool enable) override; + bool IsEntitySelected(const AZ::EntityId& id) const; bool IsSingleEntitySelected(const AZ::EntityId& id) const; diff --git a/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp b/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp index 9181793366..015b258123 100644 --- a/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp +++ b/Code/Legacy/CrySystem/LevelSystem/SpawnableLevelSystem.cpp @@ -174,6 +174,42 @@ namespace LegacyLevelSystem return false; } + // Make sure a spawnable level exists that matches levelname + AZStd::string validLevelName = ""; + AZ::Data::AssetId rootSpawnableAssetId; + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + rootSpawnableAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, levelName, nullptr, false); + + if (rootSpawnableAssetId.IsValid()) + { + validLevelName = levelName; + } + else + { + // It's common for users to only provide the level name, but not the full asset path + // Example: "MyLevel" instead of "Levels/MyLevel/MyLevel.spawnable" + if (!AZ::IO::PathView(levelName).HasExtension()) + { + // Search inside the "Levels" folder for a level spawnable matching levelname + const AZStd::string possibleLevelAssetPath = AZStd::string::format("Levels/%s/%s.spawnable", levelName, levelName); + + AZ::Data::AssetCatalogRequestBus::BroadcastResult( + rootSpawnableAssetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, possibleLevelAssetPath.c_str(), + nullptr, false); + + if (rootSpawnableAssetId.IsValid()) + { + validLevelName = possibleLevelAssetPath; + } + } + } + + if (validLevelName.empty()) + { + OnLevelNotFound(levelName); + return false; + } + // If a level is currently loaded, unload it before loading the next one. if (IsLevelLoaded()) { @@ -181,12 +217,12 @@ namespace LegacyLevelSystem } gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_LOAD_PREPARE, 0, 0); - PrepareNextLevel(levelName); + PrepareNextLevel(validLevelName.c_str()); - bool result = LoadLevelInternal(levelName); + bool result = LoadLevelInternal(validLevelName.c_str()); if (result) { - OnLoadingComplete(levelName); + OnLoadingComplete(validLevelName.c_str()); } return result; diff --git a/Code/Tools/AssetProcessor/native/unittests/FileWatcherUnitTests.cpp b/Code/Tools/AssetProcessor/native/unittests/FileWatcherUnitTests.cpp index 2ffe6a7996..dd39283b22 100644 --- a/Code/Tools/AssetProcessor/native/unittests/FileWatcherUnitTests.cpp +++ b/Code/Tools/AssetProcessor/native/unittests/FileWatcherUnitTests.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * + * * SPDX-License-Identifier: Apache-2.0 OR MIT * */ @@ -277,7 +277,7 @@ void FileWatcherUnitTestRunner::StartTest() UNIT_TEST_EXPECT_TRUE(QDir::toNativeSeparators(fileAddName).toLower() == QDir::toNativeSeparators(newName3).toLower()); #if !defined(AZ_PLATFORM_LINUX) - // final test... make sure that renaming a DIRECTORY works too. + // final test... make sure that renaming a DIRECTORY works too. // Note that linux does not get any callbacks if just the directory is renamed (from inotify) QDir renamer; fileAddCalled = false; @@ -312,6 +312,9 @@ void FileWatcherUnitTestRunner::StartTest() Q_EMIT UnitTestPassed(); } -#if !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS +// File operations on Linux behave differently on Linux than Windows. +// The system under test doesn't yet handle Linux's file operations, which surfaced as this test arbitrarily passing and failing. +// This test is disabled on Linux until the system under test can handle Linux file system behavior correctly. +#if !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS && !defined(AZ_PLATFORM_LINUX) REGISTER_UNIT_TEST(FileWatcherUnitTestRunner) #endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS diff --git a/Code/Tools/CMakeLists.txt b/Code/Tools/CMakeLists.txt index 6c025a0543..1bab1cee77 100644 --- a/Code/Tools/CMakeLists.txt +++ b/Code/Tools/CMakeLists.txt @@ -10,7 +10,6 @@ add_subdirectory(AssetProcessor) add_subdirectory(AWSNativeSDKInit) add_subdirectory(AzTestRunner) add_subdirectory(CrashHandler) -add_subdirectory(News) add_subdirectory(PythonBindingsExample) add_subdirectory(RemoteConsole) add_subdirectory(DeltaCataloger) diff --git a/Code/Tools/News/CMakeLists.txt b/Code/Tools/News/CMakeLists.txt deleted file mode 100644 index 78c5774ef0..0000000000 --- a/Code/Tools/News/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -add_subdirectory(NewsBuilder) - -if (NOT PAL_TRAIT_BUILD_HOST_TOOLS) - return() -endif() - -ly_add_target( - NAME NewsShared STATIC - NAMESPACE Legacy - AUTOMOC - AUTOUIC - AUTORCC - FILES_CMAKE - news_shared_files.cmake - INCLUDE_DIRECTORIES - PUBLIC - . - BUILD_DEPENDENCIES - PRIVATE - 3rdParty::Qt::Core - 3rdParty::Qt::Network - 3rdParty::Qt::Widgets - AZ::AzQtComponents -) diff --git a/Code/Tools/News/NewsBuilder/CMakeLists.txt b/Code/Tools/News/NewsBuilder/CMakeLists.txt deleted file mode 100644 index 218f4e28f5..0000000000 --- a/Code/Tools/News/NewsBuilder/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME}) - -include(${pal_dir}/PAL_${PAL_PLATFORM_NAME_LOWERCASE}.cmake) - -if (NOT PAL_TRAIT_BUILD_NEWSBUILDER_SUPPORTED OR NOT PAL_TRAIT_BUILD_HOST_TOOLS) - return() -endif() - -ly_add_target( - NAME NewsBuilder EXECUTABLE - NAMESPACE Legacy - AUTOMOC - AUTOUIC - AUTORCC - FILES_CMAKE - news_builder_files.cmake - INCLUDE_DIRECTORIES - PUBLIC - . - BUILD_DEPENDENCIES - PRIVATE - 3rdParty::Qt::Core - 3rdParty::Qt::Widgets - 3rdParty::AWSNativeSDK::Dependencies - 3rdParty::AWSNativeSDK::Core - 3rdParty::AWSNativeSDK::S3 - Legacy::NewsShared - AZ::AzCore - AZ::AzQtComponents - AZ::AzFramework -) diff --git a/Code/Tools/News/NewsBuilder/EndpointManager.cpp b/Code/Tools/News/NewsBuilder/EndpointManager.cpp deleted file mode 100644 index 0b2ea4dd5c..0000000000 --- a/Code/Tools/News/NewsBuilder/EndpointManager.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "EndpointManager.h" -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace News -{ - - Endpoint::Endpoint(QString name, QString awsProfile, QString url, QString bucket) - : m_name(name) - , m_awsProfile(awsProfile) - , m_url(url) - , m_bucket(bucket) - {} - - Endpoint::Endpoint(const QJsonObject& json) - : Endpoint(json["name"].toString(), - json["awsProfile"].toString(), - json["url"].toString(), - json["bucket"].toString()) - { - } - - Endpoint::~Endpoint() {} - - void Endpoint::Write(QJsonObject& json) const - { - json["name"] = m_name; - json["awsProfile"] = m_awsProfile; - json["url"] = m_url; - json["bucket"] = m_bucket; - } - - QString Endpoint::GetName() const - { - return m_name; - } - - void Endpoint::SetName(const QString& name) - { - m_name = QString(name); - } - - QString Endpoint::GetAwsProfile() const - { - return m_awsProfile; - } - - void Endpoint::SetAwsProfile(const QString& awsProfile) - { - m_awsProfile = QString(awsProfile); - } - - QString Endpoint::GetUrl() const - { - return m_url; - } - - void Endpoint::SetUrl(const QString& url) - { - m_url = QString(url); - } - - QString Endpoint::GetBucket() const - { - return m_bucket; - } - - void Endpoint::SetBucket(const QString& bucket) - { - m_bucket = bucket; - } - - EndpointManager::EndpointManager() - { - Load(); - } - - EndpointManager::~EndpointManager() - { - ClearEndpoints(); - } - - void EndpointManager::Load() - { - ClearEndpoints(); - QFile file("newsBuilderConfig.txt"); - if (file.open(QIODevice::ReadOnly)) - { - QTextStream in(&file); - QString str = in.readAll().trimmed(); - QByteArray array(str.toStdString().c_str()); - QJsonDocument doc(QJsonDocument::fromJson(array)); - QJsonObject json = doc.object(); - QJsonArray endpointArray = json["endpoints"].toArray(); - for (auto endpointDoc : endpointArray) - { - m_endpoints.append(new Endpoint(endpointDoc.toObject())); - } - int endpointIndex = json["currentEndpointIndex"].toInt(); - if (endpointIndex >= 0 && m_endpoints.count() > endpointIndex) - { - m_selectedEndpoint = m_endpoints[endpointIndex]; - } - else - { - m_selectedEndpoint = nullptr; - } - file.close(); - - SaveUrl(); - } - } - - void EndpointManager::Save() - { - QFile file("newsBuilderConfig.txt"); - if (file.open(QIODevice::WriteOnly)) - { - QJsonObject json; - QJsonArray endpointArray; - for (auto endpoint : m_endpoints) - { - QJsonObject endpointObject; - endpoint->Write(endpointObject); - endpointArray.append(endpointObject); - } - json["endpoints"] = endpointArray; - json["currentEndpointIndex"] = m_endpoints.indexOf(m_selectedEndpoint); - QTextStream out(&file); - QJsonDocument doc(json); - out << doc.toJson(QJsonDocument::Compact); - file.close(); - - SaveUrl(); - } - } - - void EndpointManager::SelectEndpoint(Endpoint* endpoint) - { - m_selectedEndpoint = endpoint; - } - - void EndpointManager::AddEndpoint(Endpoint* endpoint) - { - m_endpoints.append(endpoint); - } - - void EndpointManager::RemoveEndpoint(Endpoint* endpoint) - { - if (endpoint == m_selectedEndpoint) - { - m_selectedEndpoint = nullptr; - } - m_endpoints.removeAll(endpoint); - delete endpoint; - } - - Endpoint* EndpointManager::GetSelectedEndpoint() const - { - return m_selectedEndpoint; - } - - QList::const_iterator EndpointManager::begin() const - { - return m_endpoints.begin(); - } - - QList::const_iterator EndpointManager::end() const - { - return m_endpoints.end(); - } - - void EndpointManager::ClearEndpoints() - { - for (auto endpoint : m_endpoints) - { - delete endpoint; - } - m_endpoints.clear(); - } - - void EndpointManager::SaveUrl() const - { - if (!m_selectedEndpoint) - { - return; - } - // Editor looks for config file in /dev folder, so this file is placed in parent directory - QFile file(QCoreApplication::applicationDirPath() + "/newsConfig.txt"); - if (file.open(QIODevice::WriteOnly)) - { - QTextStream out(&file); - out << m_selectedEndpoint->GetUrl(); - file.close(); - } - } - -} diff --git a/Code/Tools/News/NewsBuilder/EndpointManager.h b/Code/Tools/News/NewsBuilder/EndpointManager.h deleted file mode 100644 index cc44951d16..0000000000 --- a/Code/Tools/News/NewsBuilder/EndpointManager.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include - -class QJsonObject; - -namespace News -{ - //! Endpoint represents a location of news data - class Endpoint - { - public: - Endpoint(QString name, QString awsProfile, QString url, QString bucket); - explicit Endpoint(const QJsonObject& json); - ~Endpoint(); - - void Write(QJsonObject& json) const; - - QString GetName() const; - void SetName(const QString& name); - - QString GetAwsProfile() const; - void SetAwsProfile(const QString& awsProfile); - - QString GetUrl() const; - void SetUrl(const QString& url); - - QString GetBucket() const; - void SetBucket(const QString& bucket); - - private: - //! name of endpoint to distinguish with others - QString m_name; - //! name of aws credentials file - QString m_awsProfile; - //! url location of news data (e.g. cloudfront url) - QString m_url; - //! name of s3 bucket where news data resides - QString m_bucket; - }; - - //! EndpointManager handles endpoint collection - class EndpointManager - { - public: - EndpointManager(); - ~EndpointManager(); - - //! Load endpoints file - void Load(); - //! Save endpoints file - void Save(); - void SelectEndpoint(Endpoint* endpoint); - void AddEndpoint(Endpoint* endpoint); - void RemoveEndpoint(Endpoint* endpoint); - Endpoint* GetSelectedEndpoint() const; - - QList::const_iterator begin() const; - QList::const_iterator end() const; - - private: - QList m_endpoints; - Endpoint* m_selectedEndpoint = nullptr; - - void ClearEndpoints(); - //! Saves news config file which is used by LY Editor to determine news location - void SaveUrl() const; - }; -} diff --git a/Code/Tools/News/NewsBuilder/Platform/Android/PAL_android.cmake b/Code/Tools/News/NewsBuilder/Platform/Android/PAL_android.cmake deleted file mode 100644 index 929d864fc4..0000000000 --- a/Code/Tools/News/NewsBuilder/Platform/Android/PAL_android.cmake +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -set(PAL_TRAIT_BUILD_NEWSBUILDER_SUPPORTED FALSE) diff --git a/Code/Tools/News/NewsBuilder/Platform/Linux/PAL_linux.cmake b/Code/Tools/News/NewsBuilder/Platform/Linux/PAL_linux.cmake deleted file mode 100644 index 929d864fc4..0000000000 --- a/Code/Tools/News/NewsBuilder/Platform/Linux/PAL_linux.cmake +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -set(PAL_TRAIT_BUILD_NEWSBUILDER_SUPPORTED FALSE) diff --git a/Code/Tools/News/NewsBuilder/Platform/Mac/PAL_mac.cmake b/Code/Tools/News/NewsBuilder/Platform/Mac/PAL_mac.cmake deleted file mode 100644 index 929d864fc4..0000000000 --- a/Code/Tools/News/NewsBuilder/Platform/Mac/PAL_mac.cmake +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -set(PAL_TRAIT_BUILD_NEWSBUILDER_SUPPORTED FALSE) diff --git a/Code/Tools/News/NewsBuilder/Platform/Windows/PAL_windows.cmake b/Code/Tools/News/NewsBuilder/Platform/Windows/PAL_windows.cmake deleted file mode 100644 index 180b7b9492..0000000000 --- a/Code/Tools/News/NewsBuilder/Platform/Windows/PAL_windows.cmake +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -set(PAL_TRAIT_BUILD_NEWSBUILDER_SUPPORTED TRUE) diff --git a/Code/Tools/News/NewsBuilder/Platform/iOS/PAL_ios.cmake b/Code/Tools/News/NewsBuilder/Platform/iOS/PAL_ios.cmake deleted file mode 100644 index 929d864fc4..0000000000 --- a/Code/Tools/News/NewsBuilder/Platform/iOS/PAL_ios.cmake +++ /dev/null @@ -1,8 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -set(PAL_TRAIT_BUILD_NEWSBUILDER_SUPPORTED FALSE) diff --git a/Code/Tools/News/NewsBuilder/Qt/ArticleDetails.cpp b/Code/Tools/News/NewsBuilder/Qt/ArticleDetails.cpp deleted file mode 100644 index 2872a714e8..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/ArticleDetails.cpp +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "ArticleDetails.h" -#include "SelectImage.h" -#include -#include "ResourceManagement/BuilderResourceManifest.h" -#include "ResourceManagement/ImageDescriptor.h" -#include "NewsShared/ErrorCodes.h" - -#include - -#include -#include -#include -#include - -#include "Qt/ui_ArticleDetails.h" - -namespace News -{ - - ArticleDetails::ArticleDetails(QWidget* parent, - Resource& resource, - BuilderResourceManifest& manifest) - : QWidget(parent) - , m_ui(new Ui::ArticleDetailsWidget) - , m_filename("") - , m_article(resource) - , m_manifest(manifest) - , m_imageIdOriginal("") - , m_imageId("") - { - m_ui->setupUi(this); - m_ui->uidLabel->setText(QString("Article: %1").arg(m_article.GetResource().GetId())); - - resizePreviewImage(); - - //! try to load image icon - auto pImageResource = m_manifest.FindById(m_article.GetImageId()); - if (pImageResource) - { - m_imageIdOriginal = pImageResource->GetId(); - SetImage(*pImageResource); - } - else - { - SetNoImage(); - } - - m_ui->titleText->setText(m_article.GetTitle()); - m_ui->descriptionText->setPlainText(m_article.GetBody()); - - connect(m_ui->fromFileButton, &QPushButton::clicked, this, &ArticleDetails::OpenImageFromFile); - connect(m_ui->fromResourceButton, &QPushButton::clicked, this, &ArticleDetails::OpenImageFromResource); - connect(m_ui->clearImageButton, &QPushButton::clicked, this, &ArticleDetails::ClearImage); - connect(m_ui->updateButton, &QPushButton::clicked, this, &ArticleDetails::UpdateArticle); - connect(m_ui->deleteButton, &QPushButton::clicked, this, &ArticleDetails::DeleteArticle); - connect(m_ui->cancelButton, &QPushButton::clicked, this, &ArticleDetails::Close); - connect(m_ui->upButton, &QPushButton::clicked, this, &ArticleDetails::MoveUp); - connect(m_ui->downButton, &QPushButton::clicked, this, &ArticleDetails::MoveDown); - } - - ArticleDetails::~ArticleDetails() {} - - void ArticleDetails::resizeEvent(QResizeEvent *event) - { - QWidget::resizeEvent(event); - resizePreviewImage(); - } - - void ArticleDetails::resizePreviewImage() - { - // Resize the imagePreview to keep the proportions - int newHeight = aznumeric_cast(m_imageRatio * width()); - m_ui->imagePreview->setFixedHeight(newHeight); - } - - ArticleDescriptor& ArticleDetails::GetArticle() - { - return m_article; - } - - QString ArticleDetails::GetId() const - { - return m_article.GetResource().GetId(); - } - - void ArticleDetails::OpenImageFromFile() - { - m_filename = QFileDialog::getOpenFileName(this, - "Open Image", ".", "Image Files (*.png *.jpg *.bmp)"); - SetImage(m_filename); - } - - void ArticleDetails::OpenImageFromResource() - { - m_pSelectImage = new SelectImage(m_manifest); - if (m_pSelectImage->exec() == QDialog::DialogCode::Accepted) - { - auto pSelectedResource = m_pSelectImage->GetSelected(); - if (!pSelectedResource) - { - QMessageBox msgBox(QMessageBox::Critical, - "Error", - "No resource pSelectedResource", - QMessageBox::Ok, - this); - msgBox.exec(); - return; - } - SetImage(*pSelectedResource); - } - delete m_pSelectImage; - } - - //! once the Update button is clicked, article resource is updated in this function - void ArticleDetails::UpdateArticle() - { - //! this flag remains false if no new changes are detected, thus avoiding unnecessary - //! re-uploading unchanged resources - bool updated = false; - - m_imageId = LoadImage(); - if (m_imageId.compare(m_imageIdOriginal) != 0) - { - m_article.SetImageId(m_imageId); - m_filename = ""; - m_imageIdOriginal = m_imageId; - m_ui->imagePathLabel->setText(QString("Image: %1").arg(m_imageId)); - updated = true; - } - - QString newTitle = m_ui->titleText->text(); - if (m_article.GetTitle().compare(newTitle)) - { - m_article.SetTitle(newTitle); - updated = true; - } - QString newBody = m_ui->descriptionText->toPlainText(); - if (m_article.GetBody().compare(newBody) != 0) - { - m_article.SetBody(newBody); - updated = true; - } - - QString newStyle = m_ui->articleStyleButtonGroup->checkedButton()->property("style").toString(); - if (m_article.GetArticleStyle() != newStyle) - { - m_article.SetArticleStyle(newStyle); - updated = true; - } - - if (updated) - { - m_article.Update(); - m_manifest.UpdateResource(&m_article.GetResource()); - emit logSignal(QString("Article %1 updated") - .arg(m_article.GetResource().GetId()), LogOk); - } - else - { - emit logSignal("Nothing to update", LogWarning); - } - emit updateArticleSignal(); - } - - //! try to load an image either from filename or from another resource, - //! update resource manifest accordingly - QString ArticleDetails::LoadImage() const - { - if (!m_filename.isEmpty()) - { - if (!m_imageIdOriginal.isEmpty()) - { - m_manifest.FreeResource(m_imageIdOriginal); - } - auto pResource = m_manifest.AddImage(m_filename); - if (pResource) - { - return pResource->GetId(); - } - return ""; - } - - if (m_imageId.compare(m_imageIdOriginal) != 0) - { - if (!m_imageIdOriginal.isEmpty()) - { - m_manifest.FreeResource(m_imageIdOriginal); - } - if (!m_imageId.isEmpty()) - { - m_manifest.UseResource(m_imageId); - } - return m_imageId; - } - - return m_imageIdOriginal; - } - - void ArticleDetails::SetImage(Resource& resource) - { - m_ui->imagePathLabel->setText(QString("Image: %1").arg(resource.GetId())); - - QPixmap pixmap; - if (pixmap.loadFromData(resource.GetData())) - { - m_ui->imagePreview->setPixmap(pixmap); - m_imageId = resource.GetId(); - } - else - { - SetNoImage(); - emit logSignal(QString("Failed to load image: %1.").arg(m_imageId)); - } - } - - void ArticleDetails::SetImage([[maybe_unused]] QString& filename) - { - m_ui->imagePathLabel->setText(QString("Image: %1").arg(m_filename)); - - QPixmap pixmap; - if (pixmap.load(m_filename)) - { - m_ui->imagePreview->setPixmap(pixmap); - } - else - { - SetNoImage(); - emit logSignal(QString("Failed to load image: %1.").arg(m_filename)); - } - } - - void ArticleDetails::SetNoImage() const - { - m_ui->imagePreview->setPixmap(QPixmap(":/images/Resources/missing-image.png")); - m_ui->imagePathLabel->setText("no image"); - } - - void ArticleDetails::ClearImage() - { - m_imageId = ""; - m_filename = ""; - SetNoImage(); - } - - void ArticleDetails::DeleteArticle() - { - if (!m_article.GetImageId().isEmpty()) - { - m_manifest.FreeResource(m_article.GetImageId()); - } - m_manifest.FreeResource(m_article.GetResource().GetId()); - emit deleteArticleSignal(); - } - - void ArticleDetails::Close() - { - emit closeArticleSignal(); - } - - void ArticleDetails::MoveUp() - { - ErrorCode error; - if (!m_manifest.UpdateArticleOrder(m_article.GetResource().GetId(), 1, error)) - { - emit logSignal(GetErrorMessage(error)); - } - else - { - emit orderChangedSignal(m_article.GetResource().GetId(), 1); - } - } - - void ArticleDetails::MoveDown() - { - ErrorCode error; - if (!m_manifest.UpdateArticleOrder(m_article.GetResource().GetId(), 0, error)) - { - emit logSignal(GetErrorMessage(error)); - } - else - { - emit orderChangedSignal(m_article.GetResource().GetId(), 0); - } - } - -#include "Qt/moc_ArticleDetails.cpp" - -} diff --git a/Code/Tools/News/NewsBuilder/Qt/ArticleDetails.h b/Code/Tools/News/NewsBuilder/Qt/ArticleDetails.h deleted file mode 100644 index 7f8d482e3f..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/ArticleDetails.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - - -#if !defined(Q_MOC_RUN) -#include -#include "ResourceManagement/BuilderResourceManifest.h" - -#include -#endif - -namespace Ui -{ - class ArticleDetailsWidget; -} - -namespace News { - class SelectImage; - class ResourceManifest; - class Resource; - - //! Control that allows to modify all parameters of a single article - class ArticleDetails - : public QWidget - { - Q_OBJECT - - public: - ArticleDetails(QWidget* parent, - Resource& resource, - BuilderResourceManifest& manifest); - ~ArticleDetails(); - ArticleDescriptor& GetArticle(); - QString GetId() const; - - Q_SIGNALS: - void logSignal(QString text, LogType logType = LogInfo); - void deleteArticleSignal(); - void updateArticleSignal(); - void closeArticleSignal(); - void orderChangedSignal(QString id, bool direction); - - private: - QScopedPointer m_ui; - QString m_filename; - ArticleDescriptor m_article; - BuilderResourceManifest& m_manifest; - SelectImage* m_pSelectImage; - QString m_imageIdOriginal; - QString m_imageId; - float m_imageRatio = 184.0f / 430.0f; - - void resizeEvent(QResizeEvent *event) override; - void resizePreviewImage(); - - void OpenImageFromFile(); - void OpenImageFromResource(); - QString LoadImage() const; - void SetImage(Resource& resource); - void SetImage(QString& filename); - void SetNoImage() const; - void ClearImage(); - - void UpdateArticle(); - void DeleteArticle(); - void Close(); - void MoveUp(); - void MoveDown(); - }; -} // namespace News diff --git a/Code/Tools/News/NewsBuilder/Qt/ArticleDetails.ui b/Code/Tools/News/NewsBuilder/Qt/ArticleDetails.ui deleted file mode 100644 index 92970f1130..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/ArticleDetails.ui +++ /dev/null @@ -1,406 +0,0 @@ - - - ArticleDetailsWidget - - - - 0 - 0 - 250 - 420 - - - - - 0 - 0 - - - - - 100 - 420 - - - - - 640 - 16777215 - - - - Form - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 100 - 100 - - - - - 16777215 - 16777215 - - - - - - - :/images/Resources/missing-image.png - - - false - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - 100 - 100 - - - - - - - - - 16777215 - 140 - - - - - 0 - - - - - Image: - - - true - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - - - - 16777215 - 16777215 - - - - Clear - - - - - - - - 16777215 - 16777215 - - - - Library... - - - - - - - - 16777215 - 16777215 - - - - Load... - - - - - - - - - - - - - - - - 1280 - 1280 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 16777215 - 20 - - - - Article: 0 - - - - - - - 0 - - - 0 - - - 3 - - - 0 - - - 3 - - - - - Default Style - - - true - - - default - - - articleStyleButtonGroup - - - - - - - Pinned Style - - - pinned - - - articleStyleButtonGroup - - - - - - - - - Title: - - - - - - - true - - - - - - - - - - 0 - - - - - Description: - - - - - - - - - - 0 - - - - - 0 - - - - - Delete - - - - - - - Cancel - - - - - - - Save - - - - - - - - - 0 - - - - - - 16777215 - 16777215 - - - - Move Up - - - - - - - - 16777215 - 16777215 - - - - Move Down - - - - - - - - - - - - - - - - - AzQtComponents::ExtendedLabel - QLabel -
AzQtComponents/Components/ExtendedLabel.h
-
-
- - - - - - - -
diff --git a/Code/Tools/News/NewsBuilder/Qt/ArticleDetailsContainer.cpp b/Code/Tools/News/NewsBuilder/Qt/ArticleDetailsContainer.cpp deleted file mode 100644 index 586978a562..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/ArticleDetailsContainer.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "ArticleDetailsContainer.h" -#include "ResourceManagement/BuilderResourceManifest.h" -#include "ArticleDetails.h" -#include "Qt/ui_ArticleDetailsContainer.h" - -namespace News -{ - - ArticleDetailsContainer::ArticleDetailsContainer( - QWidget* parent, - BuilderResourceManifest& manifest) - : QWidget(parent) - , m_ui(new Ui::ArticleDetailsContainerWidget) - , m_manifest(manifest) - , m_articleDetails(nullptr) - { - m_ui->setupUi(this); - } - - ArticleDetailsContainer::~ArticleDetailsContainer() {} - - //! When article is selected, old articleDetails control is removed, new one is created - void ArticleDetailsContainer::SelectArticle(const QString& id) - { - closeArticleSlot(); - - if (!id.isEmpty()) - { - auto article = m_manifest.FindById(id); - if (article) - { - m_articleDetails = new ArticleDetails( - m_ui->scrollAreaWidgetContents, - *article, - m_manifest); - m_ui->scrollAreaWidgetContents->layout()->addWidget(m_articleDetails); - connect(m_articleDetails, &ArticleDetails::updateArticleSignal, - this, &ArticleDetailsContainer::updateArticleSlot); - connect(m_articleDetails, &ArticleDetails::deleteArticleSignal, - this, &ArticleDetailsContainer::deleteArticleSlot); - connect(m_articleDetails, &ArticleDetails::closeArticleSignal, - this, &ArticleDetailsContainer::closeArticleSlot); - connect(m_articleDetails, SIGNAL(logSignal(QString, LogType)), - this, SIGNAL(logSignal(QString, LogType))); - connect(m_articleDetails, SIGNAL(orderChangedSignal(QString, bool)), - this, SIGNAL(orderChangedSignal(QString, bool))); - m_selectedId = id; - } - } - } - - void ArticleDetailsContainer::Reset() - { - SelectArticle(m_selectedId); - } - - void ArticleDetailsContainer::updateArticleSlot() - { - emit updateArticleSignal(m_articleDetails->GetId()); - } - - void ArticleDetailsContainer::deleteArticleSlot() - { - emit deleteArticleSignal(m_articleDetails->GetId()); - closeArticleSlot(); - } - - void ArticleDetailsContainer::closeArticleSlot() - { - if (m_articleDetails) - { - emit closeArticleSignal(m_selectedId); - delete m_articleDetails; - m_articleDetails = nullptr; - m_selectedId = ""; - } - } - -#include "Qt/moc_ArticleDetailsContainer.cpp" - -} diff --git a/Code/Tools/News/NewsBuilder/Qt/ArticleDetailsContainer.h b/Code/Tools/News/NewsBuilder/Qt/ArticleDetailsContainer.h deleted file mode 100644 index 1df42198c3..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/ArticleDetailsContainer.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#endif - -namespace Ui -{ - class ArticleDetailsContainerWidget; -} - -namespace News -{ - class ArticleDetails; - class BuilderResourceManifest; - class SelectImage; - class ResourceManifest; - class Resource; - - //! Control that manages articleDetails control - class ArticleDetailsContainer - : public QWidget - { - Q_OBJECT - - public: - ArticleDetailsContainer(QWidget* parent, BuilderResourceManifest& manifest); - ~ArticleDetailsContainer(); - - void SelectArticle(const QString& id); - void Reset(); - -Q_SIGNALS: - void logSignal(QString text, LogType logType = LogInfo); - void updateArticleSignal(QString id); - void deleteArticleSignal(QString id); - void closeArticleSignal(QString id); - void orderChangedSignal(QString id, bool direction); - - private: - QScopedPointer m_ui; - BuilderResourceManifest& m_manifest; - ArticleDetails* m_articleDetails = nullptr; - QString m_selectedId; - - private Q_SLOTS: - void updateArticleSlot(); - void deleteArticleSlot(); - void closeArticleSlot(); - }; -} // namespace News diff --git a/Code/Tools/News/NewsBuilder/Qt/ArticleDetailsContainer.ui b/Code/Tools/News/NewsBuilder/Qt/ArticleDetailsContainer.ui deleted file mode 100644 index 7652fa114d..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/ArticleDetailsContainer.ui +++ /dev/null @@ -1,100 +0,0 @@ - - - ArticleDetailsContainerWidget - - - - 0 - 0 - 250 - 386 - - - - - 0 - 0 - - - - - 250 - 0 - - - - - 640 - 16777215 - - - - ArticleDetailsContainer - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - Qt::ScrollBarAlwaysOff - - - true - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - 0 - 0 - 248 - 384 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - diff --git a/Code/Tools/News/NewsBuilder/Qt/AwsDialog.ui b/Code/Tools/News/NewsBuilder/Qt/AwsDialog.ui deleted file mode 100644 index f58243ed8d..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/AwsDialog.ui +++ /dev/null @@ -1,102 +0,0 @@ - - - Dialog - - - - 0 - 0 - 176 - 137 - - - - - 0 - 0 - - - - Dialog - - - - - - - - - - AWS Key Id: - - - - - - - - - - - - - - AWS Secret Key: - - - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - buttonBox - accepted() - Dialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - Dialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/Code/Tools/News/NewsBuilder/Qt/BuilderArticleViewContainer.cpp b/Code/Tools/News/NewsBuilder/Qt/BuilderArticleViewContainer.cpp deleted file mode 100644 index bf77a89895..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/BuilderArticleViewContainer.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "BuilderArticleViewContainer.h" -#include "ResourceManagement/BuilderResourceManifest.h" -#include "ArticleDetails.h" -#include -#include -#include -#include "Qt/ui_BuilderArticleViewContainer.h" - -#include - -#include "QCustomMessageBox.h" - -namespace News -{ - - BuilderArticleViewContainer::BuilderArticleViewContainer( - QWidget* parent, - BuilderResourceManifest& manifest) - : QWidget(parent) - , m_ui(new Ui::BuilderArticleViewContainerWidget) - , m_container(new ArticleViewContainer(this, manifest)) - , m_manifest(manifest) - { - m_ui->setupUi(this); - - m_ui->ArticleViewContainerRoot->layout()->addWidget(m_container); - connect(m_container, SIGNAL(articleSelectedSignal(QString)), - this, SLOT(articleSelectedSlot(QString))); - } - - BuilderArticleViewContainer::~BuilderArticleViewContainer(){} - - void BuilderArticleViewContainer::AddArticle() - { - auto pArticleResource = static_cast(m_manifest).AddArticle(); - if (pArticleResource) - { - m_container->AddArticleView(ArticleDescriptor(*pArticleResource)); - SelectArticle(pArticleResource->GetId()); - } - } - - void BuilderArticleViewContainer::SelectArticle(QString id) - { - if (m_selectedArticleId.compare(id) == 0) - { - return; - } - - UnselectArticle(); - m_selectedArticleId = id; - auto article = m_container->FindById(id); - if (article) - { - m_container->ScrollToView(article); - emit articleSelectedSignal(id); - - // Add class and refresh style - AzQtComponents::Style::addClass(article, m_selectedArticleClass); - article->style()->unpolish(qApp); - article->style()->polish(qApp); - } - } - - void BuilderArticleViewContainer::Sync() - { - emit logSignal("Starting sync"); - - m_manifest.Sync(); - } - - void BuilderArticleViewContainer::UpdateArticle(QString& id) const - { - auto view = m_container->FindById(id); - if (view) - { - view->Update(); - m_container->ForceRefreshArticleView(view); - } - } - - void BuilderArticleViewContainer::DeleteArticle(QString& id) const - { - auto view = m_container->FindById(id); - if (view) - { - m_container->DeleteArticleView(view); - } - } - - //possibly support multiple selection in future? - void BuilderArticleViewContainer::CloseArticle(QString& id) - { - if (m_selectedArticleId == id) - { - UnselectArticle(); - } - } - - void BuilderArticleViewContainer::UpdateArticleOrder(QString& id, bool direction) const - { - auto view = m_container->FindById(id); - if (view) - { - m_container->UpdateArticleOrder(view, direction); - } - } - - void BuilderArticleViewContainer::PopulateArticles() - { - m_container->PopulateArticles(); - - if (!m_selectedArticleId.isEmpty()) - { - SelectArticle(m_selectedArticleId); - } - } - - void BuilderArticleViewContainer::AddErrorMessage() const - { - m_container->AddErrorMessage(); - } - - void BuilderArticleViewContainer::UnselectArticle() - { - if (m_selectedArticleId.isEmpty()) - { - return; - } - auto article = m_container->FindById(m_selectedArticleId); - - // Remove class and refresh style - if (article) - { - AzQtComponents::Style::removeClass(article, m_selectedArticleClass); - article->style()->unpolish(qApp); - article->style()->polish(qApp); - } - - m_selectedArticleId = ""; - } - - void BuilderArticleViewContainer::articleSelectedSlot(QString id) - { - SelectArticle(id); - } - -#include "Qt/moc_BuilderArticleViewContainer.cpp" - -} diff --git a/Code/Tools/News/NewsBuilder/Qt/BuilderArticleViewContainer.h b/Code/Tools/News/NewsBuilder/Qt/BuilderArticleViewContainer.h deleted file mode 100644 index 94712ca768..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/BuilderArticleViewContainer.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#endif - -namespace Ui -{ - class BuilderArticleViewContainerWidget; -} - -namespace News -{ - class ArticleViewContainer; - class BuilderResourceManifest; - - //! BuilderArticleViewContainer is a Builder container for ArticleViewContainer. - /*! - It is a wrapper with additional builder functionality for displaying articles - */ - class BuilderArticleViewContainer - : public QWidget - { - Q_OBJECT - public: - BuilderArticleViewContainer(QWidget* parent, BuilderResourceManifest& manifest); - ~BuilderArticleViewContainer(); - - void UpdateArticle(QString& id) const; - void DeleteArticle(QString& id) const; - void CloseArticle(QString& id); - void UpdateArticleOrder(QString& id, bool direction) const; - void PopulateArticles(); - void AddErrorMessage() const; - void AddArticle(); - -Q_SIGNALS: - void logSignal(QString text, LogType logType = LogInfo); - void articleSelectedSignal(QString id); - - private: - QScopedPointer m_ui; - ArticleViewContainer* m_container; - QString m_selectedArticleId; - QString m_selectedArticleClass = "SelectedArticle"; - BuilderResourceManifest& m_manifest; - - void Sync(); - void SelectArticle(QString id); - void UnselectArticle(); - - - private Q_SLOTS: - void articleSelectedSlot(QString id); - }; -} // namespace News diff --git a/Code/Tools/News/NewsBuilder/Qt/BuilderArticleViewContainer.ui b/Code/Tools/News/NewsBuilder/Qt/BuilderArticleViewContainer.ui deleted file mode 100644 index dafac9b9ff..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/BuilderArticleViewContainer.ui +++ /dev/null @@ -1,57 +0,0 @@ - - - BuilderArticleViewContainerWidget - - - - 0 - 0 - 250 - 500 - - - - Form - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - diff --git a/Code/Tools/News/NewsBuilder/Qt/EndpointEntryView.cpp b/Code/Tools/News/NewsBuilder/Qt/EndpointEntryView.cpp deleted file mode 100644 index 5e698eea97..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/EndpointEntryView.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "EndpointEntryView.h" -#include "Qt/ui_EndpointEntryView.h" -#include -#include - -namespace News -{ - - const char* EndpointEntryView::SELECTED_CSS = - "background-color: rgb(60, 100, 60);\ncolor: white;"; - const char* EndpointEntryView::UNSELECTED_CSS = - "background-color: rgb(60, 60, 60);\ncolor: white;"; - - EndpointEntryView::EndpointEntryView(QWidget* parent, Endpoint* pEndpoint) - : QWidget(parent) - , m_ui(new Ui::EndpointEntryViewWidget) - , m_pEndpoint(pEndpoint) - { - m_ui->setupUi(this); - - m_ui->labelName->setText(pEndpoint->GetName()); - - connect(m_ui->labelName, &AzQtComponents::ExtendedLabel::clicked, this, &EndpointEntryView::selectSlot); - connect(m_ui->buttonDelete, &QToolButton::clicked, this, &EndpointEntryView::deleteSlot); - } - - EndpointEntryView::~EndpointEntryView() {} - - void EndpointEntryView::SetSelected(bool selected) - { - setStyleSheet(selected ? SELECTED_CSS : UNSELECTED_CSS); - } - - Endpoint* EndpointEntryView::GetEndpoint() const - { - return m_pEndpoint; - } - - void EndpointEntryView::selectSlot() - { - emit selectSignal(this); - } - - void EndpointEntryView::deleteSlot() - { - emit deleteSignal(this); - } - -#include "Qt/moc_EndpointEntryView.cpp" - -} diff --git a/Code/Tools/News/NewsBuilder/Qt/EndpointEntryView.h b/Code/Tools/News/NewsBuilder/Qt/EndpointEntryView.h deleted file mode 100644 index c8b014c167..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/EndpointEntryView.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#endif - -namespace Ui -{ - class EndpointEntryViewWidget; -} - -namespace News -{ - class Endpoint; - - //! Qt widget representing a single endpoint entry - class EndpointEntryView - : public QWidget - { - Q_OBJECT - public: - EndpointEntryView(QWidget* parent, Endpoint* pEndpoint); - ~EndpointEntryView(); - - void SetSelected(bool selected); - - Endpoint* GetEndpoint() const; - - Q_SIGNALS: - void selectSignal(EndpointEntryView* pEndpointView); - void deleteSignal(EndpointEntryView* pEndpointView); - - private: - static const char* SELECTED_CSS; - static const char* UNSELECTED_CSS; - - QScopedPointer m_ui; - Endpoint* m_pEndpoint = nullptr; - - private Q_SLOTS: - void selectSlot(); - void deleteSlot(); - }; -} // namespace News diff --git a/Code/Tools/News/NewsBuilder/Qt/EndpointEntryView.ui b/Code/Tools/News/NewsBuilder/Qt/EndpointEntryView.ui deleted file mode 100644 index 309fcd5662..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/EndpointEntryView.ui +++ /dev/null @@ -1,87 +0,0 @@ - - - EndpointEntryViewWidget - - - - 0 - 0 - 356 - 23 - - - - - 0 - 23 - - - - - 16777215 - 23 - - - - Form - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - - 25 - 0 - - - - - 25 - 16777215 - - - - background-color: red; - - - X - - - - - - - - AzQtComponents::ExtendedLabel - QLabel -
AzQtComponents/Components/ExtendedLabel.h
-
-
- - -
diff --git a/Code/Tools/News/NewsBuilder/Qt/EndpointManagerView.cpp b/Code/Tools/News/NewsBuilder/Qt/EndpointManagerView.cpp deleted file mode 100644 index e28245b895..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/EndpointManagerView.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "EndpointManagerView.h" -#include "EndpointManager.h" -#include "EndpointEntryView.h" -#include "Qt/ui_EndpointManagerView.h" -#include "Qt/QCustomMessageBox.h" -#include "ResourceManagement/BuilderResourceManifest.h" - -#include - -namespace News -{ - - EndpointManagerView::EndpointManagerView(QWidget* parent, - BuilderResourceManifest& manifest) - : QDialog(parent) - , m_ui(new Ui::EndpointManagerViewWidget) - , m_pManager(manifest.GetEndpointManager()) - , m_manifest(manifest) - { - m_ui->setupUi(this); - - for (auto endpoint : *m_pManager) - { - auto endpointView = AddEndpointEntry(endpoint); - if (m_pManager->GetSelectedEndpoint() == endpoint) - { - selectEndpointSlot(endpointView); - } - } - - connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - connect(m_ui->buttonAdd, &QPushButton::clicked, this, &EndpointManagerView::addEndpointSlot); - } - - EndpointManagerView::~EndpointManagerView() {} - - EndpointEntryView* EndpointManagerView::AddEndpointEntry(Endpoint* pEndpoint) - { - auto endpointView = new EndpointEntryView(m_ui->endpointListContents, pEndpoint); - auto layout = static_cast(m_ui->endpointListContents->layout()); - layout->insertWidget(layout->count() - 2, endpointView); - m_endpoints.append(endpointView); - connect(endpointView, SIGNAL(selectSignal(EndpointEntryView*)), - this, SLOT(selectEndpointSlot(EndpointEntryView*))); - connect(endpointView, SIGNAL(deleteSignal(EndpointEntryView*)), - this, SLOT(deleteEndpointSlot(EndpointEntryView*))); - // this lets us modify newly-added widget in the same function - qApp->processEvents(); - return endpointView; - } - - void EndpointManagerView::Update() const - { - if (m_pSelectedEndpoint) - { - auto pEndpoint = m_pSelectedEndpoint->GetEndpoint(); - pEndpoint->SetName(m_ui->nameText->text()); - pEndpoint->SetAwsProfile(m_ui->awsProfileText->text()); - pEndpoint->SetUrl(m_ui->urlText->text()); - pEndpoint->SetBucket(m_ui->bucketText->text()); - m_pManager->SelectEndpoint(m_pSelectedEndpoint->GetEndpoint()); - } - m_pManager->Save(); - } - - void EndpointManagerView::accept() - { - enum SyncResponse - { - Merge, ReplaceLocal, ReplaceRemote, Cancel - }; - enum YesNoResponse - { - Yes, No - }; - - QCustomMessageBox msgBox( - QCustomMessageBox::Question, - tr("Pull data from Endpoint"), - tr("You are changing an endpoint. " - "What would you like to do with the data on the current endpoint?\n\n" - "Merge - merge resources from the endpoint\n" - "Replace Local - overwrite local resources with endpoint resources\n" - "Replace Endpoint - overwrite endpoint resources with local resources\n" - "Cancel - undo endpoint selection" - ), - this); - msgBox.AddButton(tr("Merge"), Merge); - msgBox.AddButton(tr("Replace Local"), ReplaceLocal); - msgBox.AddButton(tr("Replace Endpoint"), ReplaceRemote); - msgBox.AddButton(tr("Cancel"), Cancel); - - switch (msgBox.exec()) - { - case Merge: - { - m_manifest.SetSyncType(SyncType::Merge); - m_manifest.PersistLocalResources(); - } - break; - case ReplaceLocal: - { - if (m_manifest.HasChanges()) - { - QCustomMessageBox msgBoxWarning( - QCustomMessageBox::Critical, - tr("Unsaved changes"), - tr("Local resources were modified but not published." - "Changing endpoints will cause unpublished work to be lost.\n\n" - "Would you like to proceed?"), - this); - msgBoxWarning.AddButton(tr("Yes"), Yes); - msgBoxWarning.AddButton(tr("No"), No); - if (msgBoxWarning.exec() == No) - { - return; - } - } - m_manifest.SetSyncType(SyncType::Merge); - m_manifest.Reset(); - } - break; - case ReplaceRemote: - { - QCustomMessageBox msgBoxWarning2( - QCustomMessageBox::Critical, - tr("Warning"), - tr("This operation will IRREVERSABLY replace ALL resources on ") + - m_pSelectedEndpoint->GetEndpoint()->GetName() + - tr(" endpoint with local data.\n\n" - "Are you sure you'd like to proceed?"), - this); - msgBoxWarning2.AddButton(tr("Yes"), Yes); - msgBoxWarning2.AddButton(tr("No"), No); - if (msgBoxWarning2.exec() == No) - { - return; - } - m_manifest.SetSyncType(SyncType::Overwrite); - m_manifest.PersistLocalResources(); - } - break; - case Cancel: - return; - } - - Update(); - - QDialog::accept(); - } - - void EndpointManagerView::addEndpointSlot() - { - auto pEndpoint = new Endpoint( - QObject::tr("New endpoint"), - QObject::tr("Enter AWS profile name"), - QObject::tr("Enter root URL"), - QObject::tr("Enter s3 bucket name")); - m_pManager->AddEndpoint(pEndpoint); - auto endpointView = AddEndpointEntry(pEndpoint); - selectEndpointSlot(endpointView); - } - - void EndpointManagerView::selectEndpointSlot(EndpointEntryView* pEndpointView) - { - m_pSelectedEndpoint = pEndpointView; - - for (auto view : m_endpoints) - { - view->SetSelected(view == pEndpointView); - } - - if (pEndpointView) - { - auto pEndpoint = pEndpointView->GetEndpoint(); - m_ui->nameText->setText(pEndpoint->GetName()); - m_ui->awsProfileText->setText(pEndpoint->GetAwsProfile()); - m_ui->urlText->setText(pEndpoint->GetUrl()); - m_ui->bucketText->setText(pEndpoint->GetBucket()); - } - else - { - m_ui->nameText->setText(""); - m_ui->awsProfileText->setText(""); - m_ui->urlText->setText(""); - m_ui->bucketText->setText(""); - } - } - - void EndpointManagerView::deleteEndpointSlot(EndpointEntryView* pEndpointView) - { - m_pManager->RemoveEndpoint(pEndpointView->GetEndpoint()); - m_endpoints.removeAll(pEndpointView); - - if (pEndpointView == m_pSelectedEndpoint) - { - if (m_endpoints.count() > 0) - { - selectEndpointSlot(m_endpoints[0]); - } - else - { - selectEndpointSlot(nullptr); - } - } - - delete pEndpointView; - } - - -#include "Qt/moc_EndpointManagerView.cpp" - -} diff --git a/Code/Tools/News/NewsBuilder/Qt/EndpointManagerView.h b/Code/Tools/News/NewsBuilder/Qt/EndpointManagerView.h deleted file mode 100644 index c6362a06af..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/EndpointManagerView.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#endif - -namespace Ui -{ - class EndpointManagerViewWidget; -} - -namespace News -{ - class BuilderResourceManifest; - class Endpoint; - class EndpointEntryView; - class EndpointManager; - - //! Qt dialog for managing endpoints - class EndpointManagerView - : public QDialog - { - Q_OBJECT - public: - EndpointManagerView(QWidget* parent, - BuilderResourceManifest& manifest); - ~EndpointManagerView(); - - private: - QScopedPointer m_ui; - EndpointManager* m_pManager = nullptr; - EndpointEntryView* m_pSelectedEndpoint = nullptr; - QList m_endpoints; - BuilderResourceManifest& m_manifest; - - EndpointEntryView* AddEndpointEntry(Endpoint* pEndpoint); - void Update() const; - - private Q_SLOTS: - void accept() override; - void addEndpointSlot(); - void selectEndpointSlot(EndpointEntryView* pEndpoint); - void deleteEndpointSlot(EndpointEntryView* pEndpoint); - }; -} // namespace News diff --git a/Code/Tools/News/NewsBuilder/Qt/EndpointManagerView.ui b/Code/Tools/News/NewsBuilder/Qt/EndpointManagerView.ui deleted file mode 100644 index 5295e30616..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/EndpointManagerView.ui +++ /dev/null @@ -1,224 +0,0 @@ - - - EndpointManagerViewWidget - - - - 0 - 0 - 400 - 350 - - - - - 400 - 350 - - - - - 400 - 350 - - - - Change Endpoint - - - Qt::LeftToRight - - - - - - Qt::ScrollBarAlwaysOn - - - Qt::ScrollBarAlwaysOff - - - true - - - - - 0 - 0 - 363 - 189 - - - - - - - + - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - Name: - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 250 - 0 - - - - - - - - - - - - AWS Profile Name: - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 250 - 0 - - - - - - - - - - - - URL: - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 250 - 0 - - - - - - - - - - - - S3 Bucket - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 250 - 0 - - - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - diff --git a/Code/Tools/News/NewsBuilder/Qt/ImageItem.cpp b/Code/Tools/News/NewsBuilder/Qt/ImageItem.cpp deleted file mode 100644 index 1566b8309d..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/ImageItem.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "ImageItem.h" -#include "NewsShared/ResourceManagement/Resource.h" - -#include "Qt/ui_ImageItem.h" - -namespace News -{ - - const char* ImageItem::SELECTED_CSS = - "border: 4px solid; border-color: white; background-color: rgb(45, 45, 45);"; - const char* ImageItem::UN_SELECTED_CSS = - "background-color: rgb(45, 45, 45);"; - - ImageItem::ImageItem(Resource& resource) - : QWidget() - , m_ui(new Ui::ImageItemWidget) - , m_resource(resource) - { - m_ui->setupUi(this); - - QPixmap pixmap; - pixmap.loadFromData(m_resource.GetData()); - m_ui->ImageLabel->setPixmap(pixmap); - - connect(m_ui->ImageLabel, &AzQtComponents::ExtendedLabel::clicked, this, &ImageItem::imageClickedSlot); - } - - void ImageItem::imageClickedSlot() - { - emit selectSignal(this); - } - - ImageItem::~ImageItem() {} - - void ImageItem::SetSelect(bool selected) const - { - m_ui->ImageLabel->setStyleSheet(selected ? SELECTED_CSS : UN_SELECTED_CSS); - } - - Resource& ImageItem::GetResource() const - { - return m_resource; - } - -#include "Qt/moc_ImageItem.cpp" - -} diff --git a/Code/Tools/News/NewsBuilder/Qt/ImageItem.h b/Code/Tools/News/NewsBuilder/Qt/ImageItem.h deleted file mode 100644 index ba883bc736..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/ImageItem.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#endif - -namespace Ui -{ - class ImageItemWidget; -} - -namespace News { - class Resource; - - //! A clickable image in selectImage control - class ImageItem - : public QWidget - { - Q_OBJECT - public: - explicit ImageItem(Resource& resource); - ~ImageItem(); - - void SetSelect(bool selected) const; - Resource& GetResource() const; - - Q_SIGNALS: - void selectSignal(ImageItem* imageItem); - - private: - QScopedPointer m_ui; - const static char* SELECTED_CSS; - const static char* UN_SELECTED_CSS; - - Resource& m_resource; - private Q_SLOTS: - void imageClickedSlot(); - }; -} diff --git a/Code/Tools/News/NewsBuilder/Qt/ImageItem.ui b/Code/Tools/News/NewsBuilder/Qt/ImageItem.ui deleted file mode 100644 index 9aef880c10..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/ImageItem.ui +++ /dev/null @@ -1,65 +0,0 @@ - - - ImageItemWidget - - - - 0 - 0 - 200 - 200 - - - - - 200 - 200 - - - - - 200 - 200 - - - - Form - - - - 20 - - - 20 - - - 20 - - - 20 - - - - - - - - - 160 - 90 - - - - - - - - - AzQtComponents::ExtendedLabel1 - QLabel -
AzQtComponents/Components/ExtendedLabel.h
-
-
- - -
diff --git a/Code/Tools/News/NewsBuilder/Qt/LogContainer.cpp b/Code/Tools/News/NewsBuilder/Qt/LogContainer.cpp deleted file mode 100644 index 5efda641db..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/LogContainer.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "LogContainer.h" - -#include "Qt/ui_LogContainer.h" - -namespace News -{ - - LogContainer::LogContainer(QWidget* parent) - : QWidget(parent) - , m_ui(new Ui::LogContainerWidget) - { - m_ui->setupUi(this); - } - - LogContainer::~LogContainer() {} - - void LogContainer::AddLog(QString text, LogType logType) const { - QString color; - switch (logType) - { - case LogOk: - color = "green"; - break; - case LogInfo: - color = "white"; - break; - case LogError: - color = "red"; - break; - case LogWarning: - color = "yellow"; - break; - default: - color = "white"; - break; - } - auto fullText = QString("%2
").arg(color).arg(text); - m_ui->logText->setTextFormat(Qt::RichText); - m_ui->logText->setText(QString("%2%1").arg(m_ui->logText->text()).arg(fullText)); - } - -#include "Qt/moc_LogContainer.cpp" - -} diff --git a/Code/Tools/News/NewsBuilder/Qt/LogContainer.h b/Code/Tools/News/NewsBuilder/Qt/LogContainer.h deleted file mode 100644 index 8f46f3b406..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/LogContainer.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#endif - -namespace Ui -{ - class LogContainerWidget; -} - -namespace News -{ - //! A control for displaying log - class LogContainer - : public QWidget - { - Q_OBJECT - - public: - explicit LogContainer(QWidget* parent); - ~LogContainer(); - - void AddLog(QString text, LogType logType) const; - - private: - QScopedPointer m_ui; - }; -} // namespace News diff --git a/Code/Tools/News/NewsBuilder/Qt/LogContainer.ui b/Code/Tools/News/NewsBuilder/Qt/LogContainer.ui deleted file mode 100644 index 3757f52480..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/LogContainer.ui +++ /dev/null @@ -1,131 +0,0 @@ - - - LogContainerWidget - - - - 0 - 0 - 547 - 125 - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - LogContainer - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - true - - - - - 0 - 0 - 545 - 123 - - - - - 0 - 0 - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - background-color: rgb(45, 45, 45); - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - false - - - Qt::TextBrowserInteraction - - - - - - - - - - - - diff --git a/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.cpp b/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.cpp deleted file mode 100644 index 5cbb510dd6..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include -#include "NewsBuilder.h" -#include "Qt/ArticleDetails.h" -#include "Qt/BuilderArticleViewContainer.h" -#include "NewsShared/Qt/ArticleViewContainer.h" -#include "NewsShared/ResourceManagement/Resource.h" -#include "ResourceManagement/BuilderResourceManifest.h" -#include "ArticleDetailsContainer.h" -#include "LogContainer.h" -#include "EndpointManagerView.h" -#include "EndpointManager.h" -#include "Qt/QCustomMessageBox.h" - -#include -#include - -AZ_PUSH_DISABLE_WARNING(4251 4996, "-Wunknown-warning-option") -#include -AZ_POP_DISABLE_WARNING - -#include -#include -#include -#include - -#include "Qt/ui_Newsbuilder.h" - -namespace News -{ - NewsBuilder::NewsBuilder(QWidget* parent, const AZ::IO::PathView& engineRootPath) - : QMainWindow(parent) - , m_ui(new Ui::NewsBuilderClass()) - , m_manifest(new BuilderResourceManifest( - std::bind(&NewsBuilder::SyncSuccess, this), - std::bind(&NewsBuilder::SyncFail, this, std::placeholders::_1), - std::bind(&NewsBuilder::SyncUpdate, this, std::placeholders::_1, std::placeholders::_2))) - , m_articleDetailsContainer(new ArticleDetailsContainer(this, *m_manifest)) - , m_articleViewContainer(new BuilderArticleViewContainer(this, *m_manifest)) - , m_logContainer(new LogContainer(this)) - { - - AzQtComponents::StyleManager* m_styleSheet = new AzQtComponents::StyleManager(this); - m_styleSheet->initialize(qApp, engineRootPath); - - m_ui->setupUi(this); - - QDir rootDir = QString::fromUtf8(engineRootPath.Native().data(), aznumeric_cast(engineRootPath.Native().size())); - const auto pathOnDisk = rootDir.absoluteFilePath("Code/Tools/News/NewsBuilder/Resources"); - const auto qrcPath = QStringLiteral(":/NewsBuilder"); - AzQtComponents::StyleManager::addSearchPaths("newsbuilder", pathOnDisk, qrcPath, engineRootPath); - - AzQtComponents::StyleManager::setStyleSheet(this, QStringLiteral("newsbuilder:NewsBuilder.qss")); - - UpdateEndpointLabel(); - - m_ui->articleViewContainerRoot->layout()->addWidget(m_articleViewContainer); - m_ui->articleDetailsContainerRoot->layout()->addWidget(m_articleDetailsContainer); - m_ui->dockWidgetContents->layout()->addWidget(m_logContainer); - - connect(m_articleViewContainer, SIGNAL(articleSelectedSignal(QString)), - this, SLOT(selectArticleSlot(QString))); - connect(m_articleViewContainer, SIGNAL(logSignal(QString, LogType)), - this, SLOT(addLogSlot(QString, LogType))); - - connect(m_articleDetailsContainer, &ArticleDetailsContainer::updateArticleSignal, - this, &NewsBuilder::updateArticleSlot); - connect(m_articleDetailsContainer, &ArticleDetailsContainer::deleteArticleSignal, - this, &NewsBuilder::deleteArticleSlot); - connect(m_articleDetailsContainer, &ArticleDetailsContainer::orderChangedSignal, - this, &NewsBuilder::orderChangedSlot); - connect(m_articleDetailsContainer, &ArticleDetailsContainer::closeArticleSignal, - this, &NewsBuilder::closeArticleSlot); - connect(m_articleDetailsContainer, SIGNAL(logSignal(QString, LogType)), - this, SLOT(addLogSlot(QString, LogType))); - - m_manifest->SetSyncType(SyncType::Merge); - m_manifest->Sync(); - - // Sync Console pane with View menu - connect(m_ui->actionConsole, &QAction::triggered, this, &NewsBuilder::OnViewLogWindow); - connect(m_ui->dockWidget, &QDockWidget::visibilityChanged, this, &NewsBuilder::OnViewVisibilityChanged); - } - - NewsBuilder::~NewsBuilder() {} - - void NewsBuilder::selectArticleSlot(const QString& id) const - { - m_articleDetailsContainer->SelectArticle(id); - } - - void NewsBuilder::addLogSlot(QString text, LogType logType) const - { - AddLog(text, logType); - } - - void NewsBuilder::addArticleToBottomSlot() const - { - m_articleViewContainer->AddArticle(); - } - - void NewsBuilder::updateArticleSlot(QString id) const - { - m_articleViewContainer->UpdateArticle(id); - } - - void NewsBuilder::deleteArticleSlot(QString id) const - { - m_articleViewContainer->DeleteArticle(id); - } - - void NewsBuilder::closeArticleSlot(QString id) const - { - m_articleViewContainer->CloseArticle(id); - } - - void NewsBuilder::orderChangedSlot(QString id, bool direction) const - { - m_articleViewContainer->UpdateArticleOrder(id, direction); - } - - void NewsBuilder::openSlot() - { - EndpointManagerView endpointManagerView( - m_ui->centralWidget, - *m_manifest); - if (endpointManagerView.exec() == QDialog::Accepted) - { - m_manifest->Sync(); - } - UpdateEndpointLabel(); - } - - void NewsBuilder::publishSlot() - { - if (!m_manifest->HasChanges()) - { - QCustomMessageBox msgBox( - QCustomMessageBox::Information, - tr("Nothing to publish"), - tr("No local changes were made, nothing to publish."), - this); - msgBox.AddButton(tr("Good"), 0); - msgBox.exec(); - return; - } - - enum Response - { - Yes, No - }; - - QCustomMessageBox msgBox( - QCustomMessageBox::Critical, - tr("Publish resources"), - tr("You are about to overwrite the current Open 3D Engine Welcome Message. Are you sure you want to publish?"), - this); - msgBox.AddButton("Yes", Yes); - msgBox.AddButton("No", No); - if (msgBox.exec() == Yes) - { - m_manifest->SetSyncType(SyncType::Verify); - m_manifest->Sync(); - } - } - - void NewsBuilder::OnViewVisibilityChanged([[maybe_unused]] bool visibility) - { - UpdateViewMenu(); - } - - void NewsBuilder::UpdateViewMenu() - { - if (m_ui->actionConsole->isChecked() != m_ui->dockWidget->isVisible()) - { - QSignalBlocker signalBlocker(m_ui->actionConsole); - m_ui->actionConsole->setChecked(m_ui->dockWidget->isVisible()); - } - } - - void NewsBuilder::OnViewLogWindow() - { - if (m_ui->dockWidget) - { - m_ui->dockWidget->toggleViewAction()->trigger(); - } - } - - void NewsBuilder::UpdateEndpointLabel() - { - auto pEndpoint = m_manifest->GetEndpointManager()->GetSelectedEndpoint(); - if (pEndpoint) - { - this->setWindowTitle("News Builder (" + pEndpoint->GetName() + ")"); - } - else - { - this->setWindowTitle("News Builder (No endpoint selected)"); - } - } - - void NewsBuilder::AddLog(QString text, LogType logType) const - { - m_logContainer->AddLog(text, logType); - } - - void NewsBuilder::SyncUpdate(const QString& message, LogType logType) const - { - AddLog(message, logType); - } - - void NewsBuilder::SyncFail(ErrorCode error) - { - const char* errorMessage = GetErrorMessage(error); - AddLog(tr("Sync failed: %1").arg(errorMessage), LogError); - QCustomMessageBox msgBoxSyncFail( - QCustomMessageBox::Critical, - tr("Sync failed"), - errorMessage, - this); - msgBoxSyncFail.AddButton("Ok", 0); - msgBoxSyncFail.exec(); - - m_articleViewContainer->PopulateArticles(); - m_articleDetailsContainer->Reset(); - } - - void NewsBuilder::SyncSuccess() const - { - AddLog("Sync completed", LogOk); - m_articleViewContainer->PopulateArticles(); - m_articleDetailsContainer->Reset(); - } -#include "Qt/moc_NewsBuilder.cpp" - -} diff --git a/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.h b/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.h deleted file mode 100644 index 61e25bda1b..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/NewsBuilder.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include - -#include "NewsShared/LogType.h" -#include "NewsShared/ErrorCodes.h" - -#include -#endif - -class QSignalMapper; -class QPushButton; - -namespace Ui -{ - class NewsBuilderClass; -} - -namespace News -{ - class BuilderArticleViewContainer; - class LogContainer; - class BuilderResourceManifest; - class ArticleDetailsContainer; - - //! A central control of News Builder. - class NewsBuilder - : public QMainWindow - { - Q_OBJECT - - public: - explicit NewsBuilder(QWidget* parent, const AZ::IO::PathView& engineRootPath); - ~NewsBuilder(); - - private: - QScopedPointer m_ui; - BuilderResourceManifest* m_manifest = nullptr; - ArticleDetailsContainer* m_articleDetailsContainer = nullptr; - BuilderArticleViewContainer* m_articleViewContainer = nullptr; - LogContainer* m_logContainer = nullptr; - - void UpdateEndpointLabel(); - void AddLog(QString text, LogType logType = LogInfo) const; - - void SyncUpdate(const QString& message, LogType logType) const; - void SyncFail(ErrorCode error); - void SyncSuccess() const; - - void OnViewVisibilityChanged(bool visibility); - void UpdateViewMenu(); - void OnViewLogWindow(); - - private Q_SLOTS: - void selectArticleSlot(const QString& id) const; - void addLogSlot(QString text, LogType logType) const; - void addArticleToBottomSlot() const; - void updateArticleSlot(QString id) const; - void deleteArticleSlot(QString id) const; - void closeArticleSlot(QString id) const; - void orderChangedSlot(QString id, bool direction) const; - void openSlot(); - void publishSlot(); - }; -} // namespace News diff --git a/Code/Tools/News/NewsBuilder/Qt/Newsbuilder.qrc b/Code/Tools/News/NewsBuilder/Qt/Newsbuilder.qrc deleted file mode 100644 index 768281fb12..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/Newsbuilder.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - ../Resources/missing-image.png - - diff --git a/Code/Tools/News/NewsBuilder/Qt/Newsbuilder.ui b/Code/Tools/News/NewsBuilder/Qt/Newsbuilder.ui deleted file mode 100644 index 55e7fe5b68..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/Newsbuilder.ui +++ /dev/null @@ -1,326 +0,0 @@ - - - NewsBuilderClass - - - - 0 - 0 - 800 - 540 - - - - - 0 - 480 - - - - - 1024 - 16777215 - - - - News Builder - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 800 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 480 - 0 - - - - - 16777215 - 16777215 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - 0 - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - - - - - - - - 0 - 0 - 800 - 21 - - - - - File - - - - - - - Article - - - - - - View - - - - - - - - - - - 0 - 0 - - - - - 63 - 66 - - - - QDockWidget::DockWidgetClosable - - - Qt::BottomDockWidgetArea - - - Console - - - 8 - - - - - 5 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - Change Endpoint - - - false - - - - - Publish Resources - - - false - - - - - Add to Bottom - - - - - Delete Selected - - - - - true - - - Console - - - - - - - AzQtComponents::StyledDockWidget - QDockWidget -
AzQtComponents/Components/StyledDockWidget.h
- 1 -
-
- - - - - - actionOpen - triggered() - NewsBuilderClass - openSlot() - - - -1 - -1 - - - 399 - 269 - - - - - actionPublish - triggered() - NewsBuilderClass - publishSlot() - - - -1 - -1 - - - 399 - 269 - - - - - actionAdd_New - triggered() - NewsBuilderClass - addArticleToBottomSlot() - - - -1 - -1 - - - 399 - 269 - - - - -
diff --git a/Code/Tools/News/NewsBuilder/Qt/QCustomMessageBox.cpp b/Code/Tools/News/NewsBuilder/Qt/QCustomMessageBox.cpp deleted file mode 100644 index 1b92f91e42..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/QCustomMessageBox.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "QCustomMessageBox.h" -#include "Qt/ui_QCustomMessageBox.h" - -#include -#include -#include - -namespace News -{ - - QCustomMessageBox::QCustomMessageBox( - Icon icon, - const QString& title, - const QString& text, - QWidget* parent) - : QDialog(parent, Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint) - , m_ui(new Ui::CustomMessageBoxDialog) - { - m_ui->setupUi(this); - - m_signalMapper = new QSignalMapper(this); - - this->setWindowTitle(title); - m_ui->labelText->setText(text); - - QStyle* style = QApplication::style(); - QIcon tmpIcon; - switch (icon) - { - case Information: - tmpIcon = style->standardIcon(QStyle::SP_MessageBoxInformation); - break; - case Warning: - tmpIcon = style->standardIcon(QStyle::SP_MessageBoxWarning); - break; - case Critical: - tmpIcon = style->standardIcon(QStyle::SP_MessageBoxCritical); - break; - case Question: - tmpIcon = style->standardIcon(QStyle::SP_MessageBoxQuestion); - default: - break; - } - if (!tmpIcon.isNull()) - { - QLabel* iconLabel = new QLabel(this); - iconLabel->setPixmap(tmpIcon.pixmap(64, 64)); - m_ui->bodyLayout->insertWidget(0, iconLabel); - } - - connect(m_signalMapper, SIGNAL(mapped(int)), - this, SLOT(clickedSlot(int))); - } - - QCustomMessageBox::~QCustomMessageBox() - { - delete m_signalMapper; - } - - void QCustomMessageBox::AddButton(const QString& name, int result) - { - auto button = new QPushButton(name, this); - connect(button, SIGNAL(clicked()), m_signalMapper, SLOT(map())); - m_signalMapper->setMapping(button, result); - m_ui->buttonLayout->layout()->addWidget(button); - } - - void QCustomMessageBox::clickedSlot(int result) - { - done(result); - } - -#include "Qt/moc_QCustomMessageBox.cpp" - -} diff --git a/Code/Tools/News/NewsBuilder/Qt/QCustomMessageBox.h b/Code/Tools/News/NewsBuilder/Qt/QCustomMessageBox.h deleted file mode 100644 index 6cd6771514..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/QCustomMessageBox.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#endif - -class QSignalMapper; - -namespace Ui -{ - class CustomMessageBoxDialog; -} - -namespace News -{ - class ArticleDetails; - class BuilderResourceManifest; - class SelectImage; - class ResourceManifest; - class Resource; - - //! Allows to add custom buttons which is not well-supported by default QMessageBox - class QCustomMessageBox - : public QDialog - { - Q_OBJECT - - public: - enum Icon { - NoIcon = 0, - Information = 1, - Warning = 2, - Critical = 3, - Question = 4 - }; - - QCustomMessageBox( - Icon, - const QString& title, - const QString& text, - QWidget* parent); - ~QCustomMessageBox(); - - void AddButton(const QString& name, int result); - - private: - QScopedPointer m_ui; - QSignalMapper* m_signalMapper = nullptr; - - private Q_SLOTS: - void clickedSlot(int result); - }; -} // namespace News diff --git a/Code/Tools/News/NewsBuilder/Qt/QCustomMessageBox.ui b/Code/Tools/News/NewsBuilder/Qt/QCustomMessageBox.ui deleted file mode 100644 index c1fb5f40bf..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/QCustomMessageBox.ui +++ /dev/null @@ -1,84 +0,0 @@ - - - CustomMessageBoxDialog - - - - 0 - 0 - 102 - 43 - - - - - 0 - 0 - - - - Message Title - - - - - - - - - - - Message text - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - 0 - - - - - Qt::Horizontal - - - - 40 - 0 - - - - - - - - 10 - - - - - - - Qt::Horizontal - - - - 40 - 0 - - - - - - - - - - - diff --git a/Code/Tools/News/NewsBuilder/Qt/SelectImage.cpp b/Code/Tools/News/NewsBuilder/Qt/SelectImage.cpp deleted file mode 100644 index 7a9e427f4b..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/SelectImage.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "SelectImage.h" -#include "ImageItem.h" -#include "NewsShared/ResourceManagement/Resource.h" -#include "ResourceManagement/BuilderResourceManifest.h" - -#include "Qt/ui_SelectImage.h" - -namespace News -{ - - const int SelectImage::MAX_COLS = 2; - - SelectImage::SelectImage(const ResourceManifest& manifest) - : QDialog() - , m_ui(new Ui::SelectImageDialog) - , m_manifest(manifest) - { - m_ui->setupUi(this); - - auto layout = static_cast(m_ui->scrollAreaContents->layout()); - layout->setAlignment(Qt::AlignTop | Qt::AlignLeft); - int row = 0; - int col = 0; - //! read all image resources and populate the container - for (auto pResource : m_manifest) - { - if (pResource->GetType().compare("image") == 0) - { - auto imageItem = new ImageItem(*pResource); - connect(imageItem, &ImageItem::selectSignal, this, &SelectImage::ImageSelected); - layout->addWidget(imageItem, row, col, Qt::AlignLeft); - m_images.append(imageItem); - col++; - if (col >= MAX_COLS) - { - col = 0; - row++; - } - } - } - - connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); - } - - SelectImage::~SelectImage() {} - - Resource* SelectImage::GetSelected() const - { - return m_pSelected; - } - - void SelectImage::ImageSelected(ImageItem* imageItem) - { - for (auto image : m_images) - { - image->SetSelect(image == imageItem); - } - if (imageItem) - { - m_pSelected = &imageItem->GetResource(); - } - } - -#include "Qt/moc_SelectImage.cpp" - -} diff --git a/Code/Tools/News/NewsBuilder/Qt/SelectImage.h b/Code/Tools/News/NewsBuilder/Qt/SelectImage.h deleted file mode 100644 index 5fc80cfe5a..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/SelectImage.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#endif - -namespace Ui -{ - class SelectImageDialog; -} - -namespace News { - class ImageItem; - class Resource; - class ResourceManifest; - - //! Allows to select existing images for multiple messages without re-uploading same one - class SelectImage - : public QDialog - { - Q_OBJECT - public: - explicit SelectImage(const ResourceManifest& manifest); - ~SelectImage(); - - void Select(); - void Close(); - Resource* GetSelected() const; - - private: - const static int MAX_COLS; - QScopedPointer m_ui; - const ResourceManifest& m_manifest; - QList m_images; - Resource* m_pSelected = nullptr; - - void ImageSelected(ImageItem* imageItem); - }; -} // namespace News diff --git a/Code/Tools/News/NewsBuilder/Qt/SelectImage.ui b/Code/Tools/News/NewsBuilder/Qt/SelectImage.ui deleted file mode 100644 index 55b27bfb7f..0000000000 --- a/Code/Tools/News/NewsBuilder/Qt/SelectImage.ui +++ /dev/null @@ -1,106 +0,0 @@ - - - SelectImageDialog - - - Qt::ApplicationModal - - - - 0 - 0 - 439 - 406 - - - - Select Image - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::LeftToRight - - - Qt::ScrollBarAlwaysOff - - - true - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - 0 - 0 - 437 - 379 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 2 - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - diff --git a/Code/Tools/News/NewsBuilder/ResourceManagement/BuilderResourceManifest.cpp b/Code/Tools/News/NewsBuilder/ResourceManagement/BuilderResourceManifest.cpp deleted file mode 100644 index 0a845216fe..0000000000 --- a/Code/Tools/News/NewsBuilder/ResourceManagement/BuilderResourceManifest.cpp +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "BuilderResourceManifest.h" -#include "NewsShared/ResourceManagement/QtDownloadManager.h" -#include "NewsBuilder/S3Connector.h" -#include "UidGenerator.h" -#include "NewsShared/ResourceManagement/Resource.h" -#include "NewsBuilder/ResourceManagement/UploadDescriptor.h" -#include "NewsBuilder/ResourceManagement/DeleteDescriptor.h" -#include "NewsShared/ResourceManagement/ArticleDescriptor.h" -#include "NewsBuilder/ResourceManagement/ImageDescriptor.h" -#include "EndpointManager.h" - -#include -#include - -#include -#include - -namespace News { - - BuilderResourceManifest::BuilderResourceManifest( - std::function syncSuccessCallback, - std::function syncFailCallback, - std::function syncUpdateCallback) - : ResourceManifest(syncSuccessCallback, syncFailCallback, syncUpdateCallback) - , m_s3Connector(new S3Connector) - , m_uidGenerator(new UidGenerator) - , m_endpointManager(new EndpointManager) {} - - - Resource* BuilderResourceManifest::AddArticle() - { - auto pResource = new Resource( - QString("%1").arg(m_uidGenerator->GenerateUid()), - "article"); - QJsonObject json; - json["title"] = "New Article"; - json["body"] = "Enter article body here"; - json["imageId"] = "0"; - QJsonDocument doc(json); - QByteArray data = doc.toJson(QJsonDocument::Compact).toStdString().data(); - pResource->SetData(data); - m_toUpload.push(pResource); - AppendResource(pResource); - m_order.append(pResource->GetId()); - return pResource; - } - - Resource* BuilderResourceManifest::AddImage(const QString& filename) - { - auto pResource = new Resource( - QString("%1").arg(m_uidGenerator->GenerateUid()), - "image"); - ImageDescriptor descriptor(*pResource); - QString error; - if (!descriptor.Read(filename, error)) - { - m_syncUpdateCallback(error, LogError); - delete pResource; - return nullptr; - } - m_toUpload.push(pResource); - AppendResource(pResource); - return pResource; - } - - void BuilderResourceManifest::UpdateResource(Resource* pResource) - { - if (!m_toUpload.contains(pResource)) - { - pResource->SetVersion(pResource->GetVersion() + 1); - m_toUpload.push(pResource); - } - } - - void BuilderResourceManifest::UseResource(const QString& id) - { - auto pResource = FindById(id, m_resources); - if (!pResource) - { - return; - } - pResource->SetRefCount(pResource->GetRefCount() + 1); - UpdateResource(pResource); - } - - void BuilderResourceManifest::FreeResource(const QString& id) - { - auto pResource = FindById(id, m_resources); - if (!pResource) - { - return; - } - if (m_toDelete.contains(pResource)) - { - return; - } - pResource->SetRefCount(pResource->GetRefCount() - 1); - if (pResource->GetRefCount() <= 0) - { - m_toDelete.push(pResource); - RemoveResource(pResource); - m_toUpload.removeAll(pResource); - - if (pResource->GetType().compare("article") == 0) - { - m_order.removeAll(pResource->GetId()); - } - } - else - { - m_toUpload.push(pResource); - } - } - - bool BuilderResourceManifest::UpdateArticleOrder(const QString& id, bool direction, ErrorCode& error) - { - int index = m_order.indexOf(id); - if (index == -1) - { - m_syncUpdateCallback(QString("Couldn't find article: %1").arg(id), LogError); - error = ErrorCode::MissingArticle; - return false; - } - m_order.removeAll(id); - - index = index + (direction ? -1 : 1); - if (index < 0) - { - index = 0; - } - if (index > m_order.count()) - { - index = m_order.count(); - } - m_order.insert(index, id); - return true; - } - - EndpointManager* BuilderResourceManifest::GetEndpointManager() const - { - return m_endpointManager; - } - - void BuilderResourceManifest::Sync() - { - if (!m_endpointManager->GetSelectedEndpoint()) - { - FailSync(ErrorCode::NoEndpoint); - return; - } - if (!InitS3Connector()) - { - FailSync(ErrorCode::S3Fail); - return; - } - ResourceManifest::Sync(); - } - - void BuilderResourceManifest::Reset() - { - if (s_syncing) - { - m_syncUpdateCallback("Sync is already running", LogError); - return; - } - - m_toUpload.clear(); - - for (auto pResource : m_toDelete) - { - delete pResource; - } - m_toDelete.clear(); - - m_uidGenerator->Clear(); - - ResourceManifest::Reset(); - } - - void BuilderResourceManifest::PersistLocalResources() - { - // we are switching to another manifest here, while having the local data still present - // so we need to explicitly mark it for uploading so that it does not get deleted - for (auto pResource : m_resources) - { - if (!m_toUpload.contains(pResource)) - { - m_toUpload.push(pResource); - } - } - } - - void BuilderResourceManifest::SetSyncType(SyncType syncType) - { - m_syncType = syncType; - } - - bool BuilderResourceManifest::HasChanges() const - { - return m_toUpload.count() > 0 || m_toDelete.count() > 0; - } - - void BuilderResourceManifest::AppendResource(Resource* pResource) - { - m_uidGenerator->AddUid(pResource->GetId().toInt()); - ResourceManifest::AppendResource(pResource); - } - - void BuilderResourceManifest::RemoveResource(Resource* pResource) - { - m_uidGenerator->RemoveUid(pResource->GetId().toInt()); - ResourceManifest::RemoveResource(pResource); - } - - void BuilderResourceManifest::OnDownloadFail() - { - QMessageBox msgBox(QMessageBox::Critical, - "Sync failed", - QString("%1\n\n%2") - .arg(GetErrorMessage(ErrorCode::ManifestDownloadFail)) - .arg(QObject::tr("Overwrite resource manifest?")), - QMessageBox::Yes | QMessageBox::No); - if (msgBox.exec() == QMessageBox::Yes) - { - if (!UploadManifest()) - { - m_failed = true; - m_errorCode = ErrorCode::ManifestUploadFail; - } - } - ResourceManifest::OnDownloadFail(); - } - - //! This function overrides ResourceManifest Read and tries to do some minimal version checking - //! NOTE: version checking is not done yet, this needs a lot more work to version check properly - ErrorCode BuilderResourceManifest::Read(const QJsonObject& json) - { - int version = json["version"].toInt(); - if (version > m_version && m_syncType == SyncType::Verify) - { - return ErrorCode::OutOfSync; - } - - m_version = version; - QJsonArray resourceArray = json["resources"].toArray(); - - // initially mark ALL existing resource for deletion - QList toDelete = m_resources; - - for (auto resourceDoc : resourceArray) - { - auto pNewResource = new Resource(resourceDoc.toObject()); - // find local resource with the same id as new resource - auto pOldResource = FindById(pNewResource->GetId(), m_resources); - // if resource with the same id already exists then check its version - if (pOldResource) - { - // local resource is outdated, keep its in delete list, and download new one instead - if (pNewResource->GetVersion() > pOldResource->GetVersion()) - { - if (m_syncType == SyncType::Merge) - { - m_toDownload.push(pNewResource); - } - else if (m_syncType == SyncType::Overwrite) - { - m_toDelete.push(pNewResource); - } - } - // local resource is newer or same version, keep it (remove from toDelete list) - // and don't need to download new one - else - { - delete pNewResource; - toDelete.removeAll(pOldResource); - } - } - else - { - // if remote resource was NOT deleted locally then download it - if (!FindById(pNewResource->GetId(), m_toDelete)) - { - if (m_syncType == SyncType::Merge) - { - m_toDownload.push(pNewResource); - } - else if (m_syncType == SyncType::Overwrite) - { - m_toDelete.push(pNewResource); - } - } - // otherwise user deleted it... needs version check here - else - { - delete pNewResource; - } - } - } - - for (auto pResource : m_toUpload) - { - toDelete.removeAll(pResource); - } - - for (auto pResource : toDelete) - { - RemoveResource(pResource); - m_toDelete.removeAll(pResource); - delete pResource; - } - - //! Sync article display order - //! this is more complex to implement because articles may have been added or deleted - //! remotely by another developer while newsbuilder was running - //! for now just overwrite s3 version - QJsonArray orderArray = json["order"].toArray(); - for (auto idObject : orderArray) - { - QString id = idObject.toString(); - if (FindById(id, m_toDownload) && !m_order.contains(id)) - { - m_order.append(id); - } - } - return ErrorCode::None; - } - - //! Write resource manifest to JSON - void BuilderResourceManifest::Write(QJsonObject& json) const - { - QJsonArray resourceArray; - foreach(auto pResource, m_resources) - { - QJsonObject resourceObject; - pResource->Write(resourceObject); - resourceArray.append(resourceObject); - } - json["resources"] = resourceArray; - - QJsonArray orderArray; - foreach(auto id, m_order) - { - orderArray.append(id); - } - json["order"] = orderArray; - json["version"] = m_version; - } - - //! Figure out how many resources need to be synced - void BuilderResourceManifest::PrepareForSync() - { - // if resource is locally marked for deletion, then we don't need to upload/download it - for (auto pResource : m_toDelete) - { - m_toDownload.removeAll(pResource); - m_toUpload.removeAll(pResource); - } - - m_syncLeft = - m_toDownload.size() + - m_toUpload.size() + - m_toDelete.size(); - } - - void BuilderResourceManifest::SyncResources() - { - ResourceManifest::SyncResources(); - UploadResources(); - DeleteResources(); - } - - void BuilderResourceManifest::UploadResources() - { - QStack failures; - while (m_toUpload.count() > 0) - { - m_syncUpdateCallback( - QString("Uploading: %1 resources left").arg(m_toUpload.count()), - LogInfo); - - auto pResource = m_toUpload.pop(); - - auto uploadDescriptor = UploadDescriptor(*pResource); - uploadDescriptor.Upload(*m_s3Connector, - [&](QString url) - { - UpdateSync(); - }, - [&, pResource](QString error) - { - failures.push(pResource); - m_failed = true; - UpdateSync(); - m_syncUpdateCallback( - error, - LogError); - }); - } - while (failures.count() > 0) - { - m_toUpload.push(failures.pop()); - } - } - - void BuilderResourceManifest::DeleteResources() - { - while (m_toDelete.count() > 0) - { - m_syncUpdateCallback( - QString("Deleting: %1 resources left").arg(m_toDelete.count()), - LogInfo); - - auto pResource = m_toDelete.pop(); - - auto deleteDescriptor = DeleteDescriptor(*pResource); - deleteDescriptor.Delete(*m_s3Connector, - [&, pResource]() - { - delete pResource; - UpdateSync(); - }, - [&, pResource](QString error) - { - m_failed = true; - delete pResource; - UpdateSync(); - m_syncUpdateCallback( - QString("Failed to delete resource: %1").arg(error), - LogError); - }); - } - } - - void BuilderResourceManifest::FinishSync() - { - if (!m_failed) - { - QString error; - if (!UploadManifest()) - { - m_failed = true; - m_errorCode = ErrorCode::ManifestUploadFail; - } - } - ResourceManifest::FinishSync(); - } - - bool BuilderResourceManifest::UploadManifest() - { - m_syncUpdateCallback(QObject::tr("%1 to %2") - .arg("Uploading manifest") - .arg(m_endpointManager->GetSelectedEndpoint()->GetBucket()), - LogInfo); - m_version++; - Aws::String awsError; - QJsonObject manifestObject; - Write(manifestObject); - QJsonDocument doc(manifestObject); - auto ss = Aws::MakeShared( - S3Connector::ALLOCATION_TAG, - std::ios::in | std::ios::out | std::ios::binary); - *ss << QString(doc.toJson(QJsonDocument::Compact)).toStdString(); - Aws::String url; - if (!m_s3Connector->PutObject("resourceManifest", ss, url, awsError)) - { - m_syncUpdateCallback(QObject::tr(awsError.c_str()), LogError); - return false; - } - return true; - } - - bool BuilderResourceManifest::InitS3Connector() const - { - auto awsProfileName = - m_endpointManager->GetSelectedEndpoint()->GetAwsProfile(); - auto bucketName = - m_endpointManager->GetSelectedEndpoint()->GetBucket(); - Aws::String awsError; - if (!m_s3Connector->Init( - awsProfileName.toStdString().c_str(), - bucketName.toStdString().c_str(), - awsError)) - { - m_syncUpdateCallback(QObject::tr(awsError.c_str()), LogError); - return false; - } - return true; - } - -} diff --git a/Code/Tools/News/NewsBuilder/ResourceManagement/BuilderResourceManifest.h b/Code/Tools/News/NewsBuilder/ResourceManagement/BuilderResourceManifest.h deleted file mode 100644 index b6c20df571..0000000000 --- a/Code/Tools/News/NewsBuilder/ResourceManagement/BuilderResourceManifest.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include "NewsShared/ResourceManagement/ResourceManifest.h" - -#include - -class QJsonObject; - -namespace News -{ - class EndpointManager; - class ArticleDescriptor; - class UidGenerator; - class S3Connector; - class QtDownloadManager; - class Descriptor; - class DownloadDescriptor; - class Resource; - - //! Type of sync behavior - enum class SyncType - { - Merge, // merge resources from both endpoints, i.e. replacing outdated and appending missing (also normal sync behavior) - Overwrite, // overwrite resources on new endpoint with old endpoint - Verify // attempt to publish changes but abort if out of sync - }; - - //! Adds news-builder functionality layer to resource manager - class BuilderResourceManifest - : public ResourceManifest - { - public: - explicit BuilderResourceManifest( - std::function syncSuccessCallback, - std::function syncFailCallback, - std::function syncUpdateCallback); - - //! Create new article resource - /*! - Create new article with default parameters, - Add it to resource collection, - Mark it for upload. - - \retval Resource * - a pointer to an article Resource - */ - Resource* AddArticle(); - - //! Create new image resource - /*! - Create new image from file, - add it to resource collection, - mark it for upload. - - \param filename - path to an image on hard drive - \retval Resource * - a pointer to an image Resource - */ - Resource* AddImage(const QString& filename); - - //! If resource was modified, add it to upload list and increment its version - void UpdateResource(Resource* resource); - - //! When resource is used by several other resources, this function is called - //! to increment its ref count - void UseResource(const QString& id); - - //! When resource is no longer used by another resource - //! decrement refCount, - //! if nothing else is using it, then mark for delete - void FreeResource(const QString& id); - - //! Move article either up or down in order queue - bool UpdateArticleOrder(const QString& id, bool direction, ErrorCode& error); - - EndpointManager* GetEndpointManager() const; - - void Sync() override; - - void Reset() override; - - //! When switching endpoints Merge allows to persist resources to another endpoint, - //! thus copying news from one location to another upon next Sync - void PersistLocalResources(); - - void SetSyncType(SyncType syncType); - - //! Are there local changes - bool HasChanges() const; - - protected: - void AppendResource(Resource* pResource) override; - void RemoveResource(Resource* pResource) override; - void OnDownloadFail() override; - void FinishSync() override; - - private: - S3Connector* m_s3Connector = nullptr; - UidGenerator* m_uidGenerator = nullptr; - EndpointManager* m_endpointManager = nullptr; - SyncType m_syncType = SyncType::Merge; - - QStack m_toUpload; - QStack m_toDelete; - - ErrorCode Read(const QJsonObject& json) override; - void Write(QJsonObject& json) const; - - void PrepareForSync() override; - void SyncResources() override; - - void UploadResources(); - void DeleteResources(); - - bool UploadManifest(); - - //! Initializes S3 connector with selected endpoint - bool InitS3Connector() const; - }; -} // namespace News diff --git a/Code/Tools/News/NewsBuilder/ResourceManagement/DeleteDescriptor.cpp b/Code/Tools/News/NewsBuilder/ResourceManagement/DeleteDescriptor.cpp deleted file mode 100644 index 63cdb46218..0000000000 --- a/Code/Tools/News/NewsBuilder/ResourceManagement/DeleteDescriptor.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "DeleteDescriptor.h" -#include "NewsBuilder/S3Connector.h" -#include "NewsShared/ResourceManagement/Resource.h" - -#include - -namespace News -{ - - DeleteDescriptor::DeleteDescriptor(Resource& resource) - : Descriptor(resource) {} - - void DeleteDescriptor::Delete(S3Connector& s3Connector, - std::function deleteSuccessCallback, - std::function deleteFailCallback) const - { - Aws::String error; - if (!s3Connector.DeleteObject( - m_resource.GetId().toStdString().c_str(), - error)) - { - deleteFailCallback(QString("Error deleting resource %1: %2") - .arg(m_resource.GetId()) - .arg(error.c_str())); - } - else - { - deleteSuccessCallback(); - } - } - -} diff --git a/Code/Tools/News/NewsBuilder/ResourceManagement/DeleteDescriptor.h b/Code/Tools/News/NewsBuilder/ResourceManagement/DeleteDescriptor.h deleted file mode 100644 index 8928e9e19d..0000000000 --- a/Code/Tools/News/NewsBuilder/ResourceManagement/DeleteDescriptor.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include "NewsShared/ResourceManagement/Descriptor.h" - -#include -#include - -namespace News -{ - class S3Connector; - - class DeleteDescriptor - : public Descriptor - { - public: - explicit DeleteDescriptor(Resource& resource); - - void Delete(S3Connector& s3Connector, - std::function deleteSuccessCallback, - std::function deleteFailCallback) const; - }; -} diff --git a/Code/Tools/News/NewsBuilder/ResourceManagement/ImageDescriptor.cpp b/Code/Tools/News/NewsBuilder/ResourceManagement/ImageDescriptor.cpp deleted file mode 100644 index a16ec48851..0000000000 --- a/Code/Tools/News/NewsBuilder/ResourceManagement/ImageDescriptor.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "ImageDescriptor.h" -#include "NewsShared/ResourceManagement/Resource.h" - -#include -#include -#include -#include -#include - -namespace News -{ - - ImageDescriptor::ImageDescriptor( - Resource& resource) - : Descriptor(resource) - { - } - - bool ImageDescriptor::Read(const QString& filename, QString& error) const - { - QImageReader reader(filename); - if (!reader.canRead()) - { - error = reader.errorString(); - return false; - } - QImage image = reader.read(); - - QPixmap pixmap(filename); - QByteArray data; - QBuffer buffer(&data); - buffer.open(QIODevice::WriteOnly); - QFile test("test.png"); - if (pixmap.save(&buffer, "PNG")) - { - m_resource.SetData(data); - return true; - } - error = QString("failed to save image %1").arg(filename); - return false; - } - -} diff --git a/Code/Tools/News/NewsBuilder/ResourceManagement/ImageDescriptor.h b/Code/Tools/News/NewsBuilder/ResourceManagement/ImageDescriptor.h deleted file mode 100644 index ba4533b0c0..0000000000 --- a/Code/Tools/News/NewsBuilder/ResourceManagement/ImageDescriptor.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include - -class QString; - -namespace News -{ - class ImageDescriptor - : public Descriptor - { - public: - explicit ImageDescriptor(Resource& resource); - - bool Read(const QString& filename, QString& error) const; - }; -} diff --git a/Code/Tools/News/NewsBuilder/ResourceManagement/UploadDescriptor.cpp b/Code/Tools/News/NewsBuilder/ResourceManagement/UploadDescriptor.cpp deleted file mode 100644 index 699959ed85..0000000000 --- a/Code/Tools/News/NewsBuilder/ResourceManagement/UploadDescriptor.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "NewsBuilder/S3Connector.h" -#include "UploadDescriptor.h" -#include "NewsShared/ResourceManagement/Resource.h" - -#include -#include -#include - -#include - -namespace News -{ - - UploadDescriptor::UploadDescriptor(Resource& resource) - : Descriptor(resource) {} - - void UploadDescriptor::Upload(S3Connector& s3Connector, - std::function uploadSuccessCallback, - std::function uploadFailCallback) const - { - Aws::String error; - - auto ss = - Aws::MakeShared(S3Connector::ALLOCATION_TAG, - std::ios::in | std::ios::out | std::ios::binary); - auto* pbuf = ss->rdbuf(); - pbuf->sputn(m_resource.GetData().data(), m_resource.GetData().size()); - Aws::String awsUrl; - - if (!s3Connector.PutObject( - m_resource.GetId().toStdString().c_str(), - ss, - m_resource.GetData().size(), - awsUrl, - error)) - { - uploadFailCallback(QObject::tr("Error uploading resource %1: %2") - .arg(m_resource.GetId()) - .arg(error.c_str())); - } - else - { - uploadSuccessCallback(QString(awsUrl.c_str())); - } - } - -} diff --git a/Code/Tools/News/NewsBuilder/ResourceManagement/UploadDescriptor.h b/Code/Tools/News/NewsBuilder/ResourceManagement/UploadDescriptor.h deleted file mode 100644 index 71a7732c1e..0000000000 --- a/Code/Tools/News/NewsBuilder/ResourceManagement/UploadDescriptor.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include "NewsShared/ResourceManagement/Descriptor.h" - -#include -#include - -namespace News -{ - class S3Connector; - - class UploadDescriptor - : public Descriptor - { - public: - explicit UploadDescriptor(Resource& resource); - - void Upload(S3Connector& s3Connector, - std::function uploadSuccessCallback, - std::function uploadFailCallback) const; - }; -} diff --git a/Code/Tools/News/NewsBuilder/Resources/NewsBuilder.qss b/Code/Tools/News/NewsBuilder/Resources/NewsBuilder.qss deleted file mode 100644 index 01ca308585..0000000000 --- a/Code/Tools/News/NewsBuilder/Resources/NewsBuilder.qss +++ /dev/null @@ -1,44 +0,0 @@ -QLabel -{ - font-size: 12px; - color: #FFFFFF; - line-height: 20px; - background-color: transparent; - margin: 0; -} - -QLabel#titleLabel -{ - font-size: 22px; - line-height: 32px; -} - -QLabel#bodyLabel -{ - font-size: 14px; - line-height: 20px; -} - -QFrame#viewContainer[articleStyle="pinned"] -{ - background: rgba(180,139,255,5%); - border: 1px solid #B48BFF; - box-shadow: 0 0 4px 0 rgba(0,0,0,50%); -} - -QWidget#articleViewContainerRoot -{ - background: #222222; -} - -QScrollArea#previewArea, -QWidget#articleViewContents, -QFrame#imageFrame -{ - background-color: transparent; -} - -News--ArticleView.SelectedArticle > QWidget -{ - background: #333333; -} diff --git a/Code/Tools/News/NewsBuilder/Resources/missing-image.png b/Code/Tools/News/NewsBuilder/Resources/missing-image.png deleted file mode 100644 index 889493e628..0000000000 --- a/Code/Tools/News/NewsBuilder/Resources/missing-image.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4255a25636d77a54809592bc98bef47fa9044be03cd65d73daa821711489e00f -size 7379 diff --git a/Code/Tools/News/NewsBuilder/S3Connector.cpp b/Code/Tools/News/NewsBuilder/S3Connector.cpp deleted file mode 100644 index a54b6fa8f8..0000000000 --- a/Code/Tools/News/NewsBuilder/S3Connector.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "S3Connector.h" - -#include -#include -#include - - -AZ_PUSH_DISABLE_WARNING(4251 4819, "-Wunknown-warning-option") // Invalid character not in default code page -#include -#include -#include -#include -#include -#include -#include -#include -AZ_POP_DISABLE_WARNING - -namespace News -{ - const char* S3Connector::ALLOCATION_TAG = "NewsBuilder"; - - S3Connector::S3Connector() - : m_s3Client(nullptr) - , m_limiter(nullptr) - , m_valid(false) - { - } - - S3Connector::~S3Connector() {} - - bool S3Connector::Init(const char* awsProfileName, const char* bucket, Aws::String& error) - { - Aws::SDKOptions options; - options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Trace; - Aws::InitAPI(options); - - Aws::Client::ClientConfiguration config; - config.enableTcpKeepAlive = AZ_TRAIT_AZFRAMEWORK_AWS_ENABLE_TCP_KEEP_ALIVE_SUPPORTED; - config.scheme = Aws::Http::Scheme::HTTPS; - config.connectTimeoutMs = 30000; - config.requestTimeoutMs = 30000; - config.readRateLimiter = m_limiter; - config.writeRateLimiter = m_limiter; - - auto provider = - Aws::MakeShared( - ALLOCATION_TAG, - awsProfileName); - - auto accessKeyId = provider->GetAWSCredentials().GetAWSAccessKeyId(); - - //! verify that credential file exists - if (accessKeyId.empty()) - { - error = "LY_NEWS_DEVELOPER AWS credentials not found. Add credentials in LY Editor AWS->ClientManager"; - m_valid = false; - return false; - } - - m_bucket = Aws::String(bucket); - m_s3Client = Aws::MakeShared( - ALLOCATION_TAG, - provider, - config); - - m_valid = true; - return true; - } - - bool S3Connector::GetObject(const char* key, - Aws::String& data, - Aws::String& url, - Aws::String& error) const - { - if (!m_valid) - { - error = "Client not initialized"; - return false; - } - - Aws::S3::Model::GetObjectRequest getObjectRequest; - getObjectRequest.SetBucket(m_bucket); - getObjectRequest.SetKey(key); - auto outcome = m_s3Client->GetObject(getObjectRequest); - if (!outcome.IsSuccess()) - { - error = outcome.GetError().GetMessage(); - return false; - } - url = m_s3Client->GeneratePresignedUrl(m_bucket, key, Aws::Http::HttpMethod::HTTP_GET); - Aws::StringStream ss; - ss << outcome.GetResult().GetBody().rdbuf(); - data = ss.str(); - return true; - } - - bool S3Connector::PutObject(const char* key, - STREAM_PTR stream, - Aws::String& url, - Aws::String& error) const - { - return PutObject(key, stream, GetStreamLength(stream), url, error); - } - - bool S3Connector::PutObject(const char* key, - STREAM_PTR stream, - int length, - Aws::String& url, - Aws::String& error) const - { - if (!m_valid) - { - error = "Client not initialized"; - return false; - } - - Aws::S3::Model::PutObjectRequest putObjectRequest; - putObjectRequest.SetBucket(m_bucket); - putObjectRequest.SetBody(stream); - putObjectRequest.SetContentLength(length); - putObjectRequest.SetContentMD5( - Aws::Utils::HashingUtils::Base64Encode( - Aws::Utils::HashingUtils::CalculateMD5(*putObjectRequest.GetBody()))); - putObjectRequest.SetContentType(Aws::String("binary/octet-stream")); - putObjectRequest.SetKey(key); - putObjectRequest.SetACL(Aws::S3::Model::ObjectCannedACL::public_read); - auto outcome = m_s3Client->PutObject(putObjectRequest); - if (!outcome.IsSuccess()) - { - error = outcome.GetError().GetMessage(); - return false; - } - url = m_s3Client->GeneratePresignedUrl(m_bucket, key, Aws::Http::HttpMethod::HTTP_GET); - return true; - } - - bool S3Connector::DeleteObject(const char* key, Aws::String& error) const - { - if (!m_valid) - { - error = "Client not initialized"; - return false; - } - - Aws::S3::Model::DeleteObjectRequest deleteObjectRequest; - deleteObjectRequest.SetBucket(m_bucket); - deleteObjectRequest.SetKey(key); - auto outcome = m_s3Client->DeleteObject(deleteObjectRequest); - if (!outcome.IsSuccess()) - { - error = outcome.GetError().GetMessage(); - return false; - } - return true; - } - - int S3Connector::GetStreamLength(STREAM_PTR stream) - { - stream->seekg(0, std::ios::end); - auto length = stream->tellg(); - stream->seekg(0, std::ios::beg); - return static_cast(length); - } - -} diff --git a/Code/Tools/News/NewsBuilder/S3Connector.h b/Code/Tools/News/NewsBuilder/S3Connector.h deleted file mode 100644 index d0404bfddb..0000000000 --- a/Code/Tools/News/NewsBuilder/S3Connector.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -AZ_PUSH_DISABLE_WARNING(4251 4355 4996, "-Wunknown-warning-option") // includes ppltasks.h which throws a C4355 warning: 'this' used in base member initializer list -#include -AZ_POP_DISABLE_WARNING - -typedef std::shared_ptr STREAM_PTR; - -namespace News -{ - //! A light wrapper around AWS SDK - class S3Connector - { - public: - static const char* ALLOCATION_TAG; - - S3Connector(); - ~S3Connector(); - - //! Make s3 client using credentials stored in [user]/.aws/credentials file - /*! - \param awsProfileName - name of AWS credentials - \param bucket - name of s3 bucket to use for AWS operations - \param error - error string - \retval bool - true if success else false - */ - bool Init(const char* awsProfileName, const char* bucket, Aws::String& error); - - bool GetObject(const char* key, - Aws::String& data, - Aws::String& url, - Aws::String& error) const; - - bool PutObject(const char* key, - STREAM_PTR stream, - Aws::String& url, - Aws::String& error) const; - - bool PutObject(const char* key, - STREAM_PTR stream, - int length, - Aws::String& url, - Aws::String& error) const; - - bool DeleteObject(const char* key, - Aws::String& error) const; - - private: - Aws::String m_bucket; - std::shared_ptr m_s3Client; - std::shared_ptr m_limiter; - bool m_valid; - - static int GetStreamLength(STREAM_PTR stream); - }; -} // namespace News diff --git a/Code/Tools/News/NewsBuilder/UidGenerator.cpp b/Code/Tools/News/NewsBuilder/UidGenerator.cpp deleted file mode 100644 index 060f593996..0000000000 --- a/Code/Tools/News/NewsBuilder/UidGenerator.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "UidGenerator.h" - -#include - -namespace News -{ - - UidGenerator::UidGenerator() - { - srand(static_cast(time(nullptr))); - } - - int UidGenerator::GenerateUid() - { - int uid; - do - { - uid = rand(); - } - while (std::find(m_uids.begin(), m_uids.end(), uid) != m_uids.end()); - m_uids.push_back(uid); - return uid; - } - - int UidGenerator::AddUid(int uid) - { - if (std::find(m_uids.begin(), m_uids.end(), uid) == m_uids.end()) - { - m_uids.push_back(uid); - } - return uid; - } - - void UidGenerator::RemoveUid(int uid) - { - auto it = std::find(m_uids.begin(), m_uids.end(), uid); - if (it != m_uids.end()) - { - m_uids.erase(it); - } - } - - void UidGenerator::Clear() - { - m_uids.clear(); - } - -} diff --git a/Code/Tools/News/NewsBuilder/UidGenerator.h b/Code/Tools/News/NewsBuilder/UidGenerator.h deleted file mode 100644 index 825df9e340..0000000000 --- a/Code/Tools/News/NewsBuilder/UidGenerator.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include - -namespace News -{ - //! A simple unique id generator. - class UidGenerator - { - public: - UidGenerator(); - int GenerateUid(); - int AddUid(int uid); - void RemoveUid(int uid); - void Clear(); - - private: - std::vector m_uids; - }; -} diff --git a/Code/Tools/News/NewsBuilder/main.cpp b/Code/Tools/News/NewsBuilder/main.cpp deleted file mode 100644 index 6a43c681b1..0000000000 --- a/Code/Tools/News/NewsBuilder/main.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include -#include - -#include "Qt/NewsBuilder.h" -#include -#include -#include -#include - - -int main(int argc, char *argv[]) -{ - // Must be set before QApplication is initialized, so that we support HighDpi monitors, like the Retina displays - // on Windows 10 - QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); - QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough); - - QApplication a(argc, argv); - AZ::IO::FixedMaxPath engineRootPath; - { - AZ::ComponentApplication componentApplication; - auto settingsRegistry = AZ::SettingsRegistry::Get(); - settingsRegistry->Get(engineRootPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder); - } - News::NewsBuilder w(nullptr, engineRootPath); - w.show(); - return a.exec(); -} diff --git a/Code/Tools/News/NewsBuilder/news_builder.qrc b/Code/Tools/News/NewsBuilder/news_builder.qrc deleted file mode 100644 index 010ac598f1..0000000000 --- a/Code/Tools/News/NewsBuilder/news_builder.qrc +++ /dev/null @@ -1,5 +0,0 @@ - - - Resources/NewsBuilder.qss - - diff --git a/Code/Tools/News/NewsBuilder/news_builder_files.cmake b/Code/Tools/News/NewsBuilder/news_builder_files.cmake deleted file mode 100644 index c46e66a357..0000000000 --- a/Code/Tools/News/NewsBuilder/news_builder_files.cmake +++ /dev/null @@ -1,64 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -set(FILES - main.cpp - S3Connector.cpp - S3Connector.h - UidGenerator.cpp - UidGenerator.h - EndpointManager.cpp - EndpointManager.h - Qt/ArticleDetails.cpp - Qt/ArticleDetails.h - Qt/ArticleDetails.ui - Qt/ArticleDetailsContainer.cpp - Qt/ArticleDetailsContainer.h - Qt/ArticleDetailsContainer.ui - Qt/AwsDialog.ui - Qt/BuilderArticleViewContainer.cpp - Qt/BuilderArticleViewContainer.h - Qt/BuilderArticleViewContainer.ui - Qt/EndpointEntryView.cpp - Qt/EndpointEntryView.h - Qt/EndpointEntryView.ui - Qt/EndpointManagerView.cpp - Qt/EndpointManagerView.h - Qt/EndpointManagerView.ui - Qt/ImageItem.cpp - Qt/ImageItem.h - Qt/ImageItem.ui - Qt/LogContainer.cpp - Qt/LogContainer.h - Qt/LogContainer.ui - Qt/NewsBuilder.cpp - Qt/NewsBuilder.h - Qt/Newsbuilder.qrc - Qt/Newsbuilder.ui - Qt/QCustomMessageBox.cpp - Qt/QCustomMessageBox.h - Qt/QCustomMessageBox.ui - Qt/SelectImage.cpp - Qt/SelectImage.h - Qt/SelectImage.ui - ResourceManagement/BuilderResourceManifest.cpp - ResourceManagement/BuilderResourceManifest.h - ResourceManagement/DeleteDescriptor.cpp - ResourceManagement/DeleteDescriptor.h - ResourceManagement/ImageDescriptor.cpp - ResourceManagement/ImageDescriptor.h - ResourceManagement/UploadDescriptor.cpp - ResourceManagement/UploadDescriptor.h -) - -set(SKIP_UNITY_BUILD_INCLUSION_FILES - # Fix for unity causing the 'News::BuilderResourceManifest::UpdateResourceA' symbol to be unresolved - Qt/ArticleDetails.cpp - # Fix for unity causing the ' Aws::S3::S3Client::GetObjectA' symbol to be unresolved - S3Connector.cpp - -) diff --git a/Code/Tools/News/NewsShared/ErrorCodes.h b/Code/Tools/News/NewsShared/ErrorCodes.h deleted file mode 100644 index 444e0c6f67..0000000000 --- a/Code/Tools/News/NewsShared/ErrorCodes.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include - -namespace News -{ - enum class ErrorCode : int - { - None, - OutOfSync, - ManifestDownloadFail, - FailedToSync, - AlreadySyncing, - FailedToParseManifest, - MissingArticle, - NoEndpoint, - ManifestUploadFail, - S3Fail - }; - - inline extern const char* GetErrorMessage(ErrorCode errorCode) - { - static const char* errors[] - { - "", - "Your manifest is out of sync. Reopen the same endpoint and sync to resolve the conflict and try again.", - "Failed to download resource manifest", - "Failed to sync resources", - "Sync is already running", - "Failed to parse resource manifest", - "Could not find article, try syncing again", - "Missing or incorrect endpoint selected", - "Failed to upload resource manifest", - "Failed to init S3 connection" - }; - int errorCount = sizeof errors / sizeof errors[0]; - int typeIndex = static_cast(errorCode); - if (typeIndex < 0 || typeIndex >= errorCount) - { - return "Invalid error code"; - } - return errors[typeIndex]; - } -} // namespace News diff --git a/Code/Tools/News/NewsShared/LogType.h b/Code/Tools/News/NewsShared/LogType.h deleted file mode 100644 index 92834adc58..0000000000 --- a/Code/Tools/News/NewsShared/LogType.h +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -namespace News { - enum LogType - { - LogOk, - LogInfo, - LogError, - LogWarning - }; -} // namespace News diff --git a/Code/Tools/News/NewsShared/Qt/ArticleErrorView.cpp b/Code/Tools/News/NewsShared/Qt/ArticleErrorView.cpp deleted file mode 100644 index 6f2a7e3c9c..0000000000 --- a/Code/Tools/News/NewsShared/Qt/ArticleErrorView.cpp +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "ArticleErrorView.h" -#include "NewsShared/Qt/ui_ArticleErrorView.h" - -using namespace News; - -ArticleErrorView::ArticleErrorView( - QWidget* parent) - : QWidget(parent) - , m_ui(new Ui::ArticleErrorViewWidget()) -{ - m_ui->setupUi(this); -} - -ArticleErrorView::~ArticleErrorView(){} - -#include "NewsShared/Qt/moc_ArticleErrorView.cpp" diff --git a/Code/Tools/News/NewsShared/Qt/ArticleErrorView.h b/Code/Tools/News/NewsShared/Qt/ArticleErrorView.h deleted file mode 100644 index 3130690dc1..0000000000 --- a/Code/Tools/News/NewsShared/Qt/ArticleErrorView.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#endif - -namespace Ui -{ - class ArticleErrorViewWidget; -} - -namespace AzQtComponents -{ - class ExtendedLabel; -} - -namespace News -{ - class ArticleErrorView - : public QWidget - { - Q_OBJECT - public: - ArticleErrorView(QWidget* parent); - ~ArticleErrorView(); - - private: - QScopedPointer m_ui; - }; -} diff --git a/Code/Tools/News/NewsShared/Qt/ArticleErrorView.ui b/Code/Tools/News/NewsShared/Qt/ArticleErrorView.ui deleted file mode 100644 index c94c636720..0000000000 --- a/Code/Tools/News/NewsShared/Qt/ArticleErrorView.ui +++ /dev/null @@ -1,239 +0,0 @@ - - - ArticleErrorViewWidget - - - - 0 - 0 - 192 - 228 - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - ArticleView - - - background-color: none; text-align: left; - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - border: none; - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 14 - - - - - - - - 0 - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 14 - 20 - - - - - - - - 0 - - - - - - 160 - 90 - - - - - - - :/images/Resources/ErrorImage.jpg - - - - 160 - 90 - - - - - - - - Qt::Vertical - - - - 20 - 20 - - - - - - - - - 0 - 0 - - - - - Open Sans - 8 - 50 - false - - - - a { text-decoration: underline; color: red } - - - We couldn’t connect to the network or access our news database. To see the latest Open 3D Engine news, blogs, tutorials, and more, please visit the <a href="http://aws.amazon.com/lumberyard/">Lumberyard website</a>. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - true - - - Qt::LinksAccessibleByMouse - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 14 - 20 - - - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 10 - - - - - - - - - - - - AzQtComponents::ExtendedLabel - QLabel -
AzQtComponents/Components/ExtendedLabel.h
-
-
- - - - -
diff --git a/Code/Tools/News/NewsShared/Qt/ArticleView.cpp b/Code/Tools/News/NewsShared/Qt/ArticleView.cpp deleted file mode 100644 index 082a29d38a..0000000000 --- a/Code/Tools/News/NewsShared/Qt/ArticleView.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "ArticleView.h" - -#include - -AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 4251: '...' needs to have dll-interface to be used by clients of class '...' -#include "NewsShared/ResourceManagement/ArticleDescriptor.h" -#include "NewsShared/Qt/ui_ArticleView.h" -#include "NewsShared/Qt/ui_PinnedArticleView.h" -#include "NewsShared/ResourceManagement/ResourceManifest.h" -#include "NewsShared/ResourceManagement/Resource.h" - - -#include -#include -AZ_POP_DISABLE_WARNING - -using namespace News; - -ArticleView::ArticleView( - QWidget* parent, - const ArticleDescriptor& article, - const ResourceManifest& manifest) - : QWidget(parent) - , m_pArticle(new ArticleDescriptor(article)) - , m_manifest(manifest) - , m_icon(nullptr) -{ - -} - -void ArticleView::Update() -{ - Q_ASSERT(m_widgetImageFrame && m_widgetTitle && m_widgetBody); - - auto pResource = m_manifest.FindById(m_pArticle->GetResource().GetId()); - m_pArticle.reset(); - if (pResource) - { - m_pArticle = QSharedPointer(new ArticleDescriptor(*pResource)); - m_widgetTitle->setText(m_pArticle->GetTitle()); - m_widgetBody->setText(m_pArticle->GetBody()); - auto pImageResource = m_manifest.FindById(m_pArticle->GetImageId()); - if (pImageResource) - { - QPixmap pixmap; - if (pixmap.loadFromData(pImageResource->GetData())) - { - if (!m_icon) - { - m_icon = new AzQtComponents::ExtendedLabel(this); - m_icon->setStyleSheet("border: none;"); - m_icon->setAlignment(Qt::AlignCenter); - static_cast( - m_widgetImageFrame->layout())->insertWidget(0, m_icon); - connect(m_icon, &AzQtComponents::ExtendedLabel::clicked, this, &ArticleView::articleSelectedSlot); - } - m_icon->setPixmap(pixmap.scaled(m_widgetImageFrame->minimumWidth(), - m_widgetImageFrame->minimumHeight(), - Qt::KeepAspectRatioByExpanding)); - } - else - { - RemoveIcon(); - } - } - else - { - RemoveIcon(); - } - } -} - -void ArticleView::mousePressEvent([[maybe_unused]] QMouseEvent* event) -{ - articleSelectedSlot(); -} - -void ArticleView::RemoveIcon() -{ - if (m_icon) - { - delete m_icon; - m_icon = nullptr; - } -} - -void ArticleView::linkActivatedSlot(const QString& link) -{ - QDesktopServices::openUrl(QUrl(link)); - Q_EMIT linkActivatedSignal(link); -} - -void ArticleView::articleSelectedSlot() -{ - Q_EMIT articleSelectedSignal(m_pArticle->GetResource().GetId()); -} - -QSharedPointer ArticleView::GetArticle() const -{ - return m_pArticle; -} - -void ArticleView::SetupViewWidget(QFrame* widgetImageFrame, AzQtComponents::ExtendedLabel* widgetTitle, AzQtComponents::ExtendedLabel* widgetBody) -{ - Q_ASSERT(m_widgetImageFrame == nullptr && m_widgetTitle == nullptr && m_widgetBody == nullptr); - - m_widgetImageFrame = widgetImageFrame; - m_widgetTitle = widgetTitle; - m_widgetBody = widgetBody; - - connect(m_widgetTitle, &QLabel::linkActivated, this, &ArticleView::linkActivatedSlot); - connect(m_widgetBody, &QLabel::linkActivated, this, &ArticleView::linkActivatedSlot); - connect(m_widgetTitle, &AzQtComponents::ExtendedLabel::clicked, this, &ArticleView::articleSelectedSlot); - connect(m_widgetBody, &AzQtComponents::ExtendedLabel::clicked, this, &ArticleView::articleSelectedSlot); - - Q_ASSERT(m_widgetImageFrame && m_widgetTitle && m_widgetBody); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// ArticleViewDefaultWidget -//////////////////////////////////////////////////////////////////////////////////////////////////// -ArticleViewDefaultWidget::ArticleViewDefaultWidget(QWidget* parent, - const ArticleDescriptor& article, - const ResourceManifest& manifest) - : ArticleView(parent, article, manifest) - , m_ui(new Ui::ArticleViewWidget()) -{ - m_ui->setupUi(this); - SetupViewWidget(m_ui->imageFrame, m_ui->titleLabel, m_ui->bodyLabel); - Update(); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// ArticleViewPinnedWidget -//////////////////////////////////////////////////////////////////////////////////////////////////// -ArticleViewPinnedWidget::ArticleViewPinnedWidget(QWidget* parent, - const ArticleDescriptor& article, - const ResourceManifest& manifest) - : ArticleView(parent, article, manifest) - , m_ui(new Ui::PinnedArticleViewWidget()) -{ - m_ui->setupUi(this); - SetupViewWidget(m_ui->imageFrame, m_ui->titleLabel, m_ui->bodyLabel); - Update(); -} - -#include "NewsShared/Qt/moc_ArticleView.cpp" diff --git a/Code/Tools/News/NewsShared/Qt/ArticleView.h b/Code/Tools/News/NewsShared/Qt/ArticleView.h deleted file mode 100644 index 16a29732f0..0000000000 --- a/Code/Tools/News/NewsShared/Qt/ArticleView.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#endif - -namespace Ui -{ - class ArticleViewWidget; - class PinnedArticleViewWidget; -} - -namespace AzQtComponents -{ - class ExtendedLabel; -} - -class QFrame; - -namespace News -{ - class ArticleDescriptor; - class ResourceManifest; - - class ArticleView - : public QWidget - { - Q_OBJECT - public: - ArticleView(QWidget* parent, - const ArticleDescriptor& article, - const ResourceManifest& manifest); - ~ArticleView() = default; - - void Update(); - QSharedPointer GetArticle() const; - - Q_SIGNALS: - void articleSelectedSignal(QString resourceId); - void linkActivatedSignal(const QString& link); - - protected: - void SetupViewWidget(QFrame* widgetImageFrame, AzQtComponents::ExtendedLabel* widgetTitle, AzQtComponents::ExtendedLabel* widgetBody); - void mousePressEvent(QMouseEvent* event); - - private: - - QFrame* m_widgetImageFrame = nullptr; - AzQtComponents::ExtendedLabel* m_widgetTitle = nullptr; - AzQtComponents::ExtendedLabel* m_widgetBody = nullptr; - AzQtComponents::ExtendedLabel* m_icon = nullptr; - - QSharedPointer m_pArticle; - const ResourceManifest& m_manifest; - - void RemoveIcon(); - - private Q_SLOTS: - void linkActivatedSlot(const QString& link); - void articleSelectedSlot(); - }; - - class ArticleViewDefaultWidget : public ArticleView - { - public: - ArticleViewDefaultWidget(QWidget* parent, - const ArticleDescriptor& article, - const ResourceManifest& manifest); - ~ArticleViewDefaultWidget() = default; - - private: - Ui::ArticleViewWidget* m_ui = nullptr; - }; - - class ArticleViewPinnedWidget : public ArticleView - { - public: - ArticleViewPinnedWidget(QWidget* parent, - const ArticleDescriptor& article, - const ResourceManifest& manifest); - ~ArticleViewPinnedWidget() = default; - - private: - Ui::PinnedArticleViewWidget* m_ui = nullptr; - }; -} diff --git a/Code/Tools/News/NewsShared/Qt/ArticleView.ui b/Code/Tools/News/NewsShared/Qt/ArticleView.ui deleted file mode 100644 index 67d1d8857b..0000000000 --- a/Code/Tools/News/NewsShared/Qt/ArticleView.ui +++ /dev/null @@ -1,244 +0,0 @@ - - - ArticleViewWidget - - - - 0 - 0 - 430 - 376 - - - - - 0 - 0 - - - - - 430 - 0 - - - - - 430 - 16777215 - - - - ArticleView - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - default - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 430 - 184 - - - - - 430 - 184 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 0 - 20 - - - - - - - - - 0 - 0 - - - - - Open Sans - 14 - 50 - false - - - - Title: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - false - - - Qt::LinksAccessibleByMouse - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 12 - - - - - - - - - 0 - 0 - - - - - Open Sans - 8 - 50 - false - - - - Body - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - 0 - - - 0 - - - false - - - Qt::LinksAccessibleByMouse - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 0 - 24 - - - - - - - - - - - - AzQtComponents::ExtendedLabel - QLabel -
AzQtComponents/Components/ExtendedLabel.h
-
-
- - -
diff --git a/Code/Tools/News/NewsShared/Qt/ArticleViewContainer.cpp b/Code/Tools/News/NewsShared/Qt/ArticleViewContainer.cpp deleted file mode 100644 index 1d718d1bb8..0000000000 --- a/Code/Tools/News/NewsShared/Qt/ArticleViewContainer.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "ArticleViewContainer.h" -#include "ArticleView.h" -#include "NewsShared/ResourceManagement/ResourceManifest.h" -#include "NewsShared/ResourceManagement/ArticleDescriptor.h" -#include "NewsShared/ResourceManagement/Resource.h" -#include "NewsShared/Qt/ArticleErrorView.h" -#include "NewsShared/Qt/KeepInTouchView.h" -#include "NewsShared/Qt/ui_ArticleViewContainer.h" - -#include -#include - -namespace News -{ - - ArticleViewContainer::ArticleViewContainer(QWidget* parent, ResourceManifest& manifest) - : QWidget(parent) - , m_ui(new Ui::ArticleViewContainerWidget) - , m_manifest(manifest) - , m_loadingLabel(nullptr) - , m_errorMessage(nullptr) - { - m_ui->setupUi(this); - AddLoadingMessage(); - - m_keepInTouchViewWidget = new KeepInTouchView(this); - m_keepInTouchViewWidget->setVisible(false); - connect(m_keepInTouchViewWidget, &KeepInTouchView::linkActivatedSignal, - this, &ArticleViewContainer::linkActivatedSignal); - } - - ArticleViewContainer::~ArticleViewContainer() {} - - void ArticleViewContainer::PopulateArticles() - { - Clear(); - - bool articlesFound = false; - for (auto id : m_manifest.GetOrder()) - { - auto pResource = m_manifest.FindById(id); - if (pResource && pResource->GetType().compare("article") == 0) - { - AddArticleView(ArticleDescriptor(*pResource)); - articlesFound = true; - } - } - - if (!articlesFound) - { - AddErrorMessage(); - } - else - { - auto layout = static_cast(m_ui->articleViewContents->layout()); - layout->insertWidget(layout->count() - 1, m_keepInTouchViewWidget); - m_keepInTouchViewWidget->setVisible(true); - } - - qApp->processEvents(); - } - - ArticleView* ArticleViewContainer::FindById(const QString& id) - { - auto it = std::find_if( - m_articles.begin(), - m_articles.end(), - [id](ArticleView* articleView) -> bool - { - if (!articleView) - { - return false; - } - return articleView->GetArticle()->GetResource().GetId().compare(id) == 0; - }); - if (it == m_articles.end()) - { - return nullptr; - } - return *it; - } - - void ArticleViewContainer::AddArticleView(const ArticleDescriptor& articleDesc, int articlePosition) - { - ClearError(); - - ArticleView* view = CreateArticleView(articleDesc); - if (view == nullptr) - { - return; - } - - m_articles.append(view); - - connect(view, &ArticleView::articleSelectedSignal, - this, &ArticleViewContainer::articleSelectedSlot); - connect(view, &ArticleView::linkActivatedSignal, - this, &ArticleViewContainer::linkActivatedSignal); - - auto layout = static_cast(m_ui->articleViewContents->layout()); - if (articlePosition == -1) - { - articlePosition = layout->count() - 1; - } - - layout->insertWidget(articlePosition, view); - qApp->processEvents(); - } - - void ArticleViewContainer::DeleteArticleView(ArticleView* view) - { - m_articles.removeAll(view); - m_ui->articleViewContents->layout()->removeWidget(view); - delete view; - } - - void ArticleViewContainer::ForceRefreshArticleView(ArticleView* articleView) - { - if (articleView == nullptr) - { - return; - } - - QSharedPointer articleDesc = articleView->GetArticle(); - auto layout = static_cast(m_ui->articleViewContents->layout()); - const int viewIndex = layout->indexOf(articleView); - - DeleteArticleView(articleView); - AddArticleView(*articleDesc, viewIndex); - } - - void ArticleViewContainer::ScrollToView(ArticleView* view) const - { - m_ui->previewArea->ensureWidgetVisible(view); - } - - void ArticleViewContainer::ClearError() - { - //delete loading label - if (m_loadingLabel) - { - delete m_loadingLabel; - m_loadingLabel = nullptr; - } - - //delete error message - if (m_errorMessage) - { - delete m_errorMessage; - m_errorMessage = nullptr; - } - } - - void ArticleViewContainer::articleSelectedSlot(QString id) - { - emit articleSelectedSignal(id); - } - - void ArticleViewContainer::UpdateArticleOrder(ArticleView* view, bool direction) const - { - QVBoxLayout* layout = qobject_cast(m_ui->articleViewContents->layout()); - - const int index = layout->indexOf(view); - - if (direction && index == 0) - { - return; - } - - if (!direction && index == layout->count() - 2) - { - return; - } - - const int newIndex = direction ? index - 1 : index + 1; - layout->removeWidget(view); - layout->insertWidget(newIndex, view); - } - - void ArticleViewContainer::AddLoadingMessage() - { - if (m_errorMessage) - { - delete m_errorMessage; - m_errorMessage = nullptr; - } - - if (!m_loadingLabel) - { - m_loadingLabel = new QLabel(this); - m_loadingLabel->setText("Retrieving news..."); - auto layout = static_cast(m_ui->articleViewContents->layout()); - layout->insertWidget(0, m_loadingLabel); - } - } - - void ArticleViewContainer::AddErrorMessage() - { - if (m_loadingLabel) - { - delete m_loadingLabel; - m_loadingLabel = nullptr; - } - - if (!m_errorMessage) - { - m_errorMessage = new ArticleErrorView(this); - auto layout = static_cast(m_ui->articleViewContents->layout()); - layout->insertWidget(0, m_errorMessage); - } - } - - void ArticleViewContainer::Clear() - { - ClearError(); - - for (auto articleView : m_articles) - { - delete articleView; - } - - m_articles.clear(); - } - - ArticleViewContainer::ArticleStyle ArticleViewContainer::GetArticleStyleEnumFromString(const QString& articleStyleStr) const - { - static const QMap articleStyleStringEnumMap = { - { "default", ArticleStyle::Default }, - { "pinned", ArticleStyle::Pinned } - }; - - if (articleStyleStringEnumMap.contains(articleStyleStr) == false) - { - Q_ASSERT(false); - return ArticleStyle::Default; - } - - return articleStyleStringEnumMap.value(articleStyleStr); - } - - ArticleView* ArticleViewContainer::CreateArticleView(const ArticleDescriptor& articleDesc) - { - ArticleStyle articleStyle = GetArticleStyleEnumFromString(articleDesc.GetArticleStyle()); - - switch(articleStyle) - { - case ArticleStyle::Default: - return new ArticleViewDefaultWidget(this, articleDesc, m_manifest); - case ArticleStyle::Pinned: - return new ArticleViewPinnedWidget(this, articleDesc, m_manifest); - default: - Q_ASSERT(false); - return nullptr; - } - } - -} - -#include "NewsShared/Qt/moc_ArticleViewContainer.cpp" diff --git a/Code/Tools/News/NewsShared/Qt/ArticleViewContainer.h b/Code/Tools/News/NewsShared/Qt/ArticleViewContainer.h deleted file mode 100644 index c0ae3b2701..0000000000 --- a/Code/Tools/News/NewsShared/Qt/ArticleViewContainer.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include "NewsShared/LogType.h" - -#include -#include -#endif - -class QLabel; - -namespace Ui -{ - class ArticleViewContainerWidget; -} - -namespace News -{ - class Resource; - class ArticleView; - class ArticleDescriptor; - class ResourceManifest; - class ArticleErrorView; - class KeepInTouchView; - - class ArticleViewContainer - : public QWidget - { - Q_OBJECT - - enum ArticleStyle - { - Default, - Pinned - }; - - public: - explicit ArticleViewContainer(QWidget* parent, ResourceManifest& manifest); - ~ArticleViewContainer(); - - virtual void PopulateArticles(); - ArticleView* FindById(const QString& id); - void AddArticleView(const ArticleDescriptor& articleDesc, int articlePosition = -1); - void DeleteArticleView(ArticleView* view); - void ForceRefreshArticleView(ArticleView* articleView); - void ScrollToView(ArticleView* view) const; - void UpdateArticleOrder(ArticleView* view, bool direction) const; - void AddLoadingMessage(); - void AddErrorMessage(); - void Clear(); - - Q_SIGNALS: - void articleSelectedSignal(QString resourceId); - void addArticle(Resource* article); - void logSignal(QString text, LogType logType = LogInfo); - void scrolled(); - void linkActivatedSignal(const QString& link); - - private: - QScopedPointer m_ui; - QList m_articles; - ResourceManifest& m_manifest; - QLabel* m_loadingLabel; - ArticleErrorView* m_errorMessage; - KeepInTouchView* m_keepInTouchViewWidget = nullptr; - - void ClearError(); - ArticleStyle GetArticleStyleEnumFromString(const QString& articleStyleStr) const; - ArticleView* CreateArticleView(const ArticleDescriptor& articleDesc); - - private Q_SLOTS: - virtual void articleSelectedSlot(QString id); - }; -} diff --git a/Code/Tools/News/NewsShared/Qt/ArticleViewContainer.ui b/Code/Tools/News/NewsShared/Qt/ArticleViewContainer.ui deleted file mode 100644 index dfb71ea31f..0000000000 --- a/Code/Tools/News/NewsShared/Qt/ArticleViewContainer.ui +++ /dev/null @@ -1,104 +0,0 @@ - - - ArticleViewContainerWidget - - - - 0 - 0 - 606 - 753 - - - - Form - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - 0 - - - Qt::ScrollBarAlwaysOn - - - Qt::ScrollBarAlwaysOff - - - true - - - Qt::AlignHCenter|Qt::AlignTop - - - - - 0 - 0 - 589 - 753 - - - - - 16 - - - 15 - - - 15 - - - 15 - - - 15 - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - - - - - diff --git a/Code/Tools/News/NewsShared/Qt/KeepInTouchView.cpp b/Code/Tools/News/NewsShared/Qt/KeepInTouchView.cpp deleted file mode 100644 index 43c32c43fc..0000000000 --- a/Code/Tools/News/NewsShared/Qt/KeepInTouchView.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "KeepInTouchView.h" -#include "NewsShared/Qt/ui_KeepInTouchView.h" - -#include -#include -#include -#include - -namespace News -{ - KeepInTouchView::KeepInTouchView(QWidget* parent) - : QWidget(parent) - , m_ui(new Ui::KeepInTouchViewWidget()) - { - m_ui->setupUi(this); - - m_ui->twich_container->setCursor(Qt::PointingHandCursor); - m_ui->twitter_container->setCursor(Qt::PointingHandCursor); - m_ui->youtube_container->setCursor(Qt::PointingHandCursor); - m_ui->facebook_container->setCursor(Qt::PointingHandCursor); - - m_ui->twich_container->installEventFilter(this); - m_ui->twitter_container->installEventFilter(this); - m_ui->youtube_container->installEventFilter(this); - m_ui->facebook_container->installEventFilter(this); - } - - bool KeepInTouchView::eventFilter(QObject *watched, QEvent *event) - { - if (event->type() == QEvent::MouseButtonRelease) - { - if (watched == m_ui->twich_container) - { - return LaunchSocialMediaUrl(SocialMediaType::Twitch); - } - else if (watched == m_ui->twitter_container) - { - return LaunchSocialMediaUrl(SocialMediaType::Twitter); - } - else if (watched == m_ui->youtube_container) - { - return LaunchSocialMediaUrl(SocialMediaType::YouTube); - } - else if (watched == m_ui->facebook_container) - { - return LaunchSocialMediaUrl(SocialMediaType::Facebook); - } - } - - return QWidget::eventFilter(watched, event); - } - - bool KeepInTouchView::LaunchSocialMediaUrl(SocialMediaType type) - { - static const QMap socialMediaTypeToUrlMap = - { - { SocialMediaType::Twitch, m_twitchUrl }, - { SocialMediaType::Twitter, m_twitterUrl }, - { SocialMediaType::YouTube, m_youtubeUrl }, - { SocialMediaType::Facebook, m_facebookUrl } - }; - - if (socialMediaTypeToUrlMap.contains(type) == false) - { - return false; - } - - QString link = socialMediaTypeToUrlMap[type]; - Q_EMIT linkActivatedSignal(link); - - return QDesktopServices::openUrl(QUrl(link)); - } -} - -#include "NewsShared/Qt/moc_KeepInTouchView.cpp" diff --git a/Code/Tools/News/NewsShared/Qt/KeepInTouchView.h b/Code/Tools/News/NewsShared/Qt/KeepInTouchView.h deleted file mode 100644 index 5d5c6a9e36..0000000000 --- a/Code/Tools/News/NewsShared/Qt/KeepInTouchView.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#endif - -namespace Ui -{ - class KeepInTouchViewWidget; -} - -namespace News -{ - class KeepInTouchView - : public QWidget - { - Q_OBJECT - - enum class SocialMediaType - { - Twitch, - Twitter, - YouTube, - Facebook - }; - - public: - KeepInTouchView(QWidget* parent); - ~KeepInTouchView() = default; - - bool eventFilter(QObject *watched, QEvent *event); - - Q_SIGNALS: - void linkActivatedSignal(const QString& link); - - private: - bool LaunchSocialMediaUrl(SocialMediaType type); - - Ui::KeepInTouchViewWidget* m_ui = nullptr; - - const char* m_twitchUrl = "https://docs.aws.amazon.com/console/lumberyard/twitch"; - const char* m_twitterUrl = "https://docs.aws.amazon.com/console/lumberyard/twitter"; - const char* m_youtubeUrl = "https://docs.aws.amazon.com/console/lumberyard/youtube"; - const char* m_facebookUrl = "https://docs.aws.amazon.com/console/lumberyard/facebook"; - }; -} diff --git a/Code/Tools/News/NewsShared/Qt/KeepInTouchView.ui b/Code/Tools/News/NewsShared/Qt/KeepInTouchView.ui deleted file mode 100644 index 076059f49d..0000000000 --- a/Code/Tools/News/NewsShared/Qt/KeepInTouchView.ui +++ /dev/null @@ -1,423 +0,0 @@ - - - KeepInTouchViewWidget - - - - 0 - 0 - 430 - 336 - - - - - 0 - 0 - - - - - 430 - 0 - - - - - 430 - 16777215 - - - - ArticleView - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 430 - 184 - - - - - 430 - 184 - - - - - - - :/images/Resources/KeepInTouchBanner.jpg - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 0 - 20 - - - - - - - - - 0 - 0 - - - - - Open Sans - 14 - 50 - false - - - - Keep in touch! - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - false - - - Qt::LinksAccessibleByMouse - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 12 - - - - - - - - - 0 - 0 - - - - - Open Sans - 8 - 50 - false - - - - Want to know the latest news at AmazonGameDev? Sign up for our newsletter and use the following links to find us! - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - 0 - - - 0 - - - false - - - Qt::LinksAccessibleByMouse - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 16 - - - - - - - - background: transparent; - - - - 20 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - 8 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - :/images/Resources/icon_twitch.png - - - - - - - Twitch - - - - - - - - - - - 0 - 0 - - - - - 8 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - :/images/Resources/icon_twitter.png - - - - - - - Twitter - - - - - - - - - - - 0 - 0 - - - - - 8 - - - 0 - - - 0 - - - 0 - - - - - - - - :/images/Resources/icon_youtube.png - - - - - - - Youtube - - - - - - - - - - - 8 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - :/images/Resources/icon_facebook.png - - - - - - - Facebook - - - - - - - - - - - - - - - - - AzQtComponents::ExtendedLabel - QLabel -
AzQtComponents/Components/ExtendedLabel.h
-
-
- - - - -
diff --git a/Code/Tools/News/NewsShared/Qt/NewsShared.qrc b/Code/Tools/News/NewsShared/Qt/NewsShared.qrc deleted file mode 100644 index 8d5b84494b..0000000000 --- a/Code/Tools/News/NewsShared/Qt/NewsShared.qrc +++ /dev/null @@ -1,10 +0,0 @@ - - - ../Resources/ErrorImage.jpg - ../Resources/KeepInTouchBanner.jpg - ../Resources/icon_facebook.png - ../Resources/icon_twitch.png - ../Resources/icon_twitter.png - ../Resources/icon_youtube.png - - diff --git a/Code/Tools/News/NewsShared/Qt/PinnedArticleView.ui b/Code/Tools/News/NewsShared/Qt/PinnedArticleView.ui deleted file mode 100644 index 928046a064..0000000000 --- a/Code/Tools/News/NewsShared/Qt/PinnedArticleView.ui +++ /dev/null @@ -1,260 +0,0 @@ - - - PinnedArticleViewWidget - - - - 0 - 0 - 430 - 376 - - - - - 0 - 0 - - - - - 430 - 0 - - - - - 430 - 16777215 - - - - ArticleView - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - pinned - - - - 12 - - - 16 - - - 16 - - - 16 - - - 16 - - - - - - 128 - 0 - - - - - 128 - 16777215 - - - - background-color: transparent; - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 128 - 96 - - - - - 128 - 96 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - Qt::Vertical - - - - 0 - 0 - - - - - - - - - - - background-color: transparent; - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - - Open Sans - 14 - 50 - false - - - - Title: - - - true - - - false - - - Qt::LinksAccessibleByMouse - - - sectionTitle - - - - - - - - 0 - 0 - - - - - Open Sans - 8 - 50 - false - - - - Body - - - true - - - false - - - Qt::LinksAccessibleByMouse - - - - - - - - - - - - - - AzQtComponents::ExtendedLabel - QLabel -
AzQtComponents/Components/ExtendedLabel.h
-
-
- - -
diff --git a/Code/Tools/News/NewsShared/ResourceManagement/ArticleDescriptor.cpp b/Code/Tools/News/NewsShared/ResourceManagement/ArticleDescriptor.cpp deleted file mode 100644 index c26d2357d7..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/ArticleDescriptor.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "ArticleDescriptor.h" -#include "Resource.h" - -#include -#include - -using namespace News; - -ArticleDescriptor::ArticleDescriptor( - Resource& resource) - : JsonDescriptor(resource) - , m_imageId(m_json["image"].toString()) - , m_title(m_json["title"].toString()) - , m_body(m_json["body"].toString()) - , m_order(m_json["order"].toInt()) -{ - if (m_json.contains("articleStyle") == true) - { - m_articleStyle = m_json["articleStyle"].toString(); - } -} - -void ArticleDescriptor::Update() const -{ - QJsonObject json; - json["image"] = m_imageId; - json["title"] = m_title; - json["body"] = m_body; - json["order"] = m_order; - json["articleStyle"] = m_articleStyle; - QJsonDocument doc(json); - QByteArray data = doc.toJson(QJsonDocument::Compact).toStdString().data(); - m_resource.SetData(data); -} - -const QString& ArticleDescriptor::GetArticleStyle() const -{ - return m_articleStyle; -} - -void ArticleDescriptor::SetArticleStyle(const QString& style) -{ - m_articleStyle = style; -} - -const QString& ArticleDescriptor::GetImageId() const -{ - return m_imageId; -} - -void ArticleDescriptor::SetImageId(const QString& imageId) -{ - m_imageId = imageId; -} - -const QString& ArticleDescriptor::GetTitle() const -{ - return m_title; -} - -void ArticleDescriptor::SetTitle(const QString& title) -{ - m_title = title; -} - -const QString& ArticleDescriptor::GetBody() const -{ - return m_body; -} - -void ArticleDescriptor::SetBody(const QString& body) -{ - m_body = body; -} diff --git a/Code/Tools/News/NewsShared/ResourceManagement/ArticleDescriptor.h b/Code/Tools/News/NewsShared/ResourceManagement/ArticleDescriptor.h deleted file mode 100644 index c0ca459cf4..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/ArticleDescriptor.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include "JsonDescriptor.h" - -#include - -namespace News -{ - class Resource; - - //! ArticleDescriptor represents Resource as an article - class ArticleDescriptor - : public JsonDescriptor - { - public: - explicit ArticleDescriptor(Resource& resource); - - //! If article was modified, call this to update resource data - void Update() const; - - const QString& GetArticleStyle() const; - - void SetArticleStyle(const QString& style); - - const QString& GetImageId() const; - - void SetImageId(const QString& imageId); - - const QString& GetTitle() const; - - void SetTitle(const QString& title); - - const QString& GetBody() const; - - void SetBody(const QString& body); - - private: - QString m_articleStyle = "default"; - QString m_imageId; - QString m_title; - QString m_body; - int m_order; - }; -} diff --git a/Code/Tools/News/NewsShared/ResourceManagement/Descriptor.cpp b/Code/Tools/News/NewsShared/ResourceManagement/Descriptor.cpp deleted file mode 100644 index 0d21a18c05..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/Descriptor.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "Descriptor.h" - -using namespace News; - -Descriptor::Descriptor(Resource& resource) - : m_resource(resource) {} - -Descriptor::~Descriptor() {} diff --git a/Code/Tools/News/NewsShared/ResourceManagement/Descriptor.h b/Code/Tools/News/NewsShared/ResourceManagement/Descriptor.h deleted file mode 100644 index 3d56037543..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/Descriptor.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -namespace News -{ - class Resource; - - //! Descriptor is a simple solution to add additional functionality to a Resource - /*! - Some descriptors can only work with certain resource types, like AerticleDescriptor - */ - class Descriptor - { - public: - explicit Descriptor(Resource& resource); - virtual ~Descriptor(); - - Resource& GetResource() const - { - return m_resource; - } - - protected: - Resource& m_resource; - }; -} diff --git a/Code/Tools/News/NewsShared/ResourceManagement/JsonDescriptor.cpp b/Code/Tools/News/NewsShared/ResourceManagement/JsonDescriptor.cpp deleted file mode 100644 index 5e71c8f10b..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/JsonDescriptor.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "JsonDescriptor.h" -#include "Resource.h" - -#include - -using namespace News; - -JsonDescriptor::JsonDescriptor(Resource& resource) - : Descriptor(resource) - , m_doc(QJsonDocument::fromJson(m_resource.GetData())) - , m_json(m_doc.object()) -{ -} diff --git a/Code/Tools/News/NewsShared/ResourceManagement/JsonDescriptor.h b/Code/Tools/News/NewsShared/ResourceManagement/JsonDescriptor.h deleted file mode 100644 index 286e66c4ac..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/JsonDescriptor.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include "Descriptor.h" - -#include -#include - -namespace News -{ - //! JsonDescriptor assumes Resource is a JSON file - class JsonDescriptor - : public Descriptor - { - public: - explicit JsonDescriptor(Resource& resource); - - protected: - QJsonDocument m_doc; - QJsonObject m_json; - }; -} diff --git a/Code/Tools/News/NewsShared/ResourceManagement/QtDownloadManager.cpp b/Code/Tools/News/NewsShared/ResourceManagement/QtDownloadManager.cpp deleted file mode 100644 index e70285fd31..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/QtDownloadManager.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "QtDownloadManager.h" -#include "QtDownloader.h" - -namespace News -{ - -QtDownloadManager::QtDownloadManager() - : QObject() - , m_worker(new QtDownloader) // this will start the thread which does downloads -{ - // make sure the response handlers are queued connections as the worker runs in a different thread - connect(m_worker, &QtDownloader::failed, this, &QtDownloadManager::failedReply, Qt::QueuedConnection); - connect(m_worker, &QtDownloader::successfullyFinished, this, &QtDownloadManager::successfulReply, Qt::QueuedConnection); -} - -QtDownloadManager::~QtDownloadManager() -{ - // NOTE: we don't delete the QtDownloader; it deletes itself. - // We just tell it to stop - m_worker->Finish(); -} - -void QtDownloadManager::Download(const QString& url, - std::function downloadSuccessCallback, - std::function downloadFailCallback) -{ - int downloadId = m_worker->Download(url); - m_downloads[downloadId] = { downloadSuccessCallback, downloadFailCallback }; -} - -void QtDownloadManager::Abort() -{ - m_worker->Abort(); - m_downloads.clear(); -} - -void QtDownloadManager::successfulReply(int downloadId, QByteArray data) -{ - m_downloads[downloadId].downloadSuccessCallback(data); - m_downloads.remove(downloadId); -} - -void QtDownloadManager::failedReply(int downloadId) -{ - m_downloads[downloadId].downloadFailCallback(); - m_downloads.remove(downloadId); -} - -} // namespace News - -#include "NewsShared/ResourceManagement/moc_QtDownloadManager.cpp" diff --git a/Code/Tools/News/NewsShared/ResourceManagement/QtDownloadManager.h b/Code/Tools/News/NewsShared/ResourceManagement/QtDownloadManager.h deleted file mode 100644 index 6a7c93a51f..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/QtDownloadManager.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include - -#include -#include -#endif - -namespace News -{ - class QtDownloader; - - //! QtDownloadManager handles multiple asynchronous downloads - class QtDownloadManager - : public QObject - { - Q_OBJECT - public: - QtDownloadManager(); - ~QtDownloadManager(); - - //! Asynchronously download a file from the input url and return it as QByteArray via the success callback - /*! - \param url - file url to download - \param downloadSuccessCallback - if download is successful pass file's data as QByteArray - \param downloadFailCallback - if download failed, pass error message - */ - void Download(const QString& url, - std::function downloadSuccessCallback, - std::function downloadFailCallback); - - //! Aborts all currently active downloads. Success/failure callbacks will not be called. - void Abort(); - - private: - void successfulReply(int downloadId, QByteArray data); - void failedReply(int downloadId); - - QtDownloader* m_worker = nullptr; - - struct DownloadResponses - { - std::function downloadSuccessCallback; - std::function downloadFailCallback; - }; - QMap m_downloads; - }; -} diff --git a/Code/Tools/News/NewsShared/ResourceManagement/QtDownloader.cpp b/Code/Tools/News/NewsShared/ResourceManagement/QtDownloader.cpp deleted file mode 100644 index 0139ec5344..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/QtDownloader.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "QtDownloader.h" - -#include -#include -#include -#include - - -namespace News -{ - QtDownloader::QtDownloader() - : m_thread(new QThread()) - { - // make sure that everything that QObject::connects to us knows we're running in a different thread - moveToThread(m_thread); - - // handle clean up of both ourselves and of our thread. - // We manage thread clean up so that it can keep running and be cleaned up later, regardless of what - // the thing that created the QtDownloader does - connect(m_thread, &QThread::finished, m_thread, [this] { - m_thread->deleteLater(); - deleteLater(); - }); - - auto abortDownloadsHandler = [this] { - auto replies = m_downloads.keys(); - for (QNetworkReply* reply : replies) - { - reply->abort(); - } - - m_downloads.clear(); - }; - - auto queueDownloadHandler = [this](int downloadId, QString url) { - if (m_networkManager) - { - QNetworkReply* reply = m_networkManager->get(QNetworkRequest(QUrl(url))); - m_downloads.insert(reply, downloadId); - } - }; - - auto createNetworkManagerHandler = [this] { - m_networkManager = new QNetworkAccessManager; - connect(m_networkManager, &QNetworkAccessManager::finished, this, &QtDownloader::downloadFinished); - }; - - auto deleteNetworkManagerHandler = [this] { - delete m_networkManager; - m_networkManager = nullptr; - }; - - auto quitHandler = [this] { - // call quit via this callback, so that it executes in the running thread. - // QThread::quit() is actually blocking and waits until everything finishes, so - // we don't want to call it in the main thread - m_thread->quit(); - }; - - // make sure the response handlers are queued connections as the worker runs in one thread, but these triggers - // will be emitted from the main thread - connect(this, &QtDownloader::triggerAbortAll, this, abortDownloadsHandler, Qt::QueuedConnection); - connect(this, &QtDownloader::triggerDownload, this, queueDownloadHandler, Qt::QueuedConnection); - connect(this, &QtDownloader::triggerQuit, this, quitHandler, Qt::QueuedConnection); - - // create/delete the QNetworkAccessManager in our thread, to ensure that any slowdowns caused by - // having to create network connectors / load drivers are done in our non-ui thread. - // make sure that these connections are direct so that network requests can't predate the network engine itself - connect(m_thread, &QThread::started, this, createNetworkManagerHandler, Qt::DirectConnection); - connect(m_thread, &QThread::finished, this, deleteNetworkManagerHandler, Qt::DirectConnection); - - m_thread->start(); - } - - QtDownloader::~QtDownloader() - { - } - - int QtDownloader::Download(const QString& url) - { - // create a unique id for this download - int downloadId = m_lastId++; - - // trigger a download running in our worker thread - Q_EMIT triggerDownload(downloadId, url); - - return downloadId; - } - - void QtDownloader::Abort() - { - // trigger an abort in our worker thread - Q_EMIT triggerAbortAll(); - } - - void QtDownloader::Finish() - { - // trigger a quit in our worker thread - Q_EMIT triggerQuit(); - } - - void QtDownloader::downloadFinished(QNetworkReply* reply) - { - // Note: this will run in our worker thread - int downloadId = m_downloads[reply]; - - // emit the signal back to the main thread indicating that we're finished, either - // successfully or unsuccessfully - if (reply->error() == QNetworkReply::NoError) - { - Q_EMIT successfullyFinished(downloadId, reply->readAll()); - } - else - { - Q_EMIT failed(downloadId); - } - - // clean up the reply; have to do this later, according to the Qt docs - reply->deleteLater(); - - // make sure to remove our reference to this reply from our list of active downloads - m_downloads.remove(reply); - } - - #include "NewsShared/ResourceManagement/moc_QtDownloader.cpp" -} diff --git a/Code/Tools/News/NewsShared/ResourceManagement/QtDownloader.h b/Code/Tools/News/NewsShared/ResourceManagement/QtDownloader.h deleted file mode 100644 index 0dcc86e951..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/QtDownloader.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#if !defined(Q_MOC_RUN) -#include -#include -#include -#include -#endif - -class QNetworkAccessManager; -class QNetworkReply; -class QThread; - -namespace News -{ - //! QtDownloader is a wrapper around Qt's file download functions - /*! - The QtDownloader spins up another thread and does all downloads in that thread. - The public slot methods (Finish, Download and Abort) can all be called from any thread. - The response signals (successfullyFinished and failed) should be QObject::connect to with - Qt::QueuedConnection, as they will be emitted from the worker thread. - */ - class QtDownloader - : public QObject - { - Q_OBJECT - - public: - QtDownloader(); - ~QtDownloader(); - - public Q_SLOTS: - void Finish(); - - int Download(const QString& url); - void Abort(); - - Q_SIGNALS: - void successfullyFinished(int downloadId, QByteArray data); - void failed(int downloadId); - - // *********************************************** - // private - DO NOT CONNECT TO outside of the class! - // (qt signals can't be made private) - void triggerAbortAll(); - void triggerDownload(int downloadId, QString url); - void triggerQuit(); - // *********************************************** - - private: - void downloadFinished(QNetworkReply* reply); - - int m_lastId = 0; - - QMap m_downloads; - QNetworkAccessManager* m_networkManager = nullptr; - QThread* m_thread; - }; -} diff --git a/Code/Tools/News/NewsShared/ResourceManagement/Resource.cpp b/Code/Tools/News/NewsShared/ResourceManagement/Resource.cpp deleted file mode 100644 index d40b66d6d7..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/Resource.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "Resource.h" - -#include - -using namespace News; - -Resource::Resource(const QJsonObject& json) - : Resource( - json["id"].toString(), - QByteArray(), - json["url"].toString(), - json["type"].toString(), - json["refCount"].toInt(), - json["version"].toInt()) {} - -Resource::Resource(const QString& id, const QString& type) - : Resource( - id, - QByteArray(), - "", - type, - 1, - 0) {} - -Resource::Resource(const QString& id, - const QByteArray& data, - [[maybe_unused]] const QString& url, - const QString& type, - int refCount, - int version) - : m_id(id) - , m_data(data) - , m_type(type) - , m_refCount(refCount) - , m_version(version) {} - -Resource::~Resource() {} - -void Resource::Write(QJsonObject& json) const -{ - json["id"] = m_id; - json["type"] = m_type; - json["refCount"] = m_refCount; - json["version"] = m_version; -} - -QString Resource::GetId() const -{ - return m_id; -} - -void Resource::SetId(const QString& id) -{ - m_id = id; -} - -QByteArray Resource::GetData() const -{ - return m_data; -} - -void Resource::SetData(QByteArray data) -{ - m_data = data; -} - -QString Resource::GetType() const -{ - return m_type; -} - -int Resource::GetRefCount() const -{ - return m_refCount; -} - -void Resource::SetRefCount(int refCount) -{ - m_refCount = refCount; -} - -int Resource::GetVersion() const -{ - return m_version; -} - -void Resource::SetVersion(int version) -{ - m_version = version; -} diff --git a/Code/Tools/News/NewsShared/ResourceManagement/Resource.h b/Code/Tools/News/NewsShared/ResourceManagement/Resource.h deleted file mode 100644 index 1174fea788..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/Resource.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include - -class QJsonObject; - -namespace News -{ - class Descriptor; - - //! Resource is a central element of in-editor messages - //! It represents articles, images, and anything else that is part of news feed - class Resource - { - public: - //! resources are stored as json objects in \ref News::ResourceManifest - //! this creates resource with empty data array, that can be downloaded later - //! by calling News::ResourceManifest::Sync - explicit Resource(const QJsonObject& json); - - explicit Resource(const QString& id, - const QString& type); - - Resource(const QString& id, - const QByteArray& data, - const QString& url, - const QString& type, - int refCount, - int version); - - ~Resource(); - - //! Saves resource's description to a json file - void Write(QJsonObject& json) const; - - QString GetId() const; - - void SetId(const QString& id); - - QByteArray GetData() const; - - void SetData(QByteArray data); - - QString GetType() const; - - int GetRefCount() const; - - void SetRefCount(int refCount); - - int GetVersion() const; - - void SetVersion(int version); - - private: - QString m_id; - QByteArray m_data; - QString m_type; - int m_refCount; - int m_version; - }; -} diff --git a/Code/Tools/News/NewsShared/ResourceManagement/ResourceManifest.cpp b/Code/Tools/News/NewsShared/ResourceManagement/ResourceManifest.cpp deleted file mode 100644 index 969c4ec8f1..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/ResourceManifest.cpp +++ /dev/null @@ -1,349 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "ResourceManifest.h" -#include "NewsShared/ResourceManagement/QtDownloadManager.h" -#include "NewsShared/ResourceManagement/Resource.h" -#include "NewsShared/ResourceManagement/ArticleDescriptor.h" - -#include -#include -#include -#include -#include - -namespace News -{ - - const QString ResourceManifest::MANIFEST_NAME = "resourceManifest"; - bool ResourceManifest::s_syncing = false; - - ResourceManifest::ResourceManifest( - std::function syncSuccessCallback, - std::function syncFailCallback, - std::function syncUpdateCallback) - : m_downloader(new QtDownloadManager) - , m_syncSuccessCallback(syncSuccessCallback) - , m_syncFailCallback(syncFailCallback) - , m_syncUpdateCallback(syncUpdateCallback) - { - } - - ResourceManifest::~ResourceManifest() - { - // clean everything up - DeleteResources(); - - delete m_downloader; - } - - Resource* ResourceManifest::FindById(const QString& id) const - { - return FindById(id, m_resources); - } - - Resource* ResourceManifest::FindById(const QString& id, const QList& resources) - { - auto it = std::find_if( - resources.begin(), - resources.end(), - [id](Resource* resource) -> bool - { - return resource->GetId().compare(id) == 0; - }); - if (it == resources.end()) - { - return nullptr; - } - return *it; - } - - Resource* ResourceManifest::FindById(const QString& id, - const QStack& resources) - { - auto it = std::find_if( - resources.begin(), - resources.end(), - [id](Resource* resource) -> bool - { - return resource->GetId().compare(id) == 0; - }); - if (it == resources.end()) - { - return nullptr; - } - return *it; - } - - void ResourceManifest::Sync() - { - if (s_syncing) - { - FailSync(ErrorCode::AlreadySyncing); - return; - } - s_syncing = true; - m_failed = false; - - m_syncUpdateCallback("Starting sync", LogInfo); - - ReadConfig(); - - // first download the manifest json - m_syncUpdateCallback("Downloading manifest", LogInfo); - m_downloader->Download(QString(m_url).append(MANIFEST_NAME), - std::bind(&ResourceManifest::OnDownloadSuccess, this, std::placeholders::_1), - std::bind(&ResourceManifest::OnDownloadFail, this)); - } - - void ResourceManifest::Abort() - { - m_aborted = true; - m_downloader->Abort(); - } - - void ResourceManifest::Reset() - { - if (s_syncing) - { - m_syncUpdateCallback("Sync is already running", LogError); - return; - } - - m_aborted = false; - m_failed = false; - m_version = -1; - - DeleteResources(); - - m_order.clear(); - } - - QList::const_iterator ResourceManifest::begin() const - { - return m_resources.constBegin(); - } - - QList::const_iterator ResourceManifest::end() const - { - return m_resources.constEnd(); - } - - QList ResourceManifest::GetOrder() const - { - return m_order; - } - - void ResourceManifest::OnDownloadSuccess(QByteArray data) - { - QJsonDocument doc(QJsonDocument::fromJson(data)); - if (doc.isNull()) - { - FailSync(ErrorCode::FailedToParseManifest); - return; - } - - ErrorCode error = Read(doc.object()); - if (error != ErrorCode::None) - { - FailSync(error); - return; - } - - // check how many resources to sync - PrepareForSync(); - // if there is anything to sync, do that - if (m_syncLeft > 0) - { - m_syncUpdateCallback("Syncing resources", LogInfo); - SyncResources(); - } - // otherwise just finish sync - else - { - m_syncUpdateCallback("No new resources to sync", LogInfo); - FinishSync(); - } - } - - void ResourceManifest::OnDownloadFail() - { - FailSync(ErrorCode::ManifestDownloadFail); - } - - ErrorCode ResourceManifest::Read(const QJsonObject& json) - { - m_version = json["version"].toInt(); - QJsonArray resourceArray = json["resources"].toArray(); - // initially mark ALL existing resource for deletion - QList toDelete = m_resources; - - for (auto resourceDoc : resourceArray) - { - auto pNewResource = new Resource(resourceDoc.toObject()); - // find local resource with the same id as new resource - auto pOldResource = FindById(pNewResource->GetId(), m_resources); - // if resource with the same id already exists then check its version - if (pOldResource) - { - // local resource is outdated, keep it in delete list, and download new one instead - if (pNewResource->GetVersion() > pOldResource->GetVersion()) - { - m_toDownload.push(pNewResource); - } - // local resource is newer or same version, keep it (remove from toDelete list) - // and don't need to download new one - else - { - delete pNewResource; - toDelete.removeAll(pOldResource); - } - } - // resource with same id not found - else - { - m_toDownload.push(pNewResource); - } - } - - // delete everything that's not in s3 - for (auto pResource : toDelete) - { - RemoveResource(pResource); - delete pResource; - } - - // parse order of articles - m_order.clear(); - QJsonArray orderArray = json["order"].toArray(); - for (auto idObject : orderArray) - { - m_order.append(idObject.toString()); - } - return ErrorCode::None; - } - - void ResourceManifest::PrepareForSync() - { - if (m_aborted) - { - m_syncLeft = 0; - } - - m_syncLeft = m_toDownload.count(); - } - - void ResourceManifest::SyncResources() - { - DownloadResources(); - } - - void ResourceManifest::DownloadResources() - { - while (m_toDownload.count() > 0) - { - m_syncUpdateCallback( - QString("Downloading: %1 resources left").arg(m_toDownload.count()), - LogInfo); - - auto pResource = m_toDownload.pop(); - - m_downloader->Download(QString(m_url).append(pResource->GetId()), - //download success - [&, pResource](QByteArray data) - { - pResource->SetData(data); - AppendResource(pResource); - UpdateSync(); - }, - //download fail - [&, pResource]() - { - m_failed = true; - delete pResource; - m_syncUpdateCallback("Failed to download resource", LogError); - UpdateSync(); - }); - } - } - - void ResourceManifest::ReadConfig() - { - QFile file(QCoreApplication::applicationDirPath() + "/newsConfig.txt"); - if (file.exists()) - { - if (file.open(QIODevice::ReadOnly)) - { - QTextStream in(&file); - m_url = in.readAll().trimmed(); - file.close(); - } - } - } - - void ResourceManifest::DeleteResources() - { - for (auto pResource : m_toDownload) - { - delete pResource; - } - m_toDownload.clear(); - - for (auto pResource : m_resources) - { - delete pResource; - } - m_resources.clear(); - } - - void ResourceManifest::UpdateSync() - { - m_syncLeft--; - if (m_syncLeft == 0) - { - if (!m_failed) - { - FinishSync(); - } - else - { - FailSync(ErrorCode::FailedToSync); - } - } - } - - void ResourceManifest::FinishSync() - { - if (!m_failed) - { - m_syncSuccessCallback(); - } - else - { - m_syncFailCallback(m_errorCode); - } - s_syncing = false; - } - - void ResourceManifest::FailSync(ErrorCode error) - { - m_failed = true; - m_errorCode = error; - FinishSync(); - } - - void ResourceManifest::AppendResource(Resource* pResource) - { - m_resources.append(pResource); - } - - void ResourceManifest::RemoveResource(Resource* pResource) - { - m_resources.removeAll(pResource); - } - -} diff --git a/Code/Tools/News/NewsShared/ResourceManagement/ResourceManifest.h b/Code/Tools/News/NewsShared/ResourceManagement/ResourceManifest.h deleted file mode 100644 index 3a0f31de8f..0000000000 --- a/Code/Tools/News/NewsShared/ResourceManagement/ResourceManifest.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include -#include - -#include "NewsShared/LogType.h" -#include "NewsShared/ErrorCodes.h" - -class QJsonObject; - -namespace News -{ - class ArticleDescriptor; - class UidGenerator; - class S3Connector; - class QtDownloadManager; - class Descriptor; - class DownloadDescriptor; - class Resource; - - //! ResourceManifest manages resources. - /*! - Manifest contains information on resources, it handles syncing resources with s3 - */ - class ResourceManifest - { - public: - //! ResourceManifest ctor - /*! - \param syncSuccessCallback - called once when everything is synced - \param syncFailCallback - called once when sync failed - \param syncUpdateCallback - called multiple times to update information on sync process - */ - explicit ResourceManifest( - std::function syncSuccessCallback, - std::function syncFailCallback, - std::function syncUpdateCallback); - virtual ~ResourceManifest(); - - //! Find a resource that matches id - /*! - \retval Resource * - a pointer to a Resource with matching id, if none found return nullptr - */ - Resource* FindById(const QString& id) const; - static Resource* FindById(const QString& id, const QList& resources); - static Resource* FindById(const QString& id, const QStack& resources); - - //! Sync resources with s3 - /* - 1) First download resource manifest file - 2) Parse manifest - 3) Determine which resources need to be downloaded, updated, or deleted - 4) Download missing resources or resource that are out of date - 5) Call m_syncSuccessCallback - */ - virtual void Sync(); - - //! Gracegully stop sync process - /*! - Aborting works differently depending at what point during sync porocess it is called - If called before resources started to download, then skip download altogether - Otherwise gracefully abort all downloads and call m_syncFailCallback - */ - void Abort(); - - //! Called when switching endpoints to reset resource manifest to a clean state - virtual void Reset(); - - QList::const_iterator begin() const; - QList::const_iterator end() const; - - //! Get order of article resources, so they can be displayed properly in ArticleViewContainer - QList GetOrder() const; - - protected: - //! The root location of cloudfront resources - QString m_url = "https://lumberyard-data.amazon.com/"; - //! Name of resourceManifest file that links all other resources - static const QString MANIFEST_NAME; - //! Identifies whether syncing is in progress - static bool s_syncing; - //! Manifest Version - int m_version = -1; - //! Number of resources left to sync - int m_syncLeft = 0; - //! Identifies whether sync process was aborted - bool m_aborted = false; - //! Indentifies whether sync process has failed - bool m_failed = false; - ErrorCode m_errorCode = ErrorCode::None; - - QtDownloadManager* m_downloader = nullptr; - - QList m_resources; - QList m_order; - QStack m_toDownload; - - std::function m_syncSuccessCallback; - std::function m_syncFailCallback; - std::function m_syncUpdateCallback; - - //! Parse resource manifest json, and figure out which resources need to be downloaded - virtual ErrorCode Read(const QJsonObject& json); - - //! Executed before sync to figure out how many resources need to be synced - virtual void PrepareForSync(); - //! Actual sync function - virtual void SyncResources(); - //! Check whether everything is synced, if so call ResourceManifest::FinishSync - void UpdateSync(); - //! Notify that everything is synced - virtual void FinishSync(); - void FailSync(ErrorCode error); - - virtual void AppendResource(Resource* pResource); - virtual void RemoveResource(Resource* pResource); - - virtual void OnDownloadSuccess(QByteArray data); - virtual void OnDownloadFail(); - virtual void DownloadResources(); - - private: - void ReadConfig(); - void DeleteResources(); - }; -} // namespace News diff --git a/Code/Tools/News/NewsShared/Resources/ErrorImage.jpg b/Code/Tools/News/NewsShared/Resources/ErrorImage.jpg deleted file mode 100644 index 216fe14bd5..0000000000 --- a/Code/Tools/News/NewsShared/Resources/ErrorImage.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0a7430d63820b3b00e03b4a8ec73b5e8e3946659031e3aeeb355b632acca4122 -size 8857 diff --git a/Code/Tools/News/NewsShared/Resources/KeepInTouchBanner.jpg b/Code/Tools/News/NewsShared/Resources/KeepInTouchBanner.jpg deleted file mode 100644 index b47040b717..0000000000 --- a/Code/Tools/News/NewsShared/Resources/KeepInTouchBanner.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:09c1733f116c11b56c54f7c3b6b4462884116db06605ca3cdfa23c45a3695385 -size 68024 diff --git a/Code/Tools/News/NewsShared/Resources/icon_facebook.png b/Code/Tools/News/NewsShared/Resources/icon_facebook.png deleted file mode 100644 index 0fb823969b..0000000000 --- a/Code/Tools/News/NewsShared/Resources/icon_facebook.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f8b5493c81354b6757a21bea6baedd5665b8cb9ca19a6ff4fbd40afef534f35f -size 1257 diff --git a/Code/Tools/News/NewsShared/Resources/icon_twitch.png b/Code/Tools/News/NewsShared/Resources/icon_twitch.png deleted file mode 100644 index 50d7436b0d..0000000000 --- a/Code/Tools/News/NewsShared/Resources/icon_twitch.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2882aad73e2ecf310934ec3eacd0c1fa0a6ff012a4c3c9cf4ca96a72cef2fb8c -size 514 diff --git a/Code/Tools/News/NewsShared/Resources/icon_twitter.png b/Code/Tools/News/NewsShared/Resources/icon_twitter.png deleted file mode 100644 index d1cf7eb3dd..0000000000 --- a/Code/Tools/News/NewsShared/Resources/icon_twitter.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:046e14f1d90f77bb6ea0fe700bb10049748b46bb84c8ac3620642d4bca9df533 -size 954 diff --git a/Code/Tools/News/NewsShared/Resources/icon_youtube.png b/Code/Tools/News/NewsShared/Resources/icon_youtube.png deleted file mode 100644 index d3e7869387..0000000000 --- a/Code/Tools/News/NewsShared/Resources/icon_youtube.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3abaf8b178763441ac6812ae518c2f8cbea9b228aa1f84052a65836b33dc980c -size 976 diff --git a/Code/Tools/News/news_shared_files.cmake b/Code/Tools/News/news_shared_files.cmake deleted file mode 100644 index 2f20029068..0000000000 --- a/Code/Tools/News/news_shared_files.cmake +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. -# -# SPDX-License-Identifier: Apache-2.0 OR MIT -# -# - -set(FILES - NewsShared/LogType.h - NewsShared/ErrorCodes.h - NewsShared/Qt/ArticleErrorView.cpp - NewsShared/Qt/ArticleErrorView.h - NewsShared/Qt/ArticleErrorView.ui - NewsShared/Qt/ArticleView.cpp - NewsShared/Qt/ArticleView.h - NewsShared/Qt/ArticleView.ui - NewsShared/Qt/PinnedArticleView.ui - NewsShared/Qt/ArticleViewContainer.cpp - NewsShared/Qt/ArticleViewContainer.h - NewsShared/Qt/ArticleViewContainer.ui - NewsShared/Qt/KeepInTouchView.cpp - NewsShared/Qt/KeepInTouchView.h - NewsShared/Qt/KeepInTouchView.ui - NewsShared/Qt/NewsShared.qrc - NewsShared/ResourceManagement/ArticleDescriptor.cpp - NewsShared/ResourceManagement/ArticleDescriptor.h - NewsShared/ResourceManagement/Descriptor.cpp - NewsShared/ResourceManagement/Descriptor.h - NewsShared/ResourceManagement/JsonDescriptor.cpp - NewsShared/ResourceManagement/JsonDescriptor.h - NewsShared/ResourceManagement/QtDownloader.cpp - NewsShared/ResourceManagement/QtDownloader.h - NewsShared/ResourceManagement/QtDownloadManager.cpp - NewsShared/ResourceManagement/QtDownloadManager.h - NewsShared/ResourceManagement/Resource.cpp - NewsShared/ResourceManagement/Resource.h - NewsShared/ResourceManagement/ResourceManifest.cpp - NewsShared/ResourceManagement/ResourceManifest.h - NewsShared/Resources/ErrorImage.jpg - NewsShared/Resources/KeepInTouchBanner.jpg - NewsShared/Resources/icon_facebook.png - NewsShared/Resources/icon_twitch.png - NewsShared/Resources/icon_twitter.png - NewsShared/Resources/icon_youtube.png -) diff --git a/Code/Tools/ProjectManager/Resources/FeatureTagClose.svg b/Code/Tools/ProjectManager/Resources/FeatureTagClose.svg new file mode 100644 index 0000000000..9ab30acd65 --- /dev/null +++ b/Code/Tools/ProjectManager/Resources/FeatureTagClose.svg @@ -0,0 +1,4 @@ + + + + diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc index cfe4b37fbc..2e93e9eca9 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qrc +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qrc @@ -34,5 +34,6 @@ Warning.svg Backgrounds/DefaultBackground.jpg Backgrounds/FtueBackground.jpg + FeatureTagClose.svg diff --git a/Code/Tools/ProjectManager/Resources/ProjectManager.qss b/Code/Tools/ProjectManager/Resources/ProjectManager.qss index d6a2476e83..74acc1c7ef 100644 --- a/Code/Tools/ProjectManager/Resources/ProjectManager.qss +++ b/Code/Tools/ProjectManager/Resources/ProjectManager.qss @@ -435,8 +435,6 @@ QProgressBar { border: none; background-color: transparent; padding: 0px; - min-height: 14px; - font-size: 2px; } QProgressBar::chunk { @@ -478,6 +476,13 @@ QProgressBar::chunk { background-color: #333333; } +/************** Filter tag widget **************/ + +#FilterTagWidgetTextLabel { + color: #94D2FF; + font-size: 10px; +} + /************** Gem Catalog (Inspector) **************/ #GemCatalogInspector { diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterTagWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterTagWidget.cpp new file mode 100644 index 0000000000..c7925a2d6e --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterTagWidget.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#include +#include +#include +#include +#include + +namespace O3DE::ProjectManager +{ + FilterTagWidget::FilterTagWidget(const QString& text, QWidget* parent) + : QFrame(parent) + { + setFrameShape(QFrame::NoFrame); + + auto* layout = new QHBoxLayout(); + layout->setContentsMargins(6, 5, 4, 4); + layout->setSpacing(2); + setLayout(layout); + + setStyleSheet("background-color: #555555;"); + + m_textLabel = new QLabel(); + m_textLabel->setObjectName("FilterTagWidgetTextLabel"); + m_textLabel->setText(text); + layout->addWidget(m_textLabel); + + m_closeButton = new QPushButton(); + m_closeButton->setFlat(true); + m_closeButton->setIcon(QIcon(":/FeatureTagClose.svg")); + m_closeButton->setIconSize(QSize(12, 12)); + m_closeButton->setStyleSheet("QPushButton { background-color: transparent; border: 0px }"); + layout->addWidget(m_closeButton); + connect(m_closeButton, &QPushButton::clicked, this, [=]{ emit RemoveClicked(); }); + } + + QString FilterTagWidget::text() const + { + return m_textLabel->text(); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + FilterTagWidgetContainer::FilterTagWidgetContainer(QWidget* parent) + : QWidget(parent) + { + m_layout = new QHBoxLayout(); + m_layout->setMargin(0); + m_layout->setSpacing(0); + setLayout(m_layout); + } + + void FilterTagWidgetContainer::Reinit(const QVector& tags) + { + if (m_widget) + { + // Hide the old widget and request deletion. + m_widget->hide(); + m_widget->deleteLater(); + } + + m_widget = new QWidget(this); + + QHBoxLayout* hLayout = new QHBoxLayout(); + hLayout->setAlignment(Qt::AlignLeft); + hLayout->setMargin(0); + hLayout->setSpacing(8); + + for(const QString& tag : tags) + { + FilterTagWidget* tagWidget = new FilterTagWidget(tag); + + // Add the tag widget to the current row. + hLayout->addWidget(tagWidget); + + // Connect the clicked event of the close button of the tag widget to the remove tag function in the container. + connect(tagWidget, &FilterTagWidget::RemoveClicked, this, [this, tagWidget]{ emit TagRemoved(tagWidget->text()); }); + } + + QWidget* spacerWidget = new QWidget(); + spacerWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + hLayout->addWidget(spacerWidget); + + m_widget->setLayout(hLayout); + m_layout->addWidget(m_widget); + + setFixedHeight(30); + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterTagWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterTagWidget.h new file mode 100644 index 0000000000..0994618d4e --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterTagWidget.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + * + * SPDX-License-Identifier: Apache-2.0 OR MIT + * + */ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#include +#include +#endif + +QT_FORWARD_DECLARE_CLASS(QHBoxLayout) +QT_FORWARD_DECLARE_CLASS(QLabel) +QT_FORWARD_DECLARE_CLASS(QPushButton) +QT_FORWARD_DECLARE_CLASS(QWidget) + +namespace O3DE::ProjectManager +{ + class FilterTagWidget + : public QFrame + { + Q_OBJECT + + public: + FilterTagWidget(const QString& text, QWidget* parent = nullptr); + QString text() const; + + signals: + void RemoveClicked(); + + private: + QLabel* m_textLabel = nullptr; + QPushButton* m_closeButton = nullptr; + }; + + // Horizontally expanding filter tag container widget + class FilterTagWidgetContainer + : public QWidget + { + Q_OBJECT + + public: + FilterTagWidgetContainer(QWidget* parent = nullptr); + void Reinit(const QVector& tags); + + signals: + void TagRemoved(QString tagName); + + private: + QWidget* m_widget = nullptr; + QHBoxLayout* m_layout = nullptr; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp index 753371ba52..268e793ee8 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp @@ -14,6 +14,7 @@ #include #include #include +#include namespace O3DE::ProjectManager { @@ -485,6 +486,7 @@ namespace O3DE::ProjectManager const QString& feature = elementNames[i]; QAbstractButton* button = buttons[i]; + // Adjust the proxy model and enable or disable the clicked feature used for filtering. connect(button, &QAbstractButton::toggled, this, [=](bool checked) { QSet features = m_filterProxyModel->GetFeatures(); @@ -498,6 +500,15 @@ namespace O3DE::ProjectManager } m_filterProxyModel->SetFeatures(features); }); + + // Sync the UI state with the proxy model filtering. + connect(m_filterProxyModel, &GemSortFilterProxyModel::OnInvalidated, this, [=] + { + const QSet& filteredFeatureTags = m_filterProxyModel->GetFeatures(); + const bool isChecked = filteredFeatureTags.contains(button->text()); + QSignalBlocker signalsBlocker(button); + button->setChecked(isChecked); + }); } } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp index b9dc3e9fcc..f5bedb79eb 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp @@ -102,9 +102,11 @@ namespace O3DE::ProjectManager // In case there are feature tags displayed at the bottom, decrease the size of the summary text field. const QStringList featureTags = GemModel::GetFeatures(modelIndex); - const int summaryHeight = contentRect.height() - (!featureTags.empty() * 30); + const int featureTagAreaHeight = 30; + const int summaryHeight = contentRect.height() - (!featureTags.empty() * featureTagAreaHeight); - const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - s_itemMargins.right() * 3, + const int additionalSummarySpacing = s_itemMargins.right() * 3; + const QSize summarySize = QSize(contentRect.width() - s_summaryStartX - s_buttonWidth - additionalSummarySpacing, summaryHeight); const QRect summaryRect = QRect(/*topLeft=*/QPoint(contentRect.left() + s_summaryStartX, contentRect.top()), summarySize); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp index 5e2f93c2fc..3d6fd1947c 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.cpp @@ -7,10 +7,13 @@ #include #include -#include +#include +#include +#include #include -#include #include +#include +#include namespace O3DE::ProjectManager { @@ -23,11 +26,34 @@ namespace O3DE::ProjectManager setStyleSheet("background-color: #333333;"); - vLayout->addSpacing(20); + vLayout->addSpacing(13); // Top section QHBoxLayout* topLayout = new QHBoxLayout(); + topLayout->addSpacing(16); topLayout->setMargin(0); + + auto* tagWidget = new FilterTagWidgetContainer(); + + // Adjust the proxy model and disable the given feature used for filtering. + connect(tagWidget, &FilterTagWidgetContainer::TagRemoved, this, [=](QString tagName) + { + QSet filteredFeatureTags = proxyModel->GetFeatures(); + filteredFeatureTags.remove(tagName); + proxyModel->SetFeatures(filteredFeatureTags); + }); + + // Reinitialize the tag widget in case the filter in the proxy model got invalided. + connect(proxyModel, &GemSortFilterProxyModel::OnInvalidated, this, [=] + { + const QSet& tagSet = proxyModel->GetFeatures(); + QVector sortedTags(tagSet.begin(), tagSet.end()); + std::sort(sortedTags.begin(), sortedTags.end()); + tagWidget->Reinit(sortedTags); + }); + + topLayout->addWidget(tagWidget); + topLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding)); QLabel* showCountLabel = new QLabel(); @@ -43,7 +69,7 @@ namespace O3DE::ProjectManager vLayout->addLayout(topLayout); - vLayout->addSpacing(20); + vLayout->addSpacing(13); // Separating line QFrame* hLine = new QFrame(); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.h index a9b3b3aa36..fcad58a321 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListHeaderWidget.h @@ -8,9 +8,8 @@ #pragma once #if !defined(Q_MOC_RUN) +#include #include -#include -#include #include #endif diff --git a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp index c0c96d8281..508b7256d1 100644 --- a/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp +++ b/Code/Tools/ProjectManager/Source/NewProjectSettingsScreen.cpp @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -117,7 +118,7 @@ namespace O3DE::ProjectManager for (int index = 0; index < m_templates.size(); ++index) { ProjectTemplateInfo projectTemplate = m_templates.at(index); - QString projectPreviewPath = projectTemplate.m_path + "/Template/preview.png"; + QString projectPreviewPath = QDir(projectTemplate.m_path).filePath(ProjectPreviewImagePath); QFileInfo doesPreviewExist(projectPreviewPath); if (!doesPreviewExist.exists() || !doesPreviewExist.isFile()) { diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h index f74233db51..79ad04c43a 100644 --- a/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h +++ b/Code/Tools/ProjectManager/Source/ProjectManagerDefs.h @@ -12,6 +12,7 @@ namespace O3DE::ProjectManager { inline constexpr static int ProjectPreviewImageWidth = 210; inline constexpr static int ProjectPreviewImageHeight = 280; + inline constexpr static int ProjectTemplateImageWidth = 92; static const QString ProjectBuildPathPostfix = "build/windows_vs2019"; static const QString ProjectBuildPathCmakeFiles = "CMakeFiles"; diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp index f7a90f5e0c..83e7546670 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.cpp @@ -10,11 +10,13 @@ #include #include +#include #include #include #include #include #include +#include namespace O3DE::ProjectManager { @@ -55,7 +57,42 @@ namespace O3DE::ProjectManager return false; } - static bool CopyDirectory(const QString& origPath, const QString& newPath) + typedef AZStd::function StatusFunction; + static void RecursiveGetAllFiles(const QDir& directory, QStringList& outFileList, qint64& outTotalSizeInBytes, StatusFunction statusCallback) + { + const QStringList entries = directory.entryList(QDir::Dirs | QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot); + for (const QString& entryPath : entries) + { + const QString filePath = QDir::toNativeSeparators(QString("%1/%2").arg(directory.path()).arg(entryPath)); + QFileInfo fileInfo(filePath); + + if (fileInfo.isDir()) + { + QDir subDirectory(filePath); + RecursiveGetAllFiles(subDirectory, outFileList, outTotalSizeInBytes, statusCallback); + } + else + { + outFileList.push_back(filePath); + outTotalSizeInBytes += fileInfo.size(); + + const int updateStatusEvery = 64; + if (outFileList.size() % updateStatusEvery == 0) + { + statusCallback(outFileList.size(), outTotalSizeInBytes); + } + } + } + } + + static bool CopyDirectory(QProgressDialog* progressDialog, + const QString& origPath, + const QString& newPath, + QStringList& filesToCopy, + int& outNumCopiedFiles, + qint64 totalSizeToCopy, + qint64& outCopiedFileSize, + bool& showIgnoreFileDialog) { QDir original(origPath); if (!original.exists()) @@ -65,19 +102,91 @@ namespace O3DE::ProjectManager for (QString directory : original.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { + if (progressDialog->wasCanceled()) + { + return false; + } + QString newDirectoryPath = newPath + QDir::separator() + directory; original.mkpath(newDirectoryPath); - if (!CopyDirectory(origPath + QDir::separator() + directory, newDirectoryPath)) + if (!CopyDirectory(progressDialog, origPath + QDir::separator() + directory, + newDirectoryPath, filesToCopy, outNumCopiedFiles, totalSizeToCopy, outCopiedFileSize, showIgnoreFileDialog)) { return false; } } + QLocale locale; + const float progressDialogRangeHalf = qFabs(progressDialog->maximum() - progressDialog->minimum()) * 0.5f; for (QString file : original.entryList(QDir::Files)) { - if (!QFile::copy(origPath + QDir::separator() + file, newPath + QDir::separator() + file)) + if (progressDialog->wasCanceled()) + { return false; + } + + // Progress window update + { + // Weight in the number of already copied files as well as the copied bytes to get a better progress indication + // for cases combining many small files and some really large files. + const float normalizedNumFiles = static_cast(outNumCopiedFiles) / filesToCopy.count(); + const float normalizedFileSize = static_cast(outCopiedFileSize) / totalSizeToCopy; + const int progress = normalizedNumFiles * progressDialogRangeHalf + normalizedFileSize * progressDialogRangeHalf; + progressDialog->setValue(progress); + + const QString copiedFileSizeString = locale.formattedDataSize(outCopiedFileSize); + const QString totalFileSizeString = locale.formattedDataSize(totalSizeToCopy); + progressDialog->setLabelText(QString("Coping file %1 of %2 (%3 of %4) ...").arg(QString::number(outNumCopiedFiles), + QString::number(filesToCopy.count()), + copiedFileSizeString, + totalFileSizeString)); + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + } + + const QString toBeCopiedFilePath = origPath + QDir::separator() + file; + const QString copyToFilePath = newPath + QDir::separator() + file; + if (!QFile::copy(toBeCopiedFilePath, copyToFilePath)) + { + // Let the user decide to ignore files that failed to copy or cancel the whole operation. + if (showIgnoreFileDialog) + { + QMessageBox ignoreFileMessageBox; + const QString text = QString("Cannot copy %1.

" + "Source: %2
" + "Destination: %3

" + "Press Yes to ignore the file, YesToAll to ignore all upcoming non-copyable files or " + "Cancel to abort duplicating the project.").arg(file, toBeCopiedFilePath, copyToFilePath); + + ignoreFileMessageBox.setModal(true); + ignoreFileMessageBox.setWindowTitle("Cannot copy file"); + ignoreFileMessageBox.setText(text); + ignoreFileMessageBox.setIcon(QMessageBox::Question); + ignoreFileMessageBox.setStandardButtons(QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::Cancel); + + int ignoreFile = ignoreFileMessageBox.exec(); + if (ignoreFile == QMessageBox::YesToAll) + { + showIgnoreFileDialog = false; + continue; + } + else if (ignoreFile == QMessageBox::Yes) + { + continue; + } + else + { + return false; + } + } + } + else + { + outNumCopiedFiles++; + + QFileInfo fileInfo(toBeCopiedFilePath); + outCopiedFileSize += fileInfo.size(); + } } return true; @@ -119,16 +228,13 @@ namespace O3DE::ProjectManager return false; } - QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - copyResult = CopyProject(origPath, newPath); - QGuiApplication::restoreOverrideCursor(); - + copyResult = CopyProject(origPath, newPath, parent); } return copyResult; } - bool CopyProject(const QString& origPath, const QString& newPath) + bool CopyProject(const QString& origPath, const QString& newPath, QWidget* parent) { // Disallow copying from or into subdirectory if (IsDirectoryDescedent(origPath, newPath) || IsDirectoryDescedent(newPath, origPath)) @@ -136,19 +242,54 @@ namespace O3DE::ProjectManager return false; } - if (!CopyDirectory(origPath, newPath)) + QStringList filesToCopy; + qint64 totalSizeInBytes = 0; + + QProgressDialog* progressDialog = new QProgressDialog(parent); + progressDialog->setAutoClose(true); + progressDialog->setValue(0); + progressDialog->setRange(0, 1000); + progressDialog->setModal(true); + progressDialog->setWindowTitle(QObject::tr("Copying project ...")); + progressDialog->show(); + + QLocale locale; + RecursiveGetAllFiles(origPath, filesToCopy, totalSizeInBytes, [=](int fileCount, int sizeInBytes) + { + // Create a human-readable version of the file size. + const QString fileSizeString = locale.formattedDataSize(sizeInBytes); + + progressDialog->setLabelText(QString("%1 ... %2 %3, %4 %5.") + .arg(QObject::tr("Indexing files")) + .arg(QString::number(fileCount)) + .arg(QObject::tr("files found")) + .arg(fileSizeString) + .arg(QObject::tr("to copy"))); + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + }); + + int numFilesCopied = 0; + qint64 copiedFileSize = 0; + + // Phase 1: Copy files + bool showIgnoreFileDialog = true; + bool success = CopyDirectory(progressDialog, origPath, newPath, filesToCopy, numFilesCopied, totalSizeInBytes, copiedFileSize, showIgnoreFileDialog); + if (success) { - // Cleanup whatever mess was made - DeleteProjectFiles(newPath, true); - return false; + // Phase 2: Register project + success = RegisterProject(newPath); } - if (!RegisterProject(newPath)) + if (!success) { + progressDialog->setLabelText(QObject::tr("Duplicating project failed/cancelled, removing already copied files ...")); + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + DeleteProjectFiles(newPath, true); } - return true; + progressDialog->deleteLater(); + return success; } bool DeleteProjectFiles(const QString& path, bool force) @@ -184,7 +325,7 @@ namespace O3DE::ProjectManager if (!newDirectory.rename(origPath, newPath)) { // Likely failed because trying to move to another partition, try copying - if (!CopyProject(origPath, newPath)) + if (!CopyProject(origPath, newPath, parent)) { return false; } @@ -272,7 +413,6 @@ namespace O3DE::ProjectManager bool IsVS2019Installed() { static bool vs2019Installed = IsVS2019Installed_internal(); - return vs2019Installed; } diff --git a/Code/Tools/ProjectManager/Source/ProjectUtils.h b/Code/Tools/ProjectManager/Source/ProjectUtils.h index 786ff34b88..2829a45180 100644 --- a/Code/Tools/ProjectManager/Source/ProjectUtils.h +++ b/Code/Tools/ProjectManager/Source/ProjectUtils.h @@ -17,7 +17,7 @@ namespace O3DE::ProjectManager bool RegisterProject(const QString& path); bool UnregisterProject(const QString& path); bool CopyProjectDialog(const QString& origPath, QWidget* parent = nullptr); - bool CopyProject(const QString& origPath, const QString& newPath); + bool CopyProject(const QString& origPath, const QString& newPath, QWidget* parent); bool DeleteProjectFiles(const QString& path, bool force = false); bool MoveProject(QString origPath, QString newPath, QWidget* parent = nullptr, bool ignoreRegister = false); diff --git a/Code/Tools/ProjectManager/Source/PythonBindings.cpp b/Code/Tools/ProjectManager/Source/PythonBindings.cpp index 167cf6d10e..f8e90b0a59 100644 --- a/Code/Tools/ProjectManager/Source/PythonBindings.cpp +++ b/Code/Tools/ProjectManager/Source/PythonBindings.cpp @@ -394,13 +394,20 @@ namespace O3DE::ProjectManager if (pybind11::isinstance(o3deData)) { engineInfo.m_path = Py_To_String(enginePath); - engineInfo.m_defaultGemsFolder = Py_To_String(o3deData["default_gems_folder"]); - engineInfo.m_defaultProjectsFolder = Py_To_String(o3deData["default_projects_folder"]); - engineInfo.m_defaultRestrictedFolder = Py_To_String(o3deData["default_restricted_folder"]); - engineInfo.m_defaultTemplatesFolder = Py_To_String(o3deData["default_templates_folder"]); + auto defaultGemsFolder = m_manifest.attr("get_o3de_gems_folder")(); + engineInfo.m_defaultGemsFolder = Py_To_String_Optional(o3deData, "default_gems_folder", Py_To_String(defaultGemsFolder)); + + auto defaultProjectsFolder = m_manifest.attr("get_o3de_projects_folder")(); + engineInfo.m_defaultProjectsFolder = Py_To_String_Optional(o3deData, "default_projects_folder", Py_To_String(defaultProjectsFolder)); + + auto defaultRestrictedFolder = m_manifest.attr("get_o3de_restricted_folder")(); + engineInfo.m_defaultRestrictedFolder = Py_To_String_Optional(o3deData, "default_restricted_folder", Py_To_String(defaultRestrictedFolder)); + + auto defaultTemplatesFolder = m_manifest.attr("get_o3de_templates_folder")(); + engineInfo.m_defaultTemplatesFolder = Py_To_String_Optional(o3deData, "default_templates_folder", Py_To_String(defaultTemplatesFolder)); auto defaultThirdPartyFolder = m_manifest.attr("get_o3de_third_party_folder")(); - engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData,"default_third_party_folder", Py_To_String(defaultThirdPartyFolder)); + engineInfo.m_thirdPartyPath = Py_To_String_Optional(o3deData, "default_third_party_folder", Py_To_String(defaultThirdPartyFolder)); } auto engineData = m_manifest.attr("get_engine_json_data")(pybind11::none(), enginePath); diff --git a/Code/Tools/ProjectManager/Source/TemplateButtonWidget.cpp b/Code/Tools/ProjectManager/Source/TemplateButtonWidget.cpp index d20b91ac8e..638b821e5d 100644 --- a/Code/Tools/ProjectManager/Source/TemplateButtonWidget.cpp +++ b/Code/Tools/ProjectManager/Source/TemplateButtonWidget.cpp @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -16,7 +17,6 @@ namespace O3DE::ProjectManager { - TemplateButton::TemplateButton(const QString& imagePath, const QString& labelText, QWidget* parent) : QPushButton(parent) { @@ -31,8 +31,8 @@ namespace O3DE::ProjectManager QLabel* image = new QLabel(this); image->setObjectName("templateImage"); - image->setPixmap( - QPixmap(imagePath).scaled(QSize(s_templateImageWidth,s_templateImageHeight) , Qt::KeepAspectRatio, Qt::SmoothTransformation)); + image->setPixmap(QPixmap(imagePath).scaled( + QSize(ProjectTemplateImageWidth, ProjectTemplateImageWidth), Qt::KeepAspectRatio, Qt::SmoothTransformation)); vLayout->addWidget(image); QLabel* label = new QLabel(labelText, this); diff --git a/Code/Tools/ProjectManager/Source/TemplateButtonWidget.h b/Code/Tools/ProjectManager/Source/TemplateButtonWidget.h index 2b2b3474c2..0607b8fbfe 100644 --- a/Code/Tools/ProjectManager/Source/TemplateButtonWidget.h +++ b/Code/Tools/ProjectManager/Source/TemplateButtonWidget.h @@ -24,9 +24,5 @@ namespace O3DE::ProjectManager protected slots: void onToggled(); - - private: - inline constexpr static int s_templateImageWidth = 92; - inline constexpr static int s_templateImageHeight = 122; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index a5632f082c..07c649624e 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -71,6 +71,8 @@ set(FILES Source/GemCatalog/GemCatalogHeaderWidget.cpp Source/GemCatalog/GemCatalogScreen.h Source/GemCatalog/GemCatalogScreen.cpp + Source/GemCatalog/GemFilterTagWidget.h + Source/GemCatalog/GemFilterTagWidget.cpp Source/GemCatalog/GemFilterWidget.h Source/GemCatalog/GemFilterWidget.cpp Source/GemCatalog/GemInfo.h diff --git a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp index 7e2540cf44..7be98ab056 100644 --- a/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp +++ b/Gems/Atom/Asset/Shader/Code/Source/Editor/ShaderVariantAssetBuilder.cpp @@ -425,16 +425,16 @@ namespace AZ { const auto& jobParameters = request.m_jobDescription.m_jobParameters; - if (jobParameters.find(ShaderVariantLoadErrorParam) != jobParameters.end()) + if (jobParameters.contains(ShaderVariantLoadErrorParam)) { AZ_Error(ShaderVariantAssetBuilderName, false, "Error during CreateJobs: %s", jobParameters.at(ShaderVariantLoadErrorParam).c_str()); response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed; return; } - if (jobParameters.find(ShouldExitEarlyFromProcessJobParam) != jobParameters.end()) + if (jobParameters.contains(ShouldExitEarlyFromProcessJobParam)) { - AZ_TracePrintf(ShaderVariantAssetBuilderName, "Doing nothing on behalf of [%s] because it's been overridden by game project.", jobParameters.at(ShaderVariantLoadErrorParam).c_str()); + AZ_TracePrintf(ShaderVariantAssetBuilderName, "Doing nothing on behalf of [%s] because it's been overridden by game project.", jobParameters.at(ShouldExitEarlyFromProcessJobParam).c_str()); response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success; return; } diff --git a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ParallaxMapping.azsli b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ParallaxMapping.azsli index 2c2f956f8f..c979cff128 100644 --- a/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ParallaxMapping.azsli +++ b/Gems/Atom/Feature/Common/Assets/ShaderLib/Atom/Features/ParallaxMapping.azsli @@ -427,7 +427,7 @@ PixelDepthOffset CalcPixelDepthOffset( float depthFactor, float4 clipOffsetPosition = mul(viewProjectionMatrix, float4(worldOffsetPosition, 1.0)); PixelDepthOffset pdo; - pdo.m_depthCS = clipOffsetPosition.z; + pdo.m_depthCS = clipOffsetPosition.w; pdo.m_depthNDC = clipOffsetPosition.z / clipOffsetPosition.w; pdo.m_worldPosition = worldOffsetPosition; return pdo; diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/SkinnedMesh/LinearSkinningCS.azsl b/Gems/Atom/Feature/Common/Assets/Shaders/SkinnedMesh/LinearSkinningCS.azsl index fc5684fe7f..99d38463c7 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/SkinnedMesh/LinearSkinningCS.azsl +++ b/Gems/Atom/Feature/Common/Assets/Shaders/SkinnedMesh/LinearSkinningCS.azsl @@ -14,6 +14,15 @@ option enum class SkinningMethod { LinearSkinning, DualQuaternion } o_skinningMe option bool o_applyMorphTargets = false; option bool o_applyColorMorphTargets = false; +float3 ReadFloat3FromFloatBuffer(Buffer buffer, uint index) +{ + float3 result; + result.x = buffer[index * 3]; + result.y = buffer[index * 3 + 1]; + result.z = buffer[index * 3 + 2]; + return result; +} + // Apply a morph target delta with three components void ApplyMorphTargetDelta(uint streamOffset, uint vertexIndex, inout float3 modifiedValue) { @@ -162,10 +171,10 @@ void MainCS(uint3 thread_id: SV_DispatchThreadID) return; } - float3 position = InstanceSrg::m_sourcePositions[i]; - float3 normal = InstanceSrg::m_sourceNormals[i]; - float4 tangent = InstanceSrg::m_sourceTangents[i]; - float3 bitangent = InstanceSrg::m_sourceBiTangents[i]; + float3 position = ReadFloat3FromFloatBuffer(InstanceSrg::m_sourcePositions, i); + float3 normal = ReadFloat3FromFloatBuffer(InstanceSrg::m_sourceNormals, i); + float4 tangent = InstanceSrg::m_sourceTangents[i]; + float3 bitangent = ReadFloat3FromFloatBuffer(InstanceSrg::m_sourceBiTangents, i); // Four indices, 16-bits each, stored in 2 32-bit uints uint2 rawIndices = InstanceSrg::m_sourceBlendIndices.Load2(i * 8); diff --git a/Gems/Atom/Feature/Common/Assets/Shaders/SkinnedMesh/LinearSkinningPassSRG.azsli b/Gems/Atom/Feature/Common/Assets/Shaders/SkinnedMesh/LinearSkinningPassSRG.azsli index 95802ddbb7..066cefdc37 100644 --- a/Gems/Atom/Feature/Common/Assets/Shaders/SkinnedMesh/LinearSkinningPassSRG.azsli +++ b/Gems/Atom/Feature/Common/Assets/Shaders/SkinnedMesh/LinearSkinningPassSRG.azsli @@ -20,10 +20,12 @@ ShaderResourceGroup InstanceSrg : SRG_PerDraw uint m_totalNumberOfThreadsX; // Per-model input - Buffer m_sourcePositions; // POSITION 0 - Buffer m_sourceNormals; // NORMAL 0 + // Positions, normals, and bitangents are all 3-component per-vertex buffers, + // but Metal doesn't support float3 buffers so Buffer is used instead + Buffer m_sourcePositions; // POSITION 0 + Buffer m_sourceNormals; // NORMAL 0 Buffer m_sourceTangents; // TANGENT 0 - Buffer m_sourceBiTangents; // BITANGENT 0 + Buffer m_sourceBiTangents; // BITANGENT 0 ByteAddressBuffer m_sourceBlendIndices; // BLENDINDICES 0 Buffer m_sourceBlendWeights; // BLENDWEIGHTS 0 diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp index e435de7799..438c8c2f28 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.cpp @@ -245,6 +245,29 @@ namespace AZ m_bakedClassificationImage.get(); } + void DiffuseProbeGrid::ResetCullingVisibility() + { + m_cullable.m_isVisible = false; + } + + bool DiffuseProbeGrid::GetIsVisible() const + { + // we need to go through the DiffuseProbeGrid passes at least once in order to initialize + // the RenderObjectSrg, which means we need to be visible until the RenderObjectSrg is created + if (m_renderObjectSrg == nullptr) + { + return true; + } + + // if a bake is in progress we need to make this DiffuseProbeGrid visible + if (!m_textureReadback.IsIdle()) + { + return true; + } + + return m_cullable.m_isVisible; + } + uint32_t DiffuseProbeGrid::GetTotalProbeCount() const { return m_probeCountX * m_probeCountY * m_probeCountZ; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h index 3c5c481fea..06fa8592a3 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGrid.h @@ -103,6 +103,9 @@ namespace AZ void DecrementRemainingRelocationIterations() { m_remainingRelocationIterations = AZStd::max(0, m_remainingRelocationIterations - 1); } void ResetRemainingRelocationIterations() { m_remainingRelocationIterations = DefaultNumRelocationIterations; } + void ResetCullingVisibility(); + bool GetIsVisible() const; + // compute total number of probes in the grid uint32_t GetTotalProbeCount() const; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp index e8c99a630f..f75c62cd6c 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendDistancePass.cpp @@ -82,7 +82,7 @@ namespace AZ RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().empty()) + if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) { // no diffuse probe grids return; @@ -106,7 +106,7 @@ namespace AZ RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { // probe raytrace image { @@ -145,7 +145,7 @@ namespace AZ RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { // the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs // (see ValidateSetImageView() in ShaderResourceGroupData.cpp) @@ -162,7 +162,7 @@ namespace AZ DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); // submit the DispatchItem for each DiffuseProbeGrid - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetBlendDistanceSrg()->GetRHIShaderResourceGroup(); commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup); diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp index 637c655074..748f0b8093 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBlendIrradiancePass.cpp @@ -82,7 +82,7 @@ namespace AZ RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().empty()) + if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) { // no diffuse probe grids return; @@ -106,7 +106,7 @@ namespace AZ RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { // probe raytrace image { @@ -145,7 +145,7 @@ namespace AZ RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { // the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs // (see ValidateSetImageView() in ShaderResourceGroupData.cpp) @@ -162,7 +162,7 @@ namespace AZ DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); // submit the DispatchItem for each DiffuseProbeGrid - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetBlendIrradianceSrg()->GetRHIShaderResourceGroup(); commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup); diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp index f437b3a1ef..a46ee0e550 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridBorderUpdatePass.cpp @@ -95,7 +95,7 @@ namespace AZ RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().empty()) + if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) { // no diffuse probe grids return; @@ -119,7 +119,7 @@ namespace AZ RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { // probe irradiance image { @@ -148,7 +148,7 @@ namespace AZ RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { // the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs // (see line ValidateSetImageView() in ShaderResourceGroupData.cpp) @@ -168,7 +168,7 @@ namespace AZ DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); // submit the DispatchItems for each DiffuseProbeGrid - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { uint32_t probeCountX; uint32_t probeCountY; diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp index 93297fe336..7ddc3f7d68 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridClassificationPass.cpp @@ -86,7 +86,7 @@ namespace AZ RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().empty()) + if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) { // no diffuse probe grids return; @@ -110,7 +110,7 @@ namespace AZ RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { // probe raytrace image { @@ -138,7 +138,7 @@ namespace AZ { RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { // the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs // (see ValidateSetImageView() in ShaderResourceGroupData.cpp) @@ -154,7 +154,7 @@ namespace AZ DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); // submit the DispatchItems for each DiffuseProbeGrid - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetClassificationSrg()->GetRHIShaderResourceGroup(); commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup); diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp index 5ceb8a197d..a001f60e89 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.cpp @@ -175,6 +175,27 @@ namespace AZ } } + void DiffuseProbeGridFeatureProcessor::OnBeginPrepareRender() + { + for (auto& diffuseProbeGrid : m_realTimeDiffuseProbeGrids) + { + diffuseProbeGrid->ResetCullingVisibility(); + } + } + + void DiffuseProbeGridFeatureProcessor::OnEndPrepareRender() + { + // re-build the list of visible real-time diffuse probe grids + m_visibleRealTimeDiffuseProbeGrids.clear(); + for (auto& diffuseProbeGrid : m_realTimeDiffuseProbeGrids) + { + if (diffuseProbeGrid->GetIsVisible()) + { + m_visibleRealTimeDiffuseProbeGrids.push_back(diffuseProbeGrid); + } + } + } + DiffuseProbeGridHandle DiffuseProbeGridFeatureProcessor::AddProbeGrid(const AZ::Transform& transform, const AZ::Vector3& extents, const AZ::Vector3& probeSpacing) { AZStd::shared_ptr diffuseProbeGrid = AZStd::make_shared(); @@ -215,6 +236,17 @@ namespace AZ m_realTimeDiffuseProbeGrids.erase(itEntry); } + // remove from side list of visible real-time grids + itEntry = AZStd::find_if(m_visibleRealTimeDiffuseProbeGrids.begin(), m_visibleRealTimeDiffuseProbeGrids.end(), [&](AZStd::shared_ptr const& entry) + { + return (entry == probeGrid); + }); + + if (itEntry != m_visibleRealTimeDiffuseProbeGrids.end()) + { + m_visibleRealTimeDiffuseProbeGrids.erase(itEntry); + } + probeGrid = nullptr; } diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h index 4d045ec62d..9771c058ad 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridFeatureProcessor.h @@ -76,6 +76,9 @@ namespace AZ // retrieve the side list of probe grids that are using real-time (raytraced) mode DiffuseProbeGridVector& GetRealTimeProbeGrids() { return m_realTimeDiffuseProbeGrids; } + // retrieve the side list of probe grids that are using real-time (raytraced) mode and visible (on screen) + DiffuseProbeGridVector& GetVisibleRealTimeProbeGrids() { return m_visibleRealTimeDiffuseProbeGrids; } + private: AZ_DISABLE_COPY_MOVE(DiffuseProbeGridFeatureProcessor); @@ -96,6 +99,8 @@ namespace AZ void HandleAssetNotification(Data::Asset asset, DiffuseProbeGridTextureNotificationType notificationType); // RPI::SceneNotificationBus::Handler overrides + void OnBeginPrepareRender() override; + void OnEndPrepareRender() override; void OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) override; void OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline) override; void OnRenderPipelineRemoved(RPI::RenderPipeline* pipeline) override; @@ -110,6 +115,9 @@ namespace AZ // side list of diffuse probe grids that are in real-time mode (subset of m_diffuseProbeGrids) DiffuseProbeGridVector m_realTimeDiffuseProbeGrids; + // side list of diffuse probe grids that are in real-time mode and visible (subset of m_realTimeDiffuseProbeGrids) + DiffuseProbeGridVector m_visibleRealTimeDiffuseProbeGrids; + // position structure for the box vertices struct Position { diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp index 8079912363..2ff9c5991e 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRayTracingPass.cpp @@ -130,7 +130,7 @@ namespace AZ } DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().empty()) + if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) { // no diffuse probe grids return; @@ -147,9 +147,9 @@ namespace AZ DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); RayTracingFeatureProcessor* rayTracingFeatureProcessor = scene->GetFeatureProcessor(); - frameGraph.SetEstimatedItemCount(aznumeric_cast(diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().size())); + frameGraph.SetEstimatedItemCount(aznumeric_cast(diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().size())); - for (const auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (const auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { // TLAS { @@ -254,7 +254,7 @@ namespace AZ rayTracingFeatureProcessor->GetMeshInfoBuffer() && rayTracingFeatureProcessor->GetSubMeshCount()) { - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { // the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader // inputs (see line ValidateSetImageView() in ShaderResourceGroupData.cpp) @@ -302,7 +302,7 @@ namespace AZ m_rayTracingShaderTable) { // submit the DispatchRaysItem for each DiffuseProbeGrid - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { const RHI::ShaderResourceGroup* shaderResourceGroups[] = { diffuseProbeGrid->GetRayTraceSrg()->GetRHIShaderResourceGroup(), diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp index c6464fcc72..efdfbebcae 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRelocationPass.cpp @@ -86,7 +86,7 @@ namespace AZ RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids().empty()) + if (!diffuseProbeGridFeatureProcessor || diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids().empty()) { // no diffuse probe grids return; @@ -103,7 +103,7 @@ namespace AZ // create the Relocation Srgs for each DiffuseProbeGrid, and check to see if any grids need relocation bool needRelocation = false; - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { uint32_t rayTracingDataRevision = rayTracingFeatureProcessor->GetRevision(); if (rayTracingDataRevision != m_rayTracingDataRevision) @@ -134,7 +134,7 @@ namespace AZ RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { // probe raytrace image { @@ -162,7 +162,7 @@ namespace AZ { RPI::Scene* scene = m_pipeline->GetScene(); DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { // the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs // (see ValidateSetImageView() in ShaderResourceGroupData.cpp) @@ -182,7 +182,7 @@ namespace AZ DiffuseProbeGridFeatureProcessor* diffuseProbeGridFeatureProcessor = scene->GetFeatureProcessor(); // submit the DispatchItems for each DiffuseProbeGrid - for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetRealTimeProbeGrids()) + for (auto& diffuseProbeGrid : diffuseProbeGridFeatureProcessor->GetVisibleRealTimeProbeGrids()) { const RHI::ShaderResourceGroup* shaderResourceGroup = diffuseProbeGrid->GetRelocationSrg()->GetRHIShaderResourceGroup(); commandList->SetShaderResourceGroupForDispatch(*shaderResourceGroup); diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp index 6f6f83dda2..a50d0084f1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridRenderPass.cpp @@ -94,7 +94,12 @@ namespace AZ { continue; } - + + if (!diffuseProbeGrid->GetIsVisible()) + { + continue; + } + // probe irradiance image { if (diffuseProbeGrid->GetMode() == DiffuseProbeGridMode::Baked) @@ -182,6 +187,11 @@ namespace AZ continue; } + if (!diffuseProbeGrid->GetIsVisible()) + { + continue; + } + // the diffuse probe grid Srg must be updated in the Compile phase in order to successfully bind the ReadWrite shader inputs // (see ValidateSetImageView() of ShaderResourceGroupData.cpp) diffuseProbeGrid->UpdateRenderObjectSrg(); diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.cpp b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.cpp index 3e808a99c1..8931a4feb1 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.cpp @@ -22,7 +22,9 @@ namespace AZ AZ_Assert(m_readbackState == DiffuseProbeGridReadbackState::Idle, "DiffuseProbeGridTextureReadback is already processing a readback request"); m_callback = callback; - m_readbackState = DiffuseProbeGridReadbackState::Irradiance; + + m_remainingInitializationFrames = DefaultNumInitializationFrames; + m_readbackState = DiffuseProbeGridReadbackState::Initializing; } void DiffuseProbeGridTextureReadback::Update(const AZ::Name& passName) @@ -32,6 +34,19 @@ namespace AZ return; } + if (m_readbackState == DiffuseProbeGridReadbackState::Initializing) + { + if (m_remainingInitializationFrames > 0) + { + // still in the initialization state to allow the irradiance textures to settle, decrement the frame count + m_remainingInitializationFrames--; + return; + } + + // settling complete, move to the irradiance readback state to begin the readback process + m_readbackState = DiffuseProbeGridReadbackState::Irradiance; + } + if (m_attachmentReadback.get() && m_attachmentReadback->GetReadbackState() > RPI::AttachmentReadback::ReadbackState::Idle) { // still processing previous request diff --git a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.h b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.h index c399fac534..b0d35069a7 100644 --- a/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.h +++ b/Gems/Atom/Feature/Common/Code/Source/DiffuseGlobalIllumination/DiffuseProbeGridTextureReadback.h @@ -20,6 +20,7 @@ namespace AZ enum class DiffuseProbeGridReadbackState { Idle, + Initializing, Irradiance, Distance, Relocation, @@ -39,6 +40,8 @@ namespace AZ void Update(const AZ::Name& passName); void FrameBegin(AZ::RPI::Pass::FramePrepareParams& params); + bool IsIdle() const { return m_readbackState == DiffuseProbeGridReadbackState::Idle; } + private: DiffuseProbeGrid* m_diffuseProbeGrid = nullptr; @@ -50,6 +53,10 @@ namespace AZ AZ::RPI::AttachmentReadback::ReadbackResult m_distanceReadbackResult; AZ::RPI::AttachmentReadback::ReadbackResult m_relocationReadbackResult; AZ::RPI::AttachmentReadback::ReadbackResult m_classificationReadbackResult; + + // number of frames to delay before starting the texture readbacks, this allows the textures to settle + static constexpr int32_t DefaultNumInitializationFrames = 50; + int32_t m_remainingInitializationFrames = DefaultNumInitializationFrames; }; } // namespace Render } // namespace AZ diff --git a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp index 3ec7bd4186..36e4689325 100644 --- a/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/ReflectionProbe/ReflectionProbeFeatureProcessor.cpp @@ -266,6 +266,10 @@ namespace AZ { AZ_Assert(probe.get(), "SetProbeCubeMap called with an invalid handle"); probe->SetCubeMapImage(cubeMapImage, relativePath); + + // notify the MeshFeatureProcessor that the reflection probe changed + MeshFeatureProcessor* meshFeatureProcessor = GetParentScene()->GetFeatureProcessor(); + meshFeatureProcessor->UpdateMeshReflectionProbes(); } void ReflectionProbeFeatureProcessor::SetProbeTransform(const ReflectionProbeHandle& probe, const AZ::Transform& transform) diff --git a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp index 75d079c937..8ef82dfac4 100644 --- a/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp +++ b/Gems/Atom/Feature/Common/Code/Source/SkinnedMesh/SkinnedMeshInputBuffers.cpp @@ -118,7 +118,29 @@ namespace AZ } m_inputBufferAssets[static_cast(inputStream)] = bufferAsset; - m_inputBuffers[static_cast(inputStream)] = RPI::Buffer::FindOrCreate(bufferAsset); + Data::Instance buffer = RPI::Buffer::FindOrCreate(bufferAsset); + m_inputBuffers[static_cast(inputStream)] = buffer; + + // Create a buffer view to use as input to the skinning shader + AZ::RHI::Ptr bufferView = RHI::Factory::Get().CreateBufferView(); + bufferView->SetName(Name{ AZStd::string(buffer->GetBufferView()->GetName().GetStringView()) + "_SkinningInputBufferView" }); + RHI::BufferViewDescriptor bufferViewDescriptor = bufferAsset->GetBufferViewDescriptor(); + + // 3-component float buffers are not supported on metal for non-input assembly buffer views, so use a float view instead + if (bufferViewDescriptor.m_elementFormat == RHI::Format::R32G32B32_FLOAT) + { + // Use one float per element, with 3x as many elements + bufferViewDescriptor = RHI::BufferViewDescriptor::CreateTyped( + bufferViewDescriptor.m_elementOffset * 3, bufferViewDescriptor.m_elementCount * 3, RHI::Format::R32_FLOAT); + } + + [[maybe_unused]] RHI::ResultCode resultCode = + bufferView->Init(*buffer->GetRHIBuffer(), bufferViewDescriptor); + AZ_Error( + "SkinnedMeshInputBuffers", resultCode == RHI::ResultCode::Success, + "Failed to initialize buffer view for skinned mesh input."); + + m_bufferViews[static_cast(inputStream)] = bufferView; } void SkinnedMeshInputLod::SetStaticBufferAsset(const Data::Asset bufferAsset, SkinnedMeshStaticVertexStreams staticStream) @@ -315,7 +337,7 @@ namespace AZ [[maybe_unused]] bool success = false; if (m_lods[lodIndex].m_inputBuffers[inputStream]) { - success = perInstanceSRG->SetBufferView(srgIndex, m_lods[lodIndex].m_inputBuffers[inputStream]->GetBufferView()); + success = perInstanceSRG->SetBufferView(srgIndex, m_lods[lodIndex].m_bufferViews[inputStream].get()); } AZ_Error("SkinnedMeshInputBuffers", success, "Failed to bind buffer view for %s", streamInfo.m_bufferName.GetCStr()); diff --git a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h index eb35a29e26..697e58cdd4 100644 --- a/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h +++ b/Gems/Atom/RHI/Code/Include/Atom/RHI/CpuProfilerImpl.h @@ -9,13 +9,13 @@ #include #include +#include #include #include #include #include #include -#include namespace AZ { @@ -83,7 +83,7 @@ namespace AZ //! cached regions, which are stored on a per thread frequency. class CpuProfilerImpl final : public CpuProfiler - , public FrameEventBus::Handler + , public SystemTickBus::Handler { friend class CpuTimingLocalStorage; @@ -99,7 +99,10 @@ namespace AZ //! Unregisters the CpuProfilerImpl instance from the interface void Shutdown(); - void OnFrameBegin(); + // SystemTickBus::Handler overrides + // When fired, the profiler collects all profiling data from registered threads and updates + // m_timeRegionMap so that the next frame has up-to-date profiling data. + void OnSystemTick() final override; //! CpuProfiler overrides... void BeginTimeRegion(TimeRegion& timeRegion) final; diff --git a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp index b31fbca6f2..187dfca1d9 100644 --- a/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp +++ b/Gems/Atom/RHI/Code/Source/RHI/CpuProfilerImpl.cpp @@ -79,8 +79,7 @@ namespace AZ { Interface::Register(this); m_initialized = true; - Device* rhiDevice = GetRHIDevice().get(); - FrameEventBus::Handler::BusConnect(rhiDevice); + SystemTickBus::Handler::BusConnect(); } void CpuProfilerImpl::Shutdown() @@ -101,7 +100,7 @@ namespace AZ m_registeredThreads.clear(); m_timeRegionMap.clear(); m_initialized = false; - FrameEventBus::Handler::BusDisconnect(); + SystemTickBus::Handler::BusDisconnect(); } void CpuProfilerImpl::BeginTimeRegion(TimeRegion& timeRegion) @@ -173,7 +172,7 @@ namespace AZ return m_enabled; } - void CpuProfilerImpl::OnFrameBegin() + void CpuProfilerImpl::OnSystemTick() { if (!m_enabled) { @@ -199,7 +198,6 @@ namespace AZ m_timeRegionMap = AZStd::move(newMap); } - void CpuProfilerImpl::RegisterThreadStorage() { AZStd::unique_lock lock(m_threadRegisterMutex); diff --git a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h index 72d0e3c69c..7f042e58cb 100644 --- a/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h +++ b/Gems/Atom/RPI/Code/Include/Atom/RPI.Public/Culling.h @@ -91,6 +91,10 @@ namespace AZ }; LodData m_lodData; + //! Flag indicating if the object is visible in any view, meaning it passed the culling tests in the previous frame. + //! This flag must be manually cleared by the Cullable object every frame. + bool m_isVisible = false; + //! Flag indicating if the object is hidden, i.e., was specifically marked as //! something that shouldn't be rendered, regardless of its actual position relative to the camera bool m_isHidden = false; diff --git a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp index cd1b0e925a..c78d8e8169 100644 --- a/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp +++ b/Gems/Atom/RPI/Code/Source/RPI.Public/Culling.cpp @@ -339,6 +339,7 @@ namespace AZ { numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view); ++numVisibleCullables; + c->m_isVisible = true; } } } @@ -374,6 +375,7 @@ namespace AZ { numDrawPackets += AddLodDataToView(c->m_cullData.m_boundingSphere.GetCenter(), c->m_lodData, *m_jobData->m_view); ++numVisibleCullables; + c->m_isVisible = true; } } } diff --git a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl index e349685fd3..cc1bc9b3c0 100644 --- a/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl +++ b/Gems/Atom/Utils/Code/Include/Atom/Utils/ImGuiCpuProfiler.inl @@ -649,7 +649,10 @@ namespace AZ // End ticks are sorted in increasing order, find the first frame bound to draw auto endTickItr = AZStd::lower_bound(m_frameEndTicks.begin(), m_frameEndTicks.end(), m_viewportStartTick); - while (endTickItr != m_frameEndTicks.end() && *endTickItr < m_viewportEndTick) + // Draw to one element before the last collected boundary if possible to avoid empty frame at the end + auto drawToItr = m_frameEndTicks.size() > 1 ? m_frameEndTicks.end() - 1 : m_frameEndTicks.end(); + + while (endTickItr != drawToItr && *endTickItr < m_viewportEndTick) { const float horizontalPixel = ConvertTickToPixelSpace(*endTickItr); drawList->AddLine({ horizontalPixel, wy }, { horizontalPixel, wy + windowHeight }, red); @@ -670,7 +673,9 @@ namespace AZ const auto [wx, wy] = ImGui::GetWindowPos(); ImDrawList* drawList = ImGui::GetWindowDrawList(); - while (nextFrameBoundaryItr != m_frameEndTicks.end()) + auto drawToItr = m_frameEndTicks.size() > 1 ? m_frameEndTicks.end() - 1 : m_frameEndTicks.end(); + + while (nextFrameBoundaryItr != drawToItr && *lastFrameBoundaryItr <= m_viewportEndTick) { const AZStd::sys_time_t lastFrameBoundaryTick = *lastFrameBoundaryItr; const AZStd::sys_time_t nextFrameBoundaryTick = *nextFrameBoundaryItr; @@ -750,7 +755,10 @@ namespace AZ // System tick bus overrides inline void ImGuiCpuProfiler::OnSystemTick() { - m_frameEndTicks.push_back(AZStd::GetTimeNowTicks()); + if (!m_paused) + { + m_frameEndTicks.push_back(AZStd::GetTimeNowTicks()); + } if (!m_showVisualizer || m_paused) { diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentConfig.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentConfig.cpp index 3923136bcc..5325ba911d 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentConfig.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/DirectionalLightComponentConfig.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace AZ { @@ -55,21 +56,15 @@ namespace AZ case PhotometricUnit::Lux: return 0.0f; case PhotometricUnit::Ev100Illuminance: - return -10.0f; + return AZStd::numeric_limits::lowest(); } return 0.0f; } float DirectionalLightComponentConfig::GetIntensityMax() const { - switch (m_intensityMode) - { - case PhotometricUnit::Lux: - return 1'000'000.0f; - case PhotometricUnit::Ev100Illuminance: - return 20.0f; - } - return 0.0f; + // While there is no hard-max, a max must be included when there is a hard min. + return AZStd::numeric_limits::max(); } float DirectionalLightComponentConfig::GetIntensitySoftMin() const diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp index 81e87f3cb5..c27faa2241 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorAreaLightComponent.cpp @@ -154,19 +154,19 @@ namespace AZ ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsPcfBoundarySearchDisabled) ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_predictionSampleCount, "Prediction sample count", - "Sample Count for prediction of whether the pixel is on the boundary. Specific to PCF and ESM+PCF.") + "Sample count for prediction of whether the pixel is on the boundary. Specific to PCF and ESM+PCF.") ->Attribute(Edit::Attributes::Min, 4) ->Attribute(Edit::Attributes::Max, 16) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsPcfBoundarySearchDisabled) ->DataElement(Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_filteringSampleCount, "Filtering sample count", - "It is used only when the pixel is predicted to be on the boundary. Specific to PCF and ESM+PCF.") + "This is only used when the pixel is predicted to be on the boundary. Specific to PCF and ESM+PCF.") ->Attribute(Edit::Attributes::Min, 4) ->Attribute(Edit::Attributes::Max, 64) ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsShadowPcfDisabled) ->DataElement( - Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_pcfMethod, "Pcf method", + Edit::UIHandlers::ComboBox, &AreaLightComponentConfig::m_pcfMethod, "PCF method", "Type of PCF to use.\n" " Bicubic: a smooth, fixed-size kernel \n" " Boundary search: do several taps to first determine if we are on a shadow boundary\n") @@ -176,8 +176,8 @@ namespace AZ ->Attribute(Edit::Attributes::Visibility, &AreaLightComponentConfig::SupportsShadows) ->Attribute(Edit::Attributes::ReadOnly, &AreaLightComponentConfig::IsShadowPcfDisabled) ->DataElement( - Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_esmExponent, "Esm Exponent", - "Exponent used by Esm shadows. " + Edit::UIHandlers::Slider, &AreaLightComponentConfig::m_esmExponent, "ESM exponent", + "Exponent used by ESM shadows. " "Larger values increase the sharpness of the border between lit and unlit areas.") ->Attribute(Edit::Attributes::Min, 50.0f) ->Attribute(Edit::Attributes::Max, 5000.0f) diff --git a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp index 8163dcfe20..4d43c23e25 100644 --- a/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp +++ b/Gems/AtomLyIntegration/CommonFeatures/Code/Source/CoreLights/EditorDirectionalLightComponent.cpp @@ -57,74 +57,74 @@ namespace AZ editContext->Class("DirectionalLightComponentConfig", "") ->ClassElement(Edit::ClassElements::EditorData, "") ->DataElement(Edit::UIHandlers::Color, &DirectionalLightComponentConfig::m_color, "Color", "Color of the light") - ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->Attribute("ColorEditorConfiguration", AZ::RPI::ColorUtils::GetLinearRgbEditorConfig()) - ->DataElement(Edit::UIHandlers::ComboBox, &DirectionalLightComponentConfig::m_intensityMode, "Intensity Mode", "Allows specifying light values in lux or Ev100") - ->EnumAttribute(PhotometricUnit::Lux, "Lux") - ->EnumAttribute(PhotometricUnit::Ev100Illuminance, "Ev100") - ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues) + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->Attribute("ColorEditorConfiguration", AZ::RPI::ColorUtils::GetLinearRgbEditorConfig()) + ->DataElement(Edit::UIHandlers::ComboBox, &DirectionalLightComponentConfig::m_intensityMode, "Intensity mode", "Allows specifying light values in lux or Ev100") + ->EnumAttribute(PhotometricUnit::Lux, "Lux") + ->EnumAttribute(PhotometricUnit::Ev100Illuminance, "Ev100") + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::AttributesAndValues) ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_intensity, "Intensity", "Intensity of the light in the set photometric unit.") - ->Attribute(Edit::Attributes::Min, &DirectionalLightComponentConfig::GetIntensityMin) - ->Attribute(Edit::Attributes::Max, &DirectionalLightComponentConfig::GetIntensityMax) - ->Attribute(Edit::Attributes::SoftMin, &DirectionalLightComponentConfig::GetIntensitySoftMin) - ->Attribute(Edit::Attributes::SoftMax, &DirectionalLightComponentConfig::GetIntensitySoftMax) - ->Attribute(Edit::Attributes::Suffix, &DirectionalLightComponentConfig::GetIntensitySuffix) - ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_angularDiameter, "Angular Diameter", "Angular Diameter of the directional light in degrees. The sun is about 0.5.") - ->Attribute(Edit::Attributes::Min, 0.0f) - ->Attribute(Edit::Attributes::Max, 5.0f) - ->Attribute(Edit::Attributes::SoftMax, 1.0f) - ->Attribute(Edit::Attributes::Suffix, " deg") + ->Attribute(Edit::Attributes::Min, &DirectionalLightComponentConfig::GetIntensityMin) + ->Attribute(Edit::Attributes::Max, &DirectionalLightComponentConfig::GetIntensityMax) + ->Attribute(Edit::Attributes::SoftMin, &DirectionalLightComponentConfig::GetIntensitySoftMin) + ->Attribute(Edit::Attributes::SoftMax, &DirectionalLightComponentConfig::GetIntensitySoftMax) + ->Attribute(Edit::Attributes::Suffix, &DirectionalLightComponentConfig::GetIntensitySuffix) + ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_angularDiameter, "Angular diameter", "Angular diameter of the directional light in degrees. The sun is about 0.5.") + ->Attribute(Edit::Attributes::Min, 0.0f) + ->Attribute(Edit::Attributes::Max, 5.0f) + ->Attribute(Edit::Attributes::SoftMax, 1.0f) + ->Attribute(Edit::Attributes::Suffix, " deg") ->ClassElement(AZ::Edit::ClassElements::Group, "Shadow") - ->Attribute(AZ::Edit::Attributes::AutoExpand, true) + ->Attribute(AZ::Edit::Attributes::AutoExpand, true) ->DataElement(Edit::UIHandlers::EntityId, &DirectionalLightComponentConfig::m_cameraEntityId, "Camera", "Entity of the camera for cascaded shadowmap view frustum.") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->DataElement(Edit::UIHandlers::Default, &DirectionalLightComponentConfig::m_shadowFarClipDistance, "Shadow Far Clip", "Shadow sepcific far clip distance.") + ->DataElement(Edit::UIHandlers::Default, &DirectionalLightComponentConfig::m_shadowFarClipDistance, "Shadow far clip", "Shadow specific far clip distance.") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->DataElement(Edit::UIHandlers::ComboBox, &DirectionalLightComponentConfig::m_shadowmapSize, "Shadowmap Size", "Width/Height of shadowmap") + ->DataElement(Edit::UIHandlers::ComboBox, &DirectionalLightComponentConfig::m_shadowmapSize, "Shadowmap size", "Width/Height of shadowmap") ->EnumAttribute(ShadowmapSize::Size256, " 256") ->EnumAttribute(ShadowmapSize::Size512, " 512") ->EnumAttribute(ShadowmapSize::Size1024, "1024") ->EnumAttribute(ShadowmapSize::Size2048, "2048") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_cascadeCount, "Cascade Count", "Number of cascades") + ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_cascadeCount, "Cascade count", "Number of cascades") ->Attribute(Edit::Attributes::Min, 1) ->Attribute(Edit::Attributes::Max, Shadow::MaxNumberOfCascades) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->DataElement(Edit::UIHandlers::Default, &DirectionalLightComponentConfig::m_isShadowmapFrustumSplitAutomatic, "Split Automatic", + ->DataElement(Edit::UIHandlers::Default, &DirectionalLightComponentConfig::m_isShadowmapFrustumSplitAutomatic, "Automatic splitting", "Switch splitting of shadowmap frustum to cascades automatically or not.") - ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_shadowmapFrustumSplitSchemeRatio, "Split Ratio", + ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_shadowmapFrustumSplitSchemeRatio, "Split ratio", "Ratio to lerp between the two types of frustum splitting scheme.\n" - "0 = Uniform scheme which will split the Frustum evenly across all cascades.\n" + "0 = Uniform scheme which will split the frustum evenly across all cascades.\n" "1 = Logarithmic scheme which is designed to split the frustum in a logarithmic fashion " "in order to enable us to produce a more optimal perspective aliasing across the frustum.") ->Attribute(Edit::Attributes::Min, 0.f) ->Attribute(Edit::Attributes::Max, 1.f) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsSplitManual) - ->DataElement(Edit::UIHandlers::Vector4, &DirectionalLightComponentConfig::m_cascadeFarDepths, "Far Depth Cascade", - "Far Depth of each cascade. The value of the index greater than or equal to cascade count is ignored.") + ->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsSplitManual) + ->DataElement(Edit::UIHandlers::Vector4, &DirectionalLightComponentConfig::m_cascadeFarDepths, "Far depth cascade", + "Far depth of each cascade. The value of the index greater than or equal to cascade count is ignored.") ->Attribute(Edit::Attributes::Min, 0.01f) ->Attribute(Edit::Attributes::Max, &DirectionalLightComponentConfig::m_shadowFarClipDistance) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsSplitAutomatic) - ->DataElement(Edit::UIHandlers::Default, &DirectionalLightComponentConfig::m_groundHeight, "Ground Height", + ->DataElement(Edit::UIHandlers::Default, &DirectionalLightComponentConfig::m_groundHeight, "Ground height", "Height of the ground. Used to correct position of cascades.") ->Attribute(Edit::Attributes::Suffix, " m") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsCascadeCorrectionDisabled) + ->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsCascadeCorrectionDisabled) ->DataElement(Edit::UIHandlers::CheckBox, - &DirectionalLightComponentConfig::m_isCascadeCorrectionEnabled, "Enable Cascade Correction?", + &DirectionalLightComponentConfig::m_isCascadeCorrectionEnabled, "Cascade correction", "Enable position correction of cascades to optimize the appearance for certain camera positions.") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->DataElement(Edit::UIHandlers::CheckBox, - &DirectionalLightComponentConfig::m_isDebugColoringEnabled, "Enable Debug Coloring?", + &DirectionalLightComponentConfig::m_isDebugColoringEnabled, "Debug coloring", "Enable coloring to see how cascades places 0:red, 1:green, 2:blue, 3:yellow.") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->DataElement(Edit::UIHandlers::ComboBox, &DirectionalLightComponentConfig::m_shadowFilterMethod, "Shadow Filter Method", + ->DataElement(Edit::UIHandlers::ComboBox, &DirectionalLightComponentConfig::m_shadowFilterMethod, "Shadow filter method", "Filtering method of edge-softening of shadows.\n" - " None: no filtering\n" - " PCF: Percentage-Closer Filtering\n" - " ESM: Exponential Shadow Maps\n" + " None: No filtering\n" + " PCF: Percentage-closer filtering\n" + " ESM: Exponential shadow maps\n" " ESM+PCF: ESM with a PCF fallback\n" "For BehaviorContext (or TrackView), None=0, PCF=1, ESM=2, ESM+PCF=3") ->EnumAttribute(ShadowFilterMethod::None, "None") @@ -132,7 +132,7 @@ namespace AZ ->EnumAttribute(ShadowFilterMethod::Esm, "ESM") ->EnumAttribute(ShadowFilterMethod::EsmPcf, "ESM+PCF") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_boundaryWidth, "Softening Boundary Width", + ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_boundaryWidth, "Softening boundary width", "Width of the boundary between shadowed area and lit one. " "Units are in meters. " "If this is 0, softening edge is disabled.") @@ -141,29 +141,29 @@ namespace AZ ->Attribute(Edit::Attributes::Suffix, " m") ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsPcfBoundarySearchDisabled) - ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_predictionSampleCount, "Prediction Sample Count", - "Sample Count for prediction of whether the pixel is on the boundary. " + ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_predictionSampleCount, "Prediction sample count", + "Sample count for prediction of whether the pixel is on the boundary. " "Specific to PCF and ESM+PCF.") ->Attribute(Edit::Attributes::Min, 4) ->Attribute(Edit::Attributes::Max, 16) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsPcfBoundarySearchDisabled) - ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_filteringSampleCount, "Filtering Sample Count", - "It is used only when the pixel is predicted as on the boundary. " + ->DataElement(Edit::UIHandlers::Slider, &DirectionalLightComponentConfig::m_filteringSampleCount, "Filtering sample count", + "This is used only when the pixel is predicted as on the boundary. " "Specific to PCF and ESM+PCF.") ->Attribute(Edit::Attributes::Min, 4) ->Attribute(Edit::Attributes::Max, 64) ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) ->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled) ->DataElement( - Edit::UIHandlers::ComboBox, &DirectionalLightComponentConfig::m_pcfMethod, "Pcf Method", - "Type of Pcf to use.\n" + Edit::UIHandlers::ComboBox, &DirectionalLightComponentConfig::m_pcfMethod, "Pcf method", + "Type of PCF to use.\n" " Bicubic: a smooth, fixed-size kernel \n" " Boundary search: do several taps to first determine if we are on a shadow boundary\n") - ->EnumAttribute(PcfMethod::Bicubic, "Bicubic") - ->EnumAttribute(PcfMethod::BoundarySearch, "Boundary Search") - ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) - ->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled); + ->EnumAttribute(PcfMethod::Bicubic, "Bicubic") + ->EnumAttribute(PcfMethod::BoundarySearch, "Boundary search") + ->Attribute(Edit::Attributes::ChangeNotify, Edit::PropertyRefreshLevels::ValuesOnly) + ->Attribute(Edit::Attributes::ReadOnly, &DirectionalLightComponentConfig::IsShadowPcfDisabled); ; } diff --git a/Gems/ImGui/Code/Include/ImGuiBus.h b/Gems/ImGui/Code/Include/ImGuiBus.h index ea7fe1631e..06a3b472da 100644 --- a/Gems/ImGui/Code/Include/ImGuiBus.h +++ b/Gems/ImGui/Code/Include/ImGuiBus.h @@ -8,6 +8,7 @@ #pragma once #include +#include // Forward Declares struct ImVec2; @@ -86,9 +87,19 @@ namespace ImGui virtual void SetImGuiRenderResolution(const ImVec2& res) = 0; virtual void OverrideRenderWindowSize(uint32_t width, uint32_t height) = 0; virtual void RestoreRenderWindowSizeToDefault() = 0; + virtual void ToggleThroughImGuiVisibleState() = 0; virtual void SetDpiScalingFactor(float dpiScalingFactor) = 0; virtual float GetDpiScalingFactor() const = 0; virtual void Render() = 0; + + using ImGuiSetEnabledEvent = AZ::Event; + ImGuiSetEnabledEvent m_setEnabledEvent; + + // interface + void ConnectImGuiSetEnabledChangedHandler(ImGuiSetEnabledEvent::Handler& handler) + { + handler.Connect(m_setEnabledEvent); + } }; class IImGuiManagerRequests @@ -101,19 +112,30 @@ namespace ImGui }; using ImGuiManagerBus = AZ::EBus; + class IImGuiManagerNotifications : public AZ::EBusTraits + { + public: + static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; + static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; + using Bus = AZ::EBus; + + virtual void ImGuiSetEnabled( [[maybe_unused]] bool enabled) {} + }; + using ImGuiManagerNotificationBus = AZ::EBus; + // Bus for getting notifications from the IMGUI Entity Outliner - class IImGuiEntityOutlinerNotifcations : public AZ::EBusTraits + class IImGuiEntityOutlinerNotifications : public AZ::EBusTraits { public: - static const char* GetUniqueName() { return "IImGuiEntityOutlinerNotifcations"; } + static const char* GetUniqueName() { return "IImGuiEntityOutlinerNotifications"; } static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple; static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single; - using Bus = AZ::EBus; + using Bus = AZ::EBus; // Callback for game code to handle targetting an IMGUI entity virtual void OnImGuiEntityOutlinerTarget(AZ::EntityId target) { (void)target; } }; - typedef AZ::EBus ImGuiEntityOutlinerNotifcationBus; + typedef AZ::EBus ImGuiEntityOutlinerNotificationBus; // a pair of an entity id, and a typeid, used to represent component rtti type info typedef AZStd::pair ImGuiEntComponentId; diff --git a/Gems/ImGui/Code/Source/ImGuiManager.cpp b/Gems/ImGui/Code/Source/ImGuiManager.cpp index 42c8d3929c..7b2506fbcb 100644 --- a/Gems/ImGui/Code/Source/ImGuiManager.cpp +++ b/Gems/ImGui/Code/Source/ImGuiManager.cpp @@ -738,8 +738,15 @@ void ImGuiManager::ToggleThroughImGuiVisibleState(int controllerIndex) } m_menuBarStatusChanged = true; + m_setEnabledEvent.Signal(m_clientMenuBarState == DisplayState::Hidden); } +void ImGuiManager::ToggleThroughImGuiVisibleState() +{ + ToggleThroughImGuiVisibleState(-1); +} + + void ImGuiManager::RenderImGuiBuffers(const ImVec2& scaleRects) { ImGui::ImGuiContextScope contextScope(m_imguiContext); diff --git a/Gems/ImGui/Code/Source/ImGuiManager.h b/Gems/ImGui/Code/Source/ImGuiManager.h index 1509f27c57..02af3d0c09 100644 --- a/Gems/ImGui/Code/Source/ImGuiManager.h +++ b/Gems/ImGui/Code/Source/ImGuiManager.h @@ -60,6 +60,7 @@ namespace ImGui void SetDpiScalingFactor(float dpiScalingFactor) override; float GetDpiScalingFactor() const override; void Render() override; + void ToggleThroughImGuiVisibleState() override; // -- ImGuiManagerBus Interface ------------------------------------------------------------------- // -- AzFramework::InputChannelEventListener and AzFramework::InputTextEventListener Interface ------------ diff --git a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYAssetExplorer.cpp b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYAssetExplorer.cpp index 2f996f5768..d9d81c24f2 100644 --- a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYAssetExplorer.cpp +++ b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYAssetExplorer.cpp @@ -465,7 +465,7 @@ namespace ImGui ImGui::BeginGroup(); if (ImGui::SmallButton(AZStd::string::format("-View #%03d-##%s", ++instanceCount, meshInstance.first.ToString().c_str()).c_str())) { - ImGuiEntityOutlinerNotifcationBus::Broadcast(&IImGuiEntityOutlinerNotifcations::OnImGuiEntityOutlinerTarget, meshInstance.first); + ImGuiEntityOutlinerNotificationBus::Broadcast(&IImGuiEntityOutlinerNotifications::OnImGuiEntityOutlinerTarget, meshInstance.first); } // Build the Label String. ImGui::SameLine(); diff --git a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCommonMenu.cpp b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCommonMenu.cpp index 9994851faa..eb918041f7 100644 --- a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCommonMenu.cpp +++ b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCommonMenu.cpp @@ -571,7 +571,26 @@ namespace ImGui // End LY Common Tools menu ImGui::EndMenu(); } + const int labelSize{ 100 }; + const int buttonSize{ 40 }; ImGuiUpdateListenerBus::Broadcast(&IImGuiUpdateListener::OnImGuiMainMenuUpdate); + ImGui::SameLine(ImGui::GetWindowContentRegionMax().x - labelSize); + float backgroundHeight = ImGui::GetTextLineHeight() + 3; + ImVec2 cursorPos = ImGui::GetCursorScreenPos(); + ImGui::GetWindowDrawList()->AddRectFilled( + cursorPos, ImVec2(cursorPos.x + labelSize, cursorPos.y + backgroundHeight), IM_COL32(0, 115, 187, 255)); + ImGui::SameLine(ImGui::GetWindowContentRegionMax().x - labelSize); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 1); + ImGui::Text("ImGui:ON"); + ImGui::SameLine(ImGui::GetWindowContentRegionMax().x - buttonSize); + ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(0, 0, 0, 255)); + ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(255, 255, 255, 255)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, IM_COL32(128, 128, 128, 255)); + if (ImGui::SmallButton("home")) + { + ImGuiManagerBus::Broadcast(&IImGuiManager::ToggleThroughImGuiVisibleState); + } + ImGui::PopStyleColor(3); ImGui::EndMainMenuBar(); } diff --git a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYEntityOutliner.cpp b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYEntityOutliner.cpp index aca52af238..57502296ae 100644 --- a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYEntityOutliner.cpp +++ b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYEntityOutliner.cpp @@ -590,7 +590,7 @@ namespace ImGui if (ImGui::SmallButton(targetLabel.c_str())) { // Send EBUS event out to Target an Entity. Up to game code to implement. - ImGuiEntityOutlinerNotifcationBus::Broadcast(&IImGuiEntityOutlinerNotifcations::OnImGuiEntityOutlinerTarget, node->m_entityId); + ImGuiEntityOutlinerNotificationBus::Broadcast(&IImGuiEntityOutlinerNotifications::OnImGuiEntityOutlinerTarget, node->m_entityId); } } diff --git a/Gems/LmbrCentral/Code/Platform/Mac/lrelease_mac.cmake b/Gems/LmbrCentral/Code/Platform/Mac/lrelease_mac.cmake index af355b0a51..34f67ccedd 100644 --- a/Gems/LmbrCentral/Code/Platform/Mac/lrelease_mac.cmake +++ b/Gems/LmbrCentral/Code/Platform/Mac/lrelease_mac.cmake @@ -5,6 +5,15 @@ # # +add_custom_command(TARGET LmbrCentral.Editor POST_BUILD + COMMAND "${CMAKE_COMMAND}" -P "${LY_ROOT_FOLDER}/cmake/Platform/Mac/RPathChange.cmake" + "$/lrelease" + @executable_path/../Frameworks + @executable_path + COMMENT "Patching lrelease..." + VERBATIM +) + set(lrelease_files ${QT_LRELEASE_EXECUTABLE} ) diff --git a/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterControllerComponent.cpp b/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterControllerComponent.cpp index b2b09306f1..ff7ec66140 100644 --- a/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterControllerComponent.cpp +++ b/Gems/PhysX/Code/Source/PhysXCharacters/Components/CharacterControllerComponent.cpp @@ -520,16 +520,19 @@ namespace PhysX CharacterControllerRequestBus::Handler::BusConnect(GetEntityId()); - m_preSimulateHandler = AzPhysics::SystemEvents::OnPresimulateEvent::Handler( - [this](float deltaTime) + if (m_characterConfig->m_applyMoveOnPhysicsTick) + { + m_preSimulateHandler = AzPhysics::SystemEvents::OnPresimulateEvent::Handler( + [this](float deltaTime) + { + OnPreSimulate(deltaTime); + } + ); + + if (auto* physXSystem = GetPhysXSystem()) { - OnPreSimulate(deltaTime); + physXSystem->RegisterPreSimulateEvent(m_preSimulateHandler); } - ); - - if (auto* physXSystem = GetPhysXSystem()) - { - physXSystem->RegisterPreSimulateEvent(m_preSimulateHandler); } } diff --git a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp index e698fcc298..2bc3a91a96 100644 --- a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp +++ b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.cpp @@ -58,16 +58,6 @@ namespace ScriptCanvasEditor required.push_back(AZ_CRC("ScriptCanvasService", 0x41fd58f3)); } - ScriptCanvas::Grammar::Context* EditorAssetSystemComponent::GetGrammarContext() - { - return &m_grammarContext; - } - - ScriptCanvas::Translation::Context* EditorAssetSystemComponent::GetTranslationContext() - { - return &m_translationContext; - } - void EditorAssetSystemComponent::Init() { } @@ -79,16 +69,10 @@ namespace ScriptCanvasEditor AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect(); EditorAssetConversionBus::Handler::BusConnect(); - - ScriptCanvas::Translation::RequestBus::Handler::BusConnect(); - ScriptCanvas::Grammar::RequestBus::Handler::BusConnect(); } void EditorAssetSystemComponent::Deactivate() { - ScriptCanvas::Translation::RequestBus::Handler::BusDisconnect(); - ScriptCanvas::Grammar::RequestBus::Handler::BusDisconnect(); - EditorAssetConversionBus::Handler::BusDisconnect(); AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect(); m_editorAssetRegistry.Unregister(); diff --git a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.h b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.h index 4a55a35908..84b10ff17c 100644 --- a/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.h +++ b/Gems/ScriptCanvas/Code/Asset/EditorAssetSystemComponent.h @@ -12,11 +12,6 @@ #include "EditorAssetConversionBus.h" #include #include - -#include -#include -#include -#include #include namespace ScriptCanvasEditor @@ -26,8 +21,6 @@ namespace ScriptCanvasEditor class EditorAssetSystemComponent : public AZ::Component , public EditorAssetConversionBus::Handler - , public ScriptCanvas::Grammar::RequestBus::Handler - , public ScriptCanvas::Translation::RequestBus::Handler , private AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler { public: @@ -60,20 +53,10 @@ namespace ScriptCanvasEditor AZ::Outcome CreateLuaAsset(const AZ::Data::Asset& editAsset, AZStd::string_view graphPathForRawLuaFile) override; ////////////////////////////////////////////////////////////////////////// - // ScriptCanvas::Grammar::RequestBus::Handler... - ScriptCanvas::Grammar::Context* GetGrammarContext() override; - - // ScriptCanvas::Translation::RequestBus::Handler... - ScriptCanvas::Translation::Context* GetTranslationContext() override; - - ScriptCanvas::AssetRegistry& GetAssetRegistry(); private: - ScriptCanvas::AssetRegistry m_editorAssetRegistry; - ScriptCanvas::Translation::Context m_translationContext; - ScriptCanvas::Grammar::Context m_grammarContext; - + ScriptCanvas::AssetRegistry m_editorAssetRegistry; EditorAssetSystemComponent(const EditorAssetSystemComponent&) = delete; }; } diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp index 2f30106707..b37d5c1da4 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.cpp @@ -104,9 +104,6 @@ namespace ScriptCanvasBuilder m_sharedHandlers = HandleAssetTypes(); AssetHandlers workerHandlers(m_sharedHandlers); m_scriptCanvasBuilder.Activate(workerHandlers); - - ScriptCanvas::Translation::RequestBus::Handler::BusConnect(); - ScriptCanvas::Grammar::RequestBus::Handler::BusConnect(); } void PluginComponent::Deactivate() @@ -116,18 +113,6 @@ namespace ScriptCanvasBuilder AzToolsFramework::ToolsAssetSystemBus::Broadcast(&AzToolsFramework::ToolsAssetSystemRequests::UnregisterSourceAssetType, azrtti_typeid()); m_scriptCanvasBuilder.BusDisconnect(); m_sharedHandlers.DeleteOwnedHandlers(); - ScriptCanvas::Translation::RequestBus::Handler::BusDisconnect(); - ScriptCanvas::Grammar::RequestBus::Handler::BusDisconnect(); - } - - ScriptCanvas::Grammar::Context* PluginComponent::GetGrammarContext() - { - return &m_grammarContext; - } - - ScriptCanvas::Translation::Context* PluginComponent::GetTranslationContext() - { - return &m_translationContext; } void PluginComponent::Reflect(AZ::ReflectContext* context) diff --git a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.h b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.h index 5d57863ec3..ff904d195a 100644 --- a/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.h +++ b/Gems/ScriptCanvas/Code/Builder/ScriptCanvasBuilderComponent.h @@ -12,18 +12,11 @@ #include #include "ScriptCanvasBuilderWorker.h" -#include -#include -#include -#include - namespace ScriptCanvasBuilder { //! ScriptCanvasBuilder is responsible for turning editor ScriptCanvas Assets into runtime script canvas assets class PluginComponent : public AZ::Component - , public ScriptCanvas::Grammar::RequestBus::Handler - , public ScriptCanvas::Translation::RequestBus::Handler { public: AZ_COMPONENT(PluginComponent, "{F8286B21-E751-4745-8BC4-512F190215FF}") @@ -42,19 +35,9 @@ namespace ScriptCanvasBuilder void Deactivate() override; ////////////////////////////////////////////////////////////////////////// - // ScriptCanvas::Grammar::RequestBus::Handler - ScriptCanvas::Grammar::Context* GetGrammarContext() override; - - // ScriptCanvas::Translation::RequestBus::Handler - ScriptCanvas::Translation::Context* GetTranslationContext() override; - private: PluginComponent(const PluginComponent&) = delete; - SharedHandlers m_sharedHandlers; - Worker m_scriptCanvasBuilder; - ScriptCanvas::Translation::Context m_translationContext; - ScriptCanvas::Grammar::Context m_grammarContext; }; } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp index 8250eb1763..3f9c5cc8a4 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.cpp @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include // Version Conversion includes @@ -2335,6 +2333,11 @@ namespace ScriptCanvas } } + bool Node::CanAcceptNullInput([[maybe_unused]] const Slot& executionSlot, [[maybe_unused]] const Slot& inputSlot) const + { + return true; + } + void Node::CollectVariableReferences(AZStd::unordered_set< ScriptCanvas::VariableId >& variableIds) const { for (const Slot& slot : m_slots) @@ -2949,45 +2952,6 @@ namespace ScriptCanvas } } - void Node::SetInput(const Datum& newInput, const SlotId& slotId) - { - AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::ScriptCanvas); - - ModifiableDatumView datumView; - FindModifiableDatumView(slotId, datumView); - - if (datumView.IsValid()) - { - datumView.AssignToDatum(newInput); - } - } - - void Node::SetInput(Datum&& newInput, const SlotId& slotId) - { - AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::ScriptCanvas); - - ModifiableDatumView datumView; - FindModifiableDatumView(slotId, datumView); - - if (datumView.IsValid()) - { - datumView.AssignToDatum(newInput); - } - } - - void Node::SetInput(Node& node, const SlotId& id, const Datum& input) - { - AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::ScriptCanvas); - node.SetInput(input, id); - } - - void Node::SetInput(Node& node, const SlotId& id, Datum&& input) - { - AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::ScriptCanvas, "ScriptCanvas::Node::SetInput"); - - node.SetInput(AZStd::move(input), id); - } - AZStd::string Node::GetDebugName() const { if (GetEntityId().IsValid()) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h index 55379e29b9..614494883a 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Node.h @@ -479,7 +479,10 @@ namespace ScriptCanvas Node(const Node&); // Needed just for DLL linkage. Does not perform a copy Node& operator=(const Node&); // Needed just for DLL linkage. Does not perform a copy + virtual bool CanAcceptNullInput(const Slot& executionSlot, const Slot& inputSlot) const; + virtual void CollectVariableReferences(AZStd::unordered_set< ScriptCanvas::VariableId >& variableIds) const; + virtual bool ContainsReferencesToVariables(const AZStd::unordered_set< ScriptCanvas::VariableId >& variableIds) const; Graph* GetGraph() const; @@ -841,9 +844,6 @@ namespace ScriptCanvas void SignalSlotsReordered(); - static void SetInput(Node& node, const SlotId& id, const Datum& input); - static void SetInput(Node& node, const SlotId& id, Datum&& input); - // Will ignore any references and return the Datum that the slot represents. void ModifyUnderlyingSlotDatum(const SlotId& id, ModifiableDatumView& datumView); @@ -995,9 +995,6 @@ protected: void SetOwningScriptCanvasId(ScriptCanvasId scriptCanvasId); void SetGraphEntityId(AZ::EntityId graphEntityId); - virtual void SetInput(const Datum& input, const SlotId& id); - virtual void SetInput(Datum&& input, const SlotId& id); - bool SlotExists(AZStd::string_view name, const SlotDescriptor& slotDescriptor) const; bool IsTargetInDataFlowPath(const ID& targetNodeId, AZStd::unordered_set& path) const; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp index f3d6070ac6..01b754506c 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/Nodeable.cpp @@ -9,8 +9,6 @@ #include #include -#include -#include namespace NodeableOutCpp { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNode.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNode.cpp index 5ec40d8e5f..db0cf8e589 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNode.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNode.cpp @@ -12,8 +12,6 @@ #include #include #include -#include -#include #include #include diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNodeOverloaded.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNodeOverloaded.cpp index c9e2e3acc6..882804de36 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNodeOverloaded.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Core/NodeableNodeOverloaded.cpp @@ -12,8 +12,6 @@ #include #include #include -#include -#include #include #include diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp index 348c89f45f..4ccb462a5d 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.cpp @@ -32,7 +32,6 @@ #include "AbstractCodeModel.h" #include "ExecutionTraversalListeners.h" -#include "GrammarContextBus.h" #include "ParsingUtilities.h" #include "Primitives.h" @@ -670,6 +669,28 @@ namespace ScriptCanvas return AddVariable(Datum(type), rawName); } + void AbstractCodeModel::CheckForKnownNullDereference(ExecutionTreeConstPtr execution, const ExecutionInput& input, const Slot& inputSlot) + { + if (Data::IsValueType(inputSlot.GetDataType()) + || !execution->GetId().m_node + || !execution->GetId().m_slot + || (input.m_value && !input.m_value->m_datum.Empty())) + { + return; + } + + if (!input.m_value) + { + AddError(execution->GetId().m_node->GetEntityId(), nullptr, "Internal Error: CheckForKnownNullDereference called with input with no m_value"); + return; + } + + if (!execution->GetId().m_node->CanAcceptNullInput(*execution->GetId().m_slot, inputSlot)) + { + AddError(execution->GetId().m_node->GetEntityId(), nullptr, ParseErrors::NullInputKnown); + } + } + void AbstractCodeModel::CheckConversion(ConversionByIndex& conversion, VariableConstPtr source, size_t index, const Data::Type& targetType) { const Data::Type& sourceType = source->m_datum.GetType(); @@ -698,7 +719,7 @@ namespace ScriptCanvas } AZStd::string AbstractCodeModel::CheckUniqueInterfaceNames - (AZStd::string_view candidate + ( AZStd::string_view candidate , AZStd::string_view defaultName , AZStd::unordered_set& uniqueNames , const AZStd::unordered_set& nodelingsOut) @@ -2422,17 +2443,17 @@ namespace ScriptCanvas ExecutionTreePtr start = OpenScope(nullptr, startNode, nullptr); start->SetSymbol(Symbol::FunctionDefinition); + m_start = start; // cache the function definition if (!m_subgraphStartCalls.empty()) { - m_start = start; - + // call OnGraphStart on all the member nodeables first for (auto node : m_subgraphStartCalls) { ExecutionTreePtr childStartCall = CreateChild(start, node, nullptr); childStartCall->SetSymbol(Symbol::FunctionCall); childStartCall->SetName(k_OnGraphStartFunctionName); - childStartCall->MarkStart(); + childStartCall->MarkStartCall(); auto lexicalScopeOutcome = node->GetFunctionCallLexicalScope(nullptr); @@ -2478,11 +2499,13 @@ namespace ScriptCanvas } } + // ExecutionTreePtr start is now either the last child start() call, or the beginning of the function block, + // either way, parsing can continue from the ExecutionTreePtr start. + if (!outSlots.empty()) { start->AddChild({ outSlots[0], {}, nullptr }); - start->MarkStart(); - + ParseExecutionMultipleOutSyntaxSugar(start, outNodes, outSlots); PostParseProcess(start); PostParseErrorDetect(start); @@ -2490,24 +2513,10 @@ namespace ScriptCanvas if (!IsErrorFree()) { start->Clear(); - - if (m_start) - { - m_start->Clear(); - } - + m_start->Clear(); AddError(AZ::EntityId{}, nullptr, ScriptCanvas::ParseErrors::StartNodeFailedToParse); return; } - - if (!m_start) - { - m_start = start; - } - } - else - { - // add warning or notification on useless start node? } if (m_start) @@ -4297,10 +4306,7 @@ namespace ScriptCanvas void AbstractCodeModel::ParseInputDatum(ExecutionTreePtr execution, const Slot& input) { - // \todo look for crossed lines in inferred functions, because sometimes, rather than the input - // being named of the result of the output that emitted it, it will be the name of the inferred function - // parameter ---> make a map of node output to function input names - AZ_Assert(execution->GetSymbol() != Symbol::FunctionDefinition, "Function definition input should have been handled already"); + AZ_Assert(execution->GetSymbol() != Symbol::FunctionDefinition, "Function definition input is not handled in AbstractCodeModel::ParseInputDatum"); auto nodes = execution->GetId().m_node->GetConnectedNodes(input); if (nodes.empty()) @@ -4310,17 +4316,6 @@ namespace ScriptCanvas execution->AddInput({ &input, variable, DebugDataSource::FromVariable(input.GetId(), input.GetDataType(), variable->m_sourceVariableId) }); CheckConversion(execution->ModConversions(), variable, execution->GetInputCount() - 1, input.GetDataType()); } - // This concept may never actually be possible -// else if (RequiresCreationFunction(input.GetDataType().GetType())) -// { -// AddError(execution, aznew NotYetImplemented( -// "1: finish input created by name when connected to other nodes" -// "2: add the name to the scope" -// "3: and check inputs be re-used, common constructors like zero/1, etc" -// "4: read the variable name if it is present instead of creating it" -// "5: check for entity references to self and other member slice variables" -// "6: mark the variable with RequiredCreationFunction()")); -// } else { auto variableDatum = input.FindDatum(); @@ -4357,26 +4352,30 @@ namespace ScriptCanvas } else { - // we don't support this, yet, but visually we could - // we could support both things, technically...auto-generated inputs, and defaults on the non-connected - // execution thread, or whatever makes possible sense - // \todo send enough information to reveal the data path in the editor - + // This isn't supported visually, yet, but technically, it could be. + // One could connect both latent execution and immediate execution to the same code execution path, + // but only one uses connected output, and the other uses defaults. + // It would require us to change the visualization of the shared path, based on which parent was clicked on in the editor. const auto& targetNode = *execution->GetId().m_node; const auto& targetSlot = input; for (auto sourceNodeAndSlot : nodes) { AddError(nullptr, aznew ScopedDataConnectionEvent - (execution->GetNodeId() + ( execution->GetNodeId() , targetNode , targetSlot , *sourceNodeAndSlot.first , *sourceNodeAndSlot.second)); } + + return; } } + + // Check for known null reads + CheckForKnownNullDereference(execution, execution->GetInput(execution->GetInputCount() - 1), input); } bool AbstractCodeModel::ParseInputThisPointer(ExecutionTreePtr execution) @@ -4428,6 +4427,7 @@ namespace ScriptCanvas if (auto eventHandling = GetEBusEventHandling(node)) { auto variable = AZStd::make_shared(); + variable->m_isMember = true; variable->m_datum = Datum(eventHandling->m_handlerName); execution->MarkInputHasThisPointer(); execution->AddInput({ nullptr, variable, DebugDataSource::FromInternal() }); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.h index 06854fdbfd..45e289739d 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/AbstractCodeModel.h @@ -207,8 +207,10 @@ namespace ScriptCanvas bool CheckCreateRoot(const Node& node); + void CheckForKnownNullDereference(ExecutionTreeConstPtr parent, const ExecutionInput& input, const Slot& inputSlot); + AZStd::string CheckUniqueInterfaceNames - (AZStd::string_view candidate + ( AZStd::string_view candidate , AZStd::string_view defaultName , AZStd::unordered_set& uniqueNames , const AZStd::unordered_set& nodelingsOut); diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ExecutionTraversalListeners.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ExecutionTraversalListeners.cpp index 1ac9303082..6ac80de542 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ExecutionTraversalListeners.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/ExecutionTraversalListeners.cpp @@ -27,7 +27,6 @@ #include #include "ExecutionTraversalListeners.h" -#include "GrammarContextBus.h" #include "ParsingUtilities.h" #include "Primitives.h" diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/GrammarContext.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/GrammarContext.cpp deleted file mode 100644 index b8eb5f5ad5..0000000000 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/GrammarContext.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#include "GrammarContext.h" - -namespace ScriptCanvas -{ - namespace Grammar - { - const SubgraphInterfaceSystem& Context::GetExecutionMapSystem() const - { - return m_executionMapSystem; - } - - SubgraphInterfaceSystem& Context::ModExecutionMapSystem() - { - return m_executionMapSystem; - } - } - -} diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/GrammarContext.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/GrammarContext.h deleted file mode 100644 index 7a9d2eaec9..0000000000 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/GrammarContext.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include -#include - -#include - -namespace ScriptCanvas -{ - namespace Grammar - { - class Context - { - public: - AZ_CLASS_ALLOCATOR(Context, AZ::SystemAllocator, 0); - - Context() = default; - ~Context() = default; - - const SubgraphInterfaceSystem& GetExecutionMapSystem() const; - SubgraphInterfaceSystem& ModExecutionMapSystem(); - - private: - SubgraphInterfaceSystem m_executionMapSystem; - - // put grammatical state globals in here, things that can be useful across several parses of graphs - }; - } - -} diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/GrammarContextBus.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/GrammarContextBus.h deleted file mode 100644 index 1630d0b99e..0000000000 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/GrammarContextBus.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -namespace ScriptCanvas -{ - namespace Grammar - { - class Context; - - struct RequestTraits : public AZ::EBusTraits - { - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - - virtual Context* GetGrammarContext() = 0; - }; - - using RequestBus = AZ::EBus; - - struct EventTraits : public AZ::EBusTraits - { - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - - // add stuff here to speed up parsing across separate graphs - }; - - using EventBus = AZ::EBus; - } - -} diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.cpp index 0984440bf4..011dfeda97 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.cpp @@ -354,9 +354,9 @@ namespace ScriptCanvas return GetRoot()->m_isPure; } - bool ExecutionTree::IsStart() const + bool ExecutionTree::IsStartCall() const { - return m_isStart; + return m_isStartCall; } void ExecutionTree::MarkDebugEmptyStatement() @@ -403,9 +403,9 @@ namespace ScriptCanvas root->m_isLatent = true; } - void ExecutionTree::MarkStart() + void ExecutionTree::MarkStartCall() { - m_isStart = true; + m_isStartCall = true; } ExecutionChild& ExecutionTree::ModChild(size_t index) diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.h index c86f445a68..80d602ad17 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Grammar/PrimitivesExecution.h @@ -199,7 +199,7 @@ namespace ScriptCanvas bool IsPure() const; - bool IsStart() const; + bool IsStartCall() const; void MarkDebugEmptyStatement(); @@ -215,7 +215,7 @@ namespace ScriptCanvas void MarkRootLatent(); - void MarkStart(); + void MarkStartCall(); ExecutionChild& ModChild(size_t index); @@ -286,7 +286,7 @@ namespace ScriptCanvas bool m_isPure = false; - bool m_isStart = false; + bool m_isStartCall = false; bool m_hasExplicitUserOutCalls = false; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp index 32b5e5741f..4eafa82331 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.cpp @@ -25,6 +25,7 @@ namespace MethodCPP Unnamed2, PluralizeResults, AddedPrettyNameFieldToSerialization, + StoreInputSlotIdsToSupportNullCheck, // add your version above Current, }; @@ -110,6 +111,37 @@ namespace ScriptCanvas { namespace Core { + bool Method::CanAcceptNullInput([[maybe_unused]] const Slot& executionSlot, const Slot& inputSlot) const + { + if (m_method) + { + auto candidateID = inputSlot.GetId(); + auto slotIter = AZStd::find(m_inputSlots.begin(), m_inputSlots.end(), candidateID); + + if (slotIter != m_inputSlots.end()) + { + const size_t index = slotIter - m_inputSlots.begin(); + if (index < m_method->GetNumArguments()) + { + const auto* argument = m_method->GetArgument(index); + if (argument->m_traits & (AZ::BehaviorParameter::TR_REFERENCE | AZ::BehaviorParameter::TR_THIS_PTR)) + { + // references and this pointers cannot accept null input + return false; + } + + if (!(argument->m_traits & AZ::BehaviorParameter::TR_POINTER)) + { + // values cannot accept null input + return false; + } + } + } + } + + return true; + } + const AZ::BehaviorClass* Method::GetClass() const { return m_class; @@ -232,6 +264,11 @@ namespace ScriptCanvas if (addedSlot.IsValid()) { MethodHelper::SetSlotToDefaultValue(*this, addedSlot, config, argIndex); + m_inputSlots.push_back(addedSlot); + } + else + { + AZ_Warning("ScriptCanvas", false, "Failed to add method input slot to Method node: %s-%s", config.m_prettyClassName.c_str(), config.m_method.m_name.c_str()); } } } @@ -520,8 +557,8 @@ namespace ScriptCanvas if (m_method && m_method->HasResult()) { if (branchOnResultMethod.GetNumArguments() == 1 - && branchOnResultMethod.HasResult() - && Data::FromAZType(branchOnResultMethod.GetResult()->m_typeId) == Data::Type::Boolean()) + && branchOnResultMethod.HasResult() + && Data::FromAZType(branchOnResultMethod.GetResult()->m_typeId) == Data::Type::Boolean()) { AZ::Uuid methodResultType = m_method->GetResult()->m_typeId; AZ::Uuid branchOnResultMethodArgType = branchOnResultMethod.GetArgument(0)->m_typeId; @@ -797,6 +834,7 @@ namespace ScriptCanvas ->Field("className", &Method::m_className) ->Field("namespaces", &Method::m_namespaces) ->Field("resultSlotIDs", &Method::m_resultSlotIDs) + ->Field("inputSlots", &Method::m_inputSlots) ->Field("prettyClassName", &Method::m_classNamePretty) ; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h index db34da040c..3dec8e3e72 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Libraries/Core/Method.h @@ -45,6 +45,8 @@ namespace ScriptCanvas size_t GenerateFingerprint() const override; + bool CanAcceptNullInput(const Slot& executionSlot, const Slot& inputSlot) const override; + bool GetBranchOnResultCheckName(AZStd::string& exposedName, Grammar::LexicalScope& lexicalScope) const; virtual bool GetCheckedOperationInfo(AZ::CheckedOperationInfo& checkedInfo, AZStd::string& exposedName, Grammar::LexicalScope& lexicalScope) const; @@ -149,8 +151,6 @@ namespace ScriptCanvas bool IsExpectingResult() const; - AZ_INLINE AZStd::vector& ModResultSlotIds() { return m_resultSlotIDs; } - virtual void OnInitializeOutputPost(const MethodOutputConfig&) {} virtual void OnInitializeOutputPre(MethodOutputConfig&) {} @@ -176,6 +176,7 @@ namespace ScriptCanvas NamespacePath m_namespaces; const AZ::BehaviorMethod* m_method = nullptr; const AZ::BehaviorClass* m_class = nullptr; + AZStd::vector m_inputSlots; AZStd::vector m_resultSlotIDs; AZStd::recursive_mutex m_mutex; // post-serialization bool m_warnOnMissingFunction = true; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h index 339c0fc3a1..928d1d7202 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Results/ErrorText.h @@ -74,6 +74,7 @@ namespace ScriptCanvas constexpr const char* NotEnoughBranchesForReturn = "Not enough branches for defined out return values."; constexpr const char* NotEnoughInputForArithmeticOperator = "Not enough input for arithmetic operator"; constexpr const char* NullEntityInGraph = "Null entity pointer in graph"; + constexpr const char* NullInputKnown = "The input is known to be null, and the node does not accept it"; constexpr const char* ParseExecutionMultipleOutSyntaxSugarChildExecutionRemovedAndNotReplaced = "ParseExecutionMultipleOutSyntaxSugar: child execution node was removed, and not replaced."; constexpr const char* ParseExecutionMultipleOutSyntaxSugarMismatchOutSize = "ParseExecutionMultipleOutSyntaxSugar: mismatch in connect nodes vs source slots size"; constexpr const char* ParseExecutionMultipleOutSyntaxSugarNonNullChildExecutionFound = "ParseExecutionMultipleOutSyntaxSugar: non null child execution node"; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.cpp b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.cpp index 772fda4f7e..085a0928bc 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.cpp +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.cpp @@ -24,8 +24,6 @@ #include #include "GraphToLuaUtility.h" -#include "TranslationContext.h" -#include "TranslationContextBus.h" namespace GraphToLuaCpp { @@ -92,9 +90,7 @@ namespace ScriptCanvas { SystemRequestBus::BroadcastResult(m_systemConfiguration, &SystemRequests::GetSystemComponentConfiguration); MarkTranslationStart(); - RequestBus::BroadcastResult(m_context, &RequestTraits::GetTranslationContext); - AZ_Assert(m_context, "Nothing is possible without the context"); - + m_tableName = GraphToLuaCpp::FileNameToTableName(m_model.GetSource().m_name); m_tableName += m_configuration.m_suffix; @@ -138,12 +134,12 @@ namespace ScriptCanvas const AZStd::string& GraphToLua::FindAbbreviation(AZStd::string_view dependency) const { - return m_context->FindAbbreviation(dependency); + return m_context.FindAbbreviation(dependency); } const AZStd::string& GraphToLua::FindLibrary(AZStd::string_view dependency) const { - return m_context->FindLibrary(dependency); + return m_context.FindLibrary(dependency); } AZStd::string_view GraphToLua::GetOperatorString(Grammar::ExecutionTreeConstPtr execution) @@ -806,7 +802,7 @@ namespace ScriptCanvas m_dotLua.Write("("); - if (execution->IsStart() && execution->IsPure()) + if (execution == m_model.GetStart() && execution->IsPure()) { m_dotLua.Write(Grammar::k_executionStateVariableName); @@ -1589,8 +1585,10 @@ namespace ScriptCanvas break; } - // #functions2 pure on graph start nodes with dependencies can only be added to the graph as variables -// if (execution->IsStart() && execution->IsPure()) + // #functions2 pure on graph start nodes with dependencies can only be added to the graph as variables, which is a work-flow we may never want to support + // as it effectively duplicates the Component-Entity-System. Technically, if this functionality is desired, one could just add another script component + // with the additional graph... +// if (execution->IsStartCall() && execution->IsPure()) // { // WriteFunctionCallInputOfChildStart(execution); // } @@ -1944,7 +1942,7 @@ namespace ScriptCanvas { const auto requirement = ParseConstructionRequirement(variable); - if (requirement == Grammar::VariableConstructionRequirement::None || (requirement != Grammar::VariableConstructionRequirement::Static && !execution->IsStart())) + if (requirement == Grammar::VariableConstructionRequirement::None || (requirement != Grammar::VariableConstructionRequirement::Static && !execution->IsStartCall())) { m_dotLua.WriteLineIndented("local %s = %s", variable->m_name.data(), ToValueString(variable->m_datum, m_configuration).data()); } diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.h index ba46b21c65..347cb764e9 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/GraphToLua.h @@ -16,6 +16,7 @@ #include #include "GraphToX.h" +#include "TranslationContext.h" #include "TranslationResult.h" #include "TranslationUtilities.h" @@ -60,7 +61,7 @@ namespace ScriptCanvas RuntimeInputs m_runtimeInputs; BuildConfiguration m_executionConfig = BuildConfiguration::Release; FunctionBlockConfig m_functionBlockConfig = FunctionBlockConfig::Ignored; - const Context* m_context = nullptr; + Context m_context; AZStd::string m_tableName; Writer m_dotLua; SystemComponentConfiguration m_systemConfiguration; diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationContext.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationContext.h index ea49f90bde..40f04f2f47 100644 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationContext.h +++ b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationContext.h @@ -10,7 +10,6 @@ #include #include #include "Translation.h" -#include "TranslationContextBus.h" namespace ScriptCanvas { diff --git a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationContextBus.h b/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationContextBus.h deleted file mode 100644 index 0edac2afe3..0000000000 --- a/Gems/ScriptCanvas/Code/Include/ScriptCanvas/Translation/TranslationContextBus.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ - -#pragma once - -#include - -#include "Translation.h" - -namespace ScriptCanvas -{ - namespace Translation - { - class Context; - - struct RequestTraits : public AZ::EBusTraits - { - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - - virtual Context* GetTranslationContext() = 0; - }; - - using RequestBus = AZ::EBus; - - struct EventTraits : public AZ::EBusTraits - { - static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single; - }; - - using EventBus = AZ::EBus; - - } - -} diff --git a/Gems/ScriptCanvas/Code/scriptcanvasgem_common_files.cmake b/Gems/ScriptCanvas/Code/scriptcanvasgem_common_files.cmake index 40b5786303..17273b7ae0 100644 --- a/Gems/ScriptCanvas/Code/scriptcanvasgem_common_files.cmake +++ b/Gems/ScriptCanvas/Code/scriptcanvasgem_common_files.cmake @@ -101,7 +101,6 @@ set(FILES Include/ScriptCanvas/Translation/Translation.cpp Include/ScriptCanvas/Translation/TranslationContext.h Include/ScriptCanvas/Translation/TranslationContext.cpp - Include/ScriptCanvas/Translation/TranslationContextBus.h Include/ScriptCanvas/Translation/TranslationResult.h Include/ScriptCanvas/Translation/TranslationResult.cpp Include/ScriptCanvas/Translation/TranslationUtilities.h @@ -196,9 +195,6 @@ set(FILES Include/ScriptCanvas/Grammar/DebugMap.cpp Include/ScriptCanvas/Grammar/ExecutionTraversalListeners.h Include/ScriptCanvas/Grammar/ExecutionTraversalListeners.cpp - Include/ScriptCanvas/Grammar/GrammarContext.h - Include/ScriptCanvas/Grammar/GrammarContext.cpp - Include/ScriptCanvas/Grammar/GrammarContextBus.h Include/ScriptCanvas/Grammar/ParsingMetaData.h Include/ScriptCanvas/Grammar/ParsingMetaData.cpp Include/ScriptCanvas/Grammar/ParsingUtilities.h diff --git a/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_ParseErrorOnKnownNull.scriptcanvas b/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_ParseErrorOnKnownNull.scriptcanvas new file mode 100644 index 0000000000..4453617996 --- /dev/null +++ b/Gems/ScriptCanvasTesting/Assets/ScriptCanvas/UnitTests/LY_SC_UnitTest_ParseErrorOnKnownNull.scriptcanvas @@ -0,0 +1,947 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestNodes.cpp b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestNodes.cpp index 727f73be39..e54c83c5d3 100644 --- a/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestNodes.cpp +++ b/Gems/ScriptCanvasTesting/Code/Source/Framework/ScriptCanvasTestNodes.cpp @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include diff --git a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp index 107bb32cd6..db3d2223d6 100644 --- a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp +++ b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_RuntimeInterpreted.cpp @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include #include @@ -85,6 +83,16 @@ public: } }; +TEST_F(ScriptCanvasTestFixture, ProveError) +{ + EXPECT_TRUE(false); +} + +TEST_F(ScriptCanvasTestFixture, ParseErrorOnKnownNull) +{ + ExpectParseError("LY_SC_UnitTest_ParseErrorOnKnownNull"); +} + TEST_F(ScriptCanvasTestFixture, UseBehaviorContextClassConstant) { RunUnitTestGraph("LY_SC_UnitTest_UseBehaviorContextClassConstant"); diff --git a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_VM.cpp b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_VM.cpp index 0733101743..8c4983da0f 100644 --- a/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_VM.cpp +++ b/Gems/ScriptCanvasTesting/Code/Tests/ScriptCanvas_VM.cpp @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/Gems/Vegetation/Code/Source/Debugger/DebugComponent.cpp b/Gems/Vegetation/Code/Source/Debugger/DebugComponent.cpp index 5fa2d6fd88..2f3c8d08be 100644 --- a/Gems/Vegetation/Code/Source/Debugger/DebugComponent.cpp +++ b/Gems/Vegetation/Code/Source/Debugger/DebugComponent.cpp @@ -185,7 +185,7 @@ void DebugComponent::DisplayEntityViewport(const AzFramework::ViewportInfo& view } } -void DebugComponent::DrawInstanceDebug(AzFramework::DebugDisplayRequests& debugDisplay) +void DebugComponent::DrawInstanceDebug([[maybe_unused]] AzFramework::DebugDisplayRequests& debugDisplay) { #if defined(VEG_PROFILE_ENABLED) AZStd::unordered_map areaDebugDisplayDataMap; diff --git a/Registry/AssetProcessorPlatformConfig.setreg b/Registry/AssetProcessorPlatformConfig.setreg index 0e91bec8a7..26aa5b2663 100644 --- a/Registry/AssetProcessorPlatformConfig.setreg +++ b/Registry/AssetProcessorPlatformConfig.setreg @@ -76,7 +76,8 @@ "animsettings": "i_caf", "Animations/SkeletonList.xml": "i_caf", "cbc": "abc", - "fbx.assetinfo": "fbx" + "fbx.assetinfo": "fbx", + "stl.assetinfo": "stl" }, // ---- add any folders to scan here. The priority order is the order they appear here diff --git a/Templates/DefaultGem/Template/CMakeLists.txt b/Templates/DefaultGem/Template/CMakeLists.txt index d00a5f0128..5ea435a790 100644 --- a/Templates/DefaultGem/Template/CMakeLists.txt +++ b/Templates/DefaultGem/Template/CMakeLists.txt @@ -10,13 +10,7 @@ set(o3de_gem_json ${o3de_gem_path}/gem.json) o3de_read_json_key(o3de_gem_name ${o3de_gem_json} "gem_name") o3de_restricted_path(${o3de_gem_json} o3de_gem_restricted_path) -# Currently we are in the DefaultProjectSource folder: ${CMAKE_CURRENT_LIST_DIR} -# Get the platform specific folder ${pal_dir} for the current folder: ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} -# Note: ly_get_list_relative_pal_filename will take care of the details for us, as this may be a restricted platform -# in which case it will see if that platform is present here or in the restricted folder. -# i.e. It could here: DefaultProjectSource/Platform/ or -# //DefaultProjectSource -ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} ${o3de_gem_restricted_path} ${o3de_gem_path} ${o3de_gem_name}) +ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME} "${o3de_gem_restricted_path}" ${o3de_gem_path} ${o3de_gem_name}) # Now that we have the platform abstraction layer (PAL) folder for this folder, thats where we will find the # project cmake for this platform. diff --git a/Templates/DefaultProject/preview.png b/Templates/DefaultProject/preview.png new file mode 100644 index 0000000000..78a2a735d2 --- /dev/null +++ b/Templates/DefaultProject/preview.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ae503ec99c8358991dc3c6e50737844d3602b81a49abbbed7d697d7238547c0 +size 28026 diff --git a/Templates/MinimalProject/preview.png b/Templates/MinimalProject/preview.png new file mode 100644 index 0000000000..b94e84a348 --- /dev/null +++ b/Templates/MinimalProject/preview.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1c14254e4c822fb50bfec42691c49f1089ab020a873c366f71168390d3705c6e +size 17522 diff --git a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake index a7a5c99adf..5e2fdff8ea 100644 --- a/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake +++ b/cmake/3rdParty/Platform/Mac/BuiltInPackages_mac.cmake @@ -42,5 +42,5 @@ ly_associate_package(PACKAGE_NAME mikkelsen-1.0.0.4-mac ly_associate_package(PACKAGE_NAME googletest-1.8.1-rev4-mac TARGETS googletest PACKAGE_HASH cbf020d5ef976c5db8b6e894c6c63151ade85ed98e7c502729dd20172acae5a8) ly_associate_package(PACKAGE_NAME googlebenchmark-1.5.0-rev2-mac TARGETS GoogleBenchmark PACKAGE_HASH ad25de0146769c91e179953d845de2bec8ed4a691f973f47e3eb37639381f665) ly_associate_package(PACKAGE_NAME OpenSSL-1.1.1b-rev1-mac TARGETS OpenSSL PACKAGE_HASH 28adc1c0616ac0482b2a9d7b4a3a3635a1020e87b163f8aba687c501cf35f96c) -ly_associate_package(PACKAGE_NAME qt-5.15.2-rev4-mac TARGETS Qt PACKAGE_HASH 08790d03a0e6ad808ad64cf25c3d75abd69a343f3d224fc39927e5c6e8738b98) +ly_associate_package(PACKAGE_NAME qt-5.15.2-rev5-mac TARGETS Qt PACKAGE_HASH 9d25918351898b308ded3e9e571fff6f26311b2071aeafd00dd5b249fdf53f7e) ly_associate_package(PACKAGE_NAME libsamplerate-0.2.1-rev2-mac TARGETS libsamplerate PACKAGE_HASH b912af40c0ac197af9c43d85004395ba92a6a859a24b7eacd920fed5854a97fe) diff --git a/cmake/LYWrappers.cmake b/cmake/LYWrappers.cmake index b6daf8b6d7..40bf6ef541 100644 --- a/cmake/LYWrappers.cmake +++ b/cmake/LYWrappers.cmake @@ -380,12 +380,14 @@ function(ly_delayed_target_link_libraries) cmake_parse_arguments(ly_delayed_target_link_libraries "" "" "${visibilities}" ${delayed_link}) foreach(visibility ${visibilities}) - foreach(item ${ly_delayed_target_link_libraries_${visibility}}) + foreach(alias_item ${ly_delayed_target_link_libraries_${visibility}}) - if(TARGET ${item}) - get_target_property(item_type ${item} TYPE) + if(TARGET ${alias_item}) + get_target_property(item_type ${alias_item} TYPE) + ly_de_alias_target(${alias_item} item) else() unset(item_type) + set(item ${alias_item}) endif() if(item_type STREQUAL MODULE_LIBRARY) diff --git a/cmake/PAL.cmake b/cmake/PAL.cmake index 11541d395a..c51b39482f 100644 --- a/cmake/PAL.cmake +++ b/cmake/PAL.cmake @@ -29,7 +29,8 @@ function(o3de_restricted_id o3de_json_file restricted) ly_file_read(${o3de_json_file} json_data) string(JSON restricted_entry ERROR_VARIABLE json_error GET ${json_data} "restricted_name") if(json_error) - message(WARNING "Unable to read restricted from '${o3de_json_file}', error: ${json_error}") + # Restricted fields can never be a requirement so no warning is issued + return() endif() if(restricted_entry) set(${restricted} ${restricted_entry} PARENT_SCOPE) @@ -148,86 +149,89 @@ function(ly_get_absolute_pal_filename out_name in_name) set(full_name ${in_name}) if(${ARGC} GREATER 4) - # The user has supplied an object restricted path, the object path and the object name for consideration - set(object_restricted_path ${ARGV2}) - set(object_path ${ARGV3}) + # The object name is used to resolve ambiguities when a PAL directory is requested from + # two different external subdirectory root paths + # Such as if a PAL directory for two root object paths with same relative structure was requested to be Palified + # i.e /Platform//IO and /Platform//IO + # Normally the restricted PAL path for both gems would be "//IO". + # The object name can be used to make this path unique + # "///IO" for gem 1 and + # "///IO" for gem 2 set(object_name ${ARGV4}) + endif() - # if the file is not in the object path then we cannot determine a PAL file for it - file(RELATIVE_PATH relative_path ${object_path} ${full_name}) - if (NOT (IS_ABSOLUTE relative_path OR relative_path MATCHES [[^(\.\./)+(.*)]])) - if (NOT EXISTS ${full_name}) - string(REGEX MATCH "${object_path}/(.*)/Platform/([^/]*)/?(.*)$" match ${full_name}) - if(NOT CMAKE_MATCH_1) - string(REGEX MATCH "${object_path}/Platform/([^/]*)/?(.*)$" match ${full_name}) - set(full_name ${object_restricted_path}/${CMAKE_MATCH_1}/${object_name}) - if(CMAKE_MATCH_2) - string(APPEND full_name "/" ${CMAKE_MATCH_2}) - endif() - elseif("${CMAKE_MATCH_2}" IN_LIST PAL_RESTRICTED_PLATFORMS) - set(full_name ${object_restricted_path}/${CMAKE_MATCH_2}/${object_name}/${CMAKE_MATCH_1}) - if(CMAKE_MATCH_3) - string(APPEND full_name "/" ${CMAKE_MATCH_3}) - endif() - endif() - endif() - endif() - set(${out_name} ${full_name} PARENT_SCOPE) - - elseif(${ARGC} GREATER 3) + # The Default object path for path is the LY_ROOT_FOLDER + cmake_path(SET object_path NORMALIZE "${LY_ROOT_FOLDER}") + if(${ARGC} GREATER 3) # The user has supplied an object restricted path, the object path for consideration - set(object_restricted_path ${ARGV2}) - set(object_path ${ARGV3}) + cmake_path(SET object_path NORMALIZE ${ARGV3}) + endif() + + # The Default restricted object path is the result of the read_engine_restricted_path function + cmake_path(SET object_restricted_path NORMALIZE "${O3DE_ENGINE_RESTRICTED_PATH}") + if(${ARGC} GREATER 2) + # The user has supplied an object restricted path + cmake_path(SET object_restricted_path NORMALIZE ${ARGV2}) + endif() + # The input path must exist in order to form a PAL path + if (NOT EXISTS ${full_name}) # if the file is not in the object path then we cannot determine a PAL file for it - file(RELATIVE_PATH relative_path ${object_path} ${full_name}) - if (NOT (IS_ABSOLUTE relative_path OR relative_path MATCHES [[^(\.\./)+(.*)]])) - if (NOT EXISTS ${full_name}) - string(REGEX MATCH "${object_path}/(.*)/Platform/([^/]*)/?(.*)$" match ${full_name}) - if(NOT CMAKE_MATCH_1) - string(REGEX MATCH "${object_path}/Platform/([^/]*)/?(.*)$" match ${full_name}) - set(full_name ${object_restricted_path}/${CMAKE_MATCH_1}) - if(CMAKE_MATCH_2) - string(APPEND full_name "/" ${CMAKE_MATCH_2}) - endif() - elseif("${CMAKE_MATCH_2}" IN_LIST PAL_RESTRICTED_PLATFORMS) - set(full_name ${object_restricted_path}/${CMAKE_MATCH_2}/${CMAKE_MATCH_1}) - if(CMAKE_MATCH_3) - string(APPEND full_name "/" ${CMAKE_MATCH_3}) - endif() + cmake_path(IS_PREFIX object_path ${full_name} is_input_path_in_root) + if(is_input_path_in_root) + cmake_path(RELATIVE_PATH full_name BASE_DIRECTORY ${object_path} OUTPUT_VARIABLE relative_object_path) + cmake_path(SET current_object_path ${relative_object_path}) + + # Remove one path segment from the end of the current_object_path and prepend it to the list path_segments + cmake_path(GET current_object_path PARENT_PATH parent_path) + cmake_path(GET current_object_path FILENAME path_segment) + list(PREPEND path_segments_visited path_segment) + cmake_path(COMPARE current_object_path NOT_EQUAL parent_path is_prev_path_segment) + cmake_path(SET current_object_path "${parent_path}") + + while(is_prev_path_segment) + # The Path is in a PAL structure + # Decompose the path into sections before "Platform" and after "Platform" + if(path_segment STREQUAL "Platform") + # The first path segment after the "/Platform/" + # is a potential platform name. Store it off for later checks + list(GET path_segments_visited 0 candidate_platform_name) + + # Store off all the path segments iterated from the end in the post-"Platform" path + cmake_path(APPEND post_platform_paths ${path_segments_visited}) + # The parent path is just the pre-"Platform" section of the path + cmake_path(SET pre_platform_paths "${parent_path}") + break() endif() - endif() - endif() - set(${out_name} ${full_name} PARENT_SCOPE) - - else() - # The user has not supplied any path so we must assume it is the o3de engine restricted and o3de engine path - # if the file is not in the o3de engine path then we cannot determine a PAL file for it - file(RELATIVE_PATH relative_path ${LY_ROOT_FOLDER} ${full_name}) - if (NOT (IS_ABSOLUTE relative_path OR relative_path MATCHES [[^(\.\./)+(.*)]])) - if (NOT EXISTS ${full_name}) - string(REGEX MATCH "${LY_ROOT_FOLDER}/(.*)/Platform/([^/]*)/?(.*)$" match ${full_name}) - if(NOT CMAKE_MATCH_1) - string(REGEX MATCH "${LY_ROOT_FOLDER}/Platform/([^/]*)/?(.*)$" match ${full_name}) - set(full_name ${O3DE_ENGINE_RESTRICTED_PATH}/${CMAKE_MATCH_1}) - if(CMAKE_MATCH_2) - string(APPEND full_name "/" ${CMAKE_MATCH_2}) - endif() - elseif("${CMAKE_MATCH_2}" IN_LIST PAL_RESTRICTED_PLATFORMS) - set(full_name ${O3DE_ENGINE_RESTRICTED_PATH}/${CMAKE_MATCH_2}/${CMAKE_MATCH_1}) - if(CMAKE_MATCH_3) - string(APPEND full_name "/" ${CMAKE_MATCH_3}) - endif() + + # Remove one path segment from the end of the current_object_path and prepend it to the list path_segments + cmake_path(GET current_object_path PARENT_PATH parent_path) + cmake_path(GET current_object_path FILENAME path_segment) + list(PREPEND path_segments_visited path_segment) + cmake_path(COMPARE current_object_path NOT_EQUAL parent_path is_prev_path_segment) + cmake_path(SET current_object_path "${parent_path}") + endwhile() + + # Compose a candidate restricted path and examine if it exists + cmake_path(APPEND object_restricted_path ${pre_platform_paths} "Platform" ${post_platform_paths} + OUTPUT_VARIABLE candidate_PAL_path) + if(NOT EXISTS ${candidate_PAL_path}) + if("${candidate_platform_name}" IN_LIST PAL_RESTRICTED_PLATFORMS) + cmake_path(APPEND object_restricted_path ${candidate_platform_name} ${object_name} + ${pre_platform_paths} ${post_platform_paths} OUTPUT_VARIABLE candidate_PAL_path) endif() endif() + if(EXISTS ${candidate_PAL_path}) + cmake_path(SET full_name ${candidate_PAL_path}) + endif() endif() - set(${out_name} ${full_name} PARENT_SCOPE) endif() + set(${out_name} ${full_name} PARENT_SCOPE) endfunction() function(ly_get_list_relative_pal_filename out_name in_name) ly_get_absolute_pal_filename(abs_name ${in_name} ${ARGN}) - file(RELATIVE_PATH relative_name ${CMAKE_CURRENT_LIST_DIR} ${abs_name}) + cmake_path(RELATIVE_PATH abs_name BASE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} OUTPUT_VARIABLE relative_name) set(${out_name} ${relative_name} PARENT_SCOPE) endfunction() diff --git a/cmake/Platform/Common/RuntimeDependencies_common.cmake b/cmake/Platform/Common/RuntimeDependencies_common.cmake index 734dd94203..31c8191a57 100644 --- a/cmake/Platform/Common/RuntimeDependencies_common.cmake +++ b/cmake/Platform/Common/RuntimeDependencies_common.cmake @@ -254,7 +254,8 @@ function(ly_delayed_generate_runtime_dependencies) # Generate the output file set(target_file_dir "$") - file(READ ${LY_RUNTIME_DEPENDENCIES_TEMPLATE} template_file) + set(target_file "$") + ly_file_read(${LY_RUNTIME_DEPENDENCIES_TEMPLATE} template_file) string(CONFIGURE "${LY_COPY_COMMANDS}" LY_COPY_COMMANDS @ONLY) string(CONFIGURE "${template_file}" configured_template_file @ONLY) file(GENERATE diff --git a/cmake/Platform/Common/runtime_dependencies_common.cmake.in b/cmake/Platform/Common/runtime_dependencies_common.cmake.in index e2a85374b8..9d23a73a26 100644 --- a/cmake/Platform/Common/runtime_dependencies_common.cmake.in +++ b/cmake/Platform/Common/runtime_dependencies_common.cmake.in @@ -13,6 +13,7 @@ function(ly_copy source_file target_directory) if(NOT ${same_location}) file(LOCK ${target_directory}/${target_filename}.lock GUARD FUNCTION TIMEOUT 300) if("${source_file}" IS_NEWER_THAN "${target_directory}/${target_filename}") + message(STATUS "Copying \"${source_file}\" to \"${target_directory}\"...") file(COPY "${source_file}" DESTINATION "${target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN) endif() endif() diff --git a/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in b/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in index 92ad3514d4..9f9006c4c0 100644 --- a/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in +++ b/cmake/Platform/Mac/runtime_dependencies_mac.cmake.in @@ -19,56 +19,96 @@ endfunction() include(BundleUtilities) cmake_policy(SET CMP0012 NEW) # new policy for the if that evaluates a boolean out of the LY_BUILD_FIXUP_BUNDLE expansion +cmake_policy(SET CMP0009 NEW) # do not traverse symlinks on GLOB_RECURSE set(anything_new FALSE) set(plugin_libs) set(plugin_dirs) +set(depends_on_python FALSE) + +find_program(LY_INSTALL_NAME_TOOL install_name_tool) +if (NOT LY_INSTALL_NAME_TOOL) + message(FATAL_ERROR "Unable to locate 'install_name_tool'") +endif() function(ly_copy source_file target_directory) get_filename_component(target_filename "${source_file}" NAME) - # If source_file is a Framework and target_directory is a bundle - if("${source_file}" MATCHES "\\.[Ff]ramework[^\\.]" AND "${target_directory}" MATCHES "\\.app/Contents/MacOS") + # If target_directory is a bundle + if("${target_directory}" MATCHES "\\.app/Contents/MacOS") - if(NOT @LY_BUILD_FIXUP_BUNDLE@) - return() - endif() + set(target_is_bundle TRUE) + if("${source_file}" MATCHES "\\.[Ff]ramework[^\\.]") - # fixup origin to copy the whole Framework folder and change destination to Contents/Frameworks - string(REGEX REPLACE "(.*\\.[Ff]ramework).*" "\\1" source_file "${source_file}") - get_filename_component(source_file_folder "${source_file}" DIRECTORY) - - set(local_plugin_dirs ${plugin_dirs}) - list(APPEND local_plugin_dirs "${source_file_folder}") - set(plugin_dirs ${local_plugin_dirs} PARENT_SCOPE) - return() + if(NOT @LY_BUILD_FIXUP_BUNDLE@) + return() + endif() - elseif("${source_file}" MATCHES "qt/plugins" AND "${target_directory}" MATCHES "\\.app/Contents/MacOS") + # fixup origin to copy the whole Framework folder and change destination to Contents/Frameworks + string(REGEX REPLACE "(.*\\.[Ff]ramework).*" "\\1" source_file "${source_file}") + get_filename_component(source_file_folder "${source_file}" DIRECTORY) + + # Python.framework produces a bug in BundleUtilities so it needs manual handling + # https://gitlab.kitware.com/cmake/cmake/-/issues/20165 + if("${source_file}" MATCHES "Python.framework") + # fixup the destination so it ends up in Contents/Frameworks + string(REGEX REPLACE "(.*\\.app/Contents)/MacOS" "\\1/Frameworks" target_directory "${target_directory}") + set(local_plugin_dirs ${plugin_dirs}) + list(APPEND local_plugin_dirs "${target_directory}/Python.framework") + set(target_filename Python.framework) + set(plugin_dirs ${local_plugin_dirs} PARENT_SCOPE) + set(depends_on_python TRUE PARENT_SCOPE) + else() + set(local_plugin_dirs ${plugin_dirs}) + list(APPEND local_plugin_dirs "${source_file_folder}") + set(plugin_dirs ${local_plugin_dirs} PARENT_SCOPE) + return() + endif() - if(NOT @LY_BUILD_FIXUP_BUNDLE@) - return() - endif() + elseif("${source_file}" MATCHES "qt/plugins") - # fixup the destination so it ends up in Contents/Plugins - string(REGEX REPLACE "(.*\\.app/Contents)/MacOS" "\\1/plugins" target_directory "${target_directory}") + if(NOT @LY_BUILD_FIXUP_BUNDLE@) + return() + endif() - set(local_plugin_dirs ${plugin_dirs}) - list(APPEND local_plugin_dirs "${target_directory}") - set(plugin_dirs ${local_plugin_dirs} PARENT_SCOPE) - set(local_plugin_libs ${plugin_libs}) - list(APPEND local_plugin_libs "${target_directory}/${target_filename}") - set(plugin_libs ${local_plugin_libs} PARENT_SCOPE) + # fixup the destination so it ends up in Contents/Plugins + string(REGEX REPLACE "(.*\\.app/Contents)/MacOS" "\\1/plugins" target_directory "${target_directory}") - elseif("${source_file}" MATCHES "qt/translations" AND "${target_directory}" MATCHES "\\.app/Contents/MacOS") + set(local_plugin_dirs ${plugin_dirs}) + list(APPEND local_plugin_dirs "${target_directory}") + set(plugin_dirs ${local_plugin_dirs} PARENT_SCOPE) + set(local_plugin_libs ${plugin_libs}) + list(APPEND local_plugin_libs "${target_directory}/${target_filename}") + set(plugin_libs ${local_plugin_libs} PARENT_SCOPE) - return() # skip, is this used? + elseif("${source_file}" MATCHES "qt/translations") + + return() # skip, is this used? + + elseif("${source_file}" MATCHES ".dylib") + + set(local_plugin_dirs ${plugin_dirs}) + list(APPEND local_plugin_dirs "${target_directory}") + set(plugin_dirs ${local_plugin_dirs} PARENT_SCOPE) + + endif() - elseif("${source_file}" MATCHES ".dylib") + else() + + # target is not a bundle + set(target_is_bundle FALSE) + if("${source_file}" MATCHES "\\.[Ff]ramework[^\\.]") + + # fixup origin to copy the whole Framework folder + string(REGEX REPLACE "(.*\\.[Ff]ramework).*" "\\1" source_file "${source_file}") + get_filename_component(target_filename "${source_file}" NAME) + + if("${source_file}" MATCHES "Python.framework") + set(depends_on_python TRUE PARENT_SCOPE) + endif() - set(local_plugin_dirs ${plugin_dirs}) - list(APPEND local_plugin_dirs "${target_directory}") - set(plugin_dirs ${local_plugin_dirs} PARENT_SCOPE) + endif() endif() @@ -79,6 +119,11 @@ function(ly_copy source_file target_directory) endif() if(NOT EXISTS "${target_directory}/${target_filename}" OR "${source_file}" IS_NEWER_THAN "${target_directory}/${target_filename}") message(STATUS "Copying \"${source_file}\" to \"${target_directory}\"...") + if(NOT target_is_bundle) + # if it is a bundle, there is no contention about the files in the destination, each bundle target will copy everything + # we dont want these files to invalidate the bundle and cause a new signature + file(LOCK ${target_directory}/${target_filename}.lock GUARD FUNCTION TIMEOUT 300) + endif() file(COPY "${source_file}" DESTINATION "${target_directory}" FILE_PERMISSIONS @LY_COPY_PERMISSIONS@ FOLLOW_SYMLINK_CHAIN) file(TOUCH ${target_directory}/${target_filename}) set(anything_new TRUE PARENT_SCOPE) @@ -93,6 +138,7 @@ if(NOT @LY_BUILD_FIXUP_BUNDLE@) endif() if(@target_file_dir@ MATCHES ".app/Contents/MacOS") + string(REGEX REPLACE "(.*\\.app)/Contents/MacOS.*" "\\1" bundle_path "@target_file_dir@") set(fixup_timestamp_file "${bundle_path}.fixup.stamp") if(NOT anything_new) @@ -106,31 +152,44 @@ if(@target_file_dir@ MATCHES ".app/Contents/MacOS") if(EXISTS ${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/bin/dxc-3.7) list(APPEND fixup_bundle_ignore dxc-3.7) endif() - # Python.framework being copied by fixup_bundle - #if(EXISTS ${bundle_path}/Contents/Frameworks/Python.framework) - # # LYN-4502: Patch python bundle, it contains some windows executables, some files that fixup_bundle doesnt like and has - # # duplicated binaries between Versions/3.7 and Versions/Current. - # file(GLOB exe_files - # ${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/lib/python3.7/distutils/command/*.exe - # ${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/pip/_vendor/distlib/*.exe - # ${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/setuptools/*.exe - # ) - # foreach(exe_file ${exe_files}) - # file(REMOVE ${exe_file}) - # endforeach() - # file(REMOVE_RECURSE - # ${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/lib/python3.7/test - # ${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/scipy/io/tests - # ${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/Resources - # ${bundle_path}/Contents/Frameworks/Python.framework/Python - # ${bundle_path}/Contents/Frameworks/Python.framework/Resources/Python.app - # ${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/Python - # ) - # file(REMOVE_RECURSE ${bundle_path}/Contents/Frameworks/Python.framework/Versions/Current) - # execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink 3.7 Current - # WORKING_DIRECTORY ${bundle_path}/Contents/Frameworks/Python.framework/Versions/ - # ) - #endif() + # LYN-4502: Patch python bundle, it contains some windows executables, some files that fixup_bundle doesnt like and has + # other issues that produce signature problems + if(depends_on_python) + message(STATUS "Fixing ${bundle_path}/Contents/Frameworks/Python.framework...") + list(APPEND fixup_bundle_ignore Python python3.7m python3.7) + file(REMOVE_RECURSE + ${bundle_path}/Contents/Frameworks/Python.framework/Versions/Current + ${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/Headers + ${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/lib/Python + ${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/lib/python3.7/test + ${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/scipy/io/tests + ${bundle_path}/Contents/Frameworks/Python.framework/Python + ${bundle_path}/Contents/Frameworks/Python.framework/Resources + ${bundle_path}/Contents/Frameworks/Python.framework/Headers + ) + file(GLOB_RECURSE exe_file_list "${bundle_path}/Contents/Frameworks/Python.framework/**/*.exe") + if(exe_file_list) + file(REMOVE_RECURSE ${exe_file_list}) + endif() + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink include/python3.7m Headers + WORKING_DIRECTORY ${bundle_path}/Contents/Frameworks/Python.framework/Versions/3.7 + ) + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink 3.7 Current + WORKING_DIRECTORY ${bundle_path}/Contents/Frameworks/Python.framework/Versions/ + ) + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Python Python + WORKING_DIRECTORY ${bundle_path}/Contents/Frameworks/Python.framework + ) + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Headers Headers + WORKING_DIRECTORY ${bundle_path}/Contents/Frameworks/Python.framework + ) + execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink Versions/Current/Resources Resources + WORKING_DIRECTORY ${bundle_path}/Contents/Frameworks/Python.framework + ) + file(CHMOD ${bundle_path}/Contents/Frameworks/Python.framework/Versions/Current/Python + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE + ) + endif() list(REMOVE_DUPLICATES plugin_libs) list(REMOVE_DUPLICATES plugin_dirs) fixup_bundle("${bundle_path}" "${plugin_libs}" "${plugin_dirs}" IGNORE_ITEM ${fixup_bundle_ignore}) @@ -139,11 +198,27 @@ if(@target_file_dir@ MATCHES ".app/Contents/MacOS") # fixup bundle ends up removing the rpath of dxc (despite we exclude it) if(EXISTS ${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/bin/dxc-3.7) - find_program(LY_INSTALL_NAME_TOOL install_name_tool) - if (NOT LY_INSTALL_NAME_TOOL) - message(FATAL_ERROR "Unable to locate 'install_name_tool'") - endif() execute_process(COMMAND ${LY_INSTALL_NAME_TOOL} -add_rpath @executable_path/../lib ${bundle_path}/Contents/MacOS/Builders/DirectXShaderCompiler/bin/dxc-3.7) endif() + + # misplaced .DS_Store files can cause signing to fail + # Interrupted signatures can leave cstemp files behind that fail next signature + file(GLOB_RECURSE remove_file_list + "${bundle_path}/**/.DS_Store" + "${bundle_path/}**/*.cstemp" + ) + if(remove_file_list) + file(REMOVE_RECURSE ${remove_file_list}) + endif() + + endif() + +else() # Non-bundle case + + if(depends_on_python) + # RPATH fix python + execute_process(COMMAND ${LY_INSTALL_NAME_TOOL} -change @rpath/Python @rpath/Python.framework/Versions/Current/Python @target_file@) + endif() + endif() diff --git a/cmake/Platform/Windows/Packaging/Shortcuts.wxs b/cmake/Platform/Windows/Packaging/Shortcuts.wxs index 283a3c08ea..fefd15294a 100644 --- a/cmake/Platform/Windows/Packaging/Shortcuts.wxs +++ b/cmake/Platform/Windows/Packaging/Shortcuts.wxs @@ -26,10 +26,15 @@ - + + + Name="$(var.CPACK_PACKAGE_NAME) Project Manager" /> diff --git a/cmake/Platform/Windows/PackagingPostBuild.cmake b/cmake/Platform/Windows/PackagingPostBuild.cmake index 2d003d6062..70f8834207 100644 --- a/cmake/Platform/Windows/PackagingPostBuild.cmake +++ b/cmake/Platform/Windows/PackagingPostBuild.cmake @@ -105,39 +105,94 @@ file(TO_NATIVE_PATH "${_root_path}/python/python.cmd" _python_cmd) file(TO_NATIVE_PATH "${_root_path}/scripts/build/tools/upload_to_s3.py" _upload_script) file(TO_NATIVE_PATH "${_cpack_wix_out_dir}" _cpack_wix_out_dir) -# strip the scheme and extract the bucket/key prefix from the URL -string(REPLACE "s3://" "" _stripped_url ${CPACK_UPLOAD_URL}) -string(REPLACE "/" ";" _tokens ${_stripped_url}) - -list(POP_FRONT _tokens _bucket) -string(JOIN "/" _prefix ${_tokens}) - -set(_file_regex ".*(cab|exe|msi)$") -set(_extra_args [[{"ACL":"bucket-owner-full-control"}]]) - -set(_upload_command - ${_python_cmd} -s - -u ${_upload_script} - --base_dir ${_cpack_wix_out_dir} - --file_regex="${_file_regex}" - --bucket ${_bucket} - --key_prefix ${_prefix} - --extra_args ${_extra_args} -) - -if(CPACK_AWS_PROFILE) - list(APPEND _upload_command --profile ${CPACK_AWS_PROFILE}) -endif() +function(upload_to_s3 in_url in_local_path in_file_regex) + + # strip the scheme and extract the bucket/key prefix from the URL + string(REPLACE "s3://" "" _stripped_url ${in_url}) + string(REPLACE "/" ";" _tokens ${_stripped_url}) + + list(POP_FRONT _tokens _bucket) + string(JOIN "/" _prefix ${_tokens}) + + set(_extra_args [[{"ACL":"bucket-owner-full-control"}]]) + + set(_upload_command + ${_python_cmd} -s + -u ${_upload_script} + --base_dir ${in_local_path} + --file_regex="${in_file_regex}" + --bucket ${_bucket} + --key_prefix ${_prefix} + --extra_args ${_extra_args} + ) + + if(CPACK_AWS_PROFILE) + list(APPEND _upload_command --profile ${CPACK_AWS_PROFILE}) + endif() + + execute_process( + COMMAND ${_upload_command} + RESULT_VARIABLE _upload_result + OUTPUT_VARIABLE _upload_output + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + if (NOT ${_upload_result} EQUAL 0) + message(FATAL_ERROR "An error occurred uploading to s3.\nOutput:\n${_upload_output}") + endif() +endfunction() message(STATUS "Uploading artifacts to ${CPACK_UPLOAD_URL}") -execute_process( - COMMAND ${_upload_command} - RESULT_VARIABLE _upload_result - ERROR_VARIABLE _upload_errors +upload_to_s3( + ${CPACK_UPLOAD_URL} + ${_cpack_wix_out_dir} + ".*(cab|exe|msi)$" ) - -if (${_upload_result} EQUAL 0) - message(STATUS "Artifact uploading complete!") -else() - message(FATAL_ERROR "An error occurred uploading artifacts. ${_upload_errors}") +message(STATUS "Artifact uploading complete!") + +# for auto tagged builds, we will also upload a second copy of just the boostrapper +# to a special "Latest" folder under the branch in place of the commit date/hash +if(CPACK_AUTO_GEN_TAG) + message(STATUS "Updating latest tagged build") + + # make sure we can extra the commit info from the URL first + string(REGEX MATCH "([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]-[0-9a-zA-Z]+)" + _commit_info ${CPACK_UPLOAD_URL} + ) + if(NOT _commit_info) + message(FATAL_ERROR "Failed to extract the build tag") + endif() + + set(_temp_dir ${_cpack_wix_out_dir}/temp) + if(NOT EXISTS ${_temp_dir}) + file(MAKE_DIRECTORY ${_temp_dir}) + endif() + + # strip the version number form the exe name in the one uploaded to latest + string(TOLOWER "${CPACK_PACKAGE_NAME}_installer.exe" _non_versioned_exe) + set(_temp_exe_copy ${_temp_dir}/${_non_versioned_exe}) + + file(COPY ${_bootstrap_output_file} DESTINATION ${_temp_dir}) + file(RENAME "${_temp_dir}/${_bootstrap_filename}" ${_temp_exe_copy}) + + # include the commit info in a text file that will live next to the exe + set(_temp_info_file ${_temp_dir}/build_tag.txt) + file(WRITE ${_temp_info_file} ${_commit_info}) + + # update the URL and upload + string(REPLACE + ${_commit_info} "Latest" + _latest_upload_url ${CPACK_UPLOAD_URL} + ) + + upload_to_s3( + ${_latest_upload_url} + ${_temp_dir} + "(${_non_versioned_exe}|build_tag.txt)$" + ) + + # cleanup the temp files + file(REMOVE_RECURSE ${_temp_dir}) + + message(STATUS "Latest build update complete!") endif() diff --git a/cmake/SettingsRegistry.cmake b/cmake/SettingsRegistry.cmake index 0eae244c4f..934bae4e30 100644 --- a/cmake/SettingsRegistry.cmake +++ b/cmake/SettingsRegistry.cmake @@ -160,12 +160,6 @@ function(ly_delayed_generate_settings_registry) get_property(has_manually_added_dependencies TARGET ${gem_target} PROPERTY MANUALLY_ADDED_DEPENDENCIES SET) get_target_property(target_type ${gem_target} TYPE) - if (target_type STREQUAL "INTERFACE_LIBRARY" AND has_manually_added_dependencies) - # don't use interface libraries here, we only want ones which produce actual binaries unless the target - # is empty. We have still already recursed into their dependencies - they'll show up later. - # When the target has no dependencies however we want to add the gem root path to the generated setreg - continue() - endif() ly_get_gem_module_root(gem_module_root ${gem_target}) diff --git a/scripts/build/Jenkins/Jenkinsfile b/scripts/build/Jenkins/Jenkinsfile index 7b2227a6f1..e2f341ba7b 100644 --- a/scripts/build/Jenkins/Jenkinsfile +++ b/scripts/build/Jenkins/Jenkinsfile @@ -216,8 +216,6 @@ def CheckoutRepo(boolean disableSubmodules = false) { if (!fileExists(ENGINE_REPOSITORY_NAME)) { palMkdir(ENGINE_REPOSITORY_NAME) } - - palSh('git lfs uninstall', 'Git LFS Uninstall') // Prevent git from pulling lfs objects during checkout if(fileExists('.git')) { // If the repository after checkout is locked, likely we took a snapshot while git was running, @@ -251,13 +249,6 @@ def CheckoutRepo(boolean disableSubmodules = false) { ] } - // Run lfs in a separate step. Jenkins is unable to load the credentials for the custom LFS endpoint - withCredentials([usernamePassword(credentialsId: "${env.GITHUB_USER}", passwordVariable: 'accesstoken', usernameVariable: 'username')]) { - palSh("git config -f .lfsconfig lfs.url https://${username}:${accesstoken}@${env.LFS_URL}", 'Set credentials', false) - } - palSh('git lfs install', 'Git LFS Install') - palSh('git lfs pull', 'Git LFS Pull') - // CHANGE_ID is used by some scripts to identify uniquely the current change (usually metric jobs) palSh('git rev-parse HEAD > commitid', 'Getting commit id') env.CHANGE_ID = readFile file: 'commitid' diff --git a/scripts/o3de/o3de/register.py b/scripts/o3de/o3de/register.py index ff4ccdc0a6..9d1d6e3122 100644 --- a/scripts/o3de/o3de/register.py +++ b/scripts/o3de/o3de/register.py @@ -253,7 +253,8 @@ def add_engine_name_to_path(json_data: dict, engine_path: pathlib.Path, force: b logger.error( f'Attempting to register existing engine "{engine_name}" with a new path of {engine_path.as_posix()}.' f' The current path is {pathlib.Path(engines_path_json[engine_name]).as_posix()}.' - f' To force registration of a new engine path, specify the -f/--force option.') + f' To force registration of a new engine path, specify the -f/--force option.' + f'\nAlternatively the engine can be registered with a different name by changing the "engine_name" field in the engine.json.') return 1 engines_path_json[engine_name] = engine_path.as_posix() return 0 @@ -665,7 +666,7 @@ def remove_invalid_o3de_projects(manifest_path: pathlib.Path = None) -> int: result = 0 - for project in json_data['projects']: + for project in json_data.get('projects', []): if not validation.valid_o3de_project_json(pathlib.Path(project).resolve() / 'project.json'): logger.warn(f"Project path {project} is invalid.") # Attempt to unregister all invalid projects even if previous projects failed to unregister @@ -677,36 +678,36 @@ def remove_invalid_o3de_projects(manifest_path: pathlib.Path = None) -> int: def remove_invalid_o3de_objects() -> None: json_data = manifest.load_o3de_manifest() - for engine_object in json_data['engines']: - engine_path = engine_object['path'] + for engine_object in json_data.get('engines', []): + engine_path = engine_object.get('path', '') if not validation.valid_o3de_engine_json(pathlib.Path(engine_path).resolve() / 'engine.json'): logger.warn(f"Engine path {engine_path} is invalid.") register(engine_path=engine_path, remove=True) remove_invalid_o3de_projects() - for gem in json_data['gems']: + for gem in json_data.get('gems', []): if not validation.valid_o3de_gem_json(pathlib.Path(gem).resolve() / 'gem.json'): logger.warn(f"Gem path {gem} is invalid.") register(gem_path=gem, remove=True) - for external in json_data['external_subdirectories']: + for external in json_data.get('external_subdirectories', []): external = pathlib.Path(external).resolve() if not external.is_dir(): logger.warn(f"External subdirectory {external} is invalid.") register(engine_path=engine_path, external_subdir_path=external, remove=True) - for template in json_data['templates']: + for template in json_data.get('templates', []): if not validation.valid_o3de_template_json(pathlib.Path(template).resolve() / 'template.json'): logger.warn(f"Template path {template} is invalid.") register(template_path=template, remove=True) - for restricted in json_data['restricted']: + for restricted in json_data.get('restricted', []): if not validation.valid_o3de_restricted_json(pathlib.Path(restricted).resolve() / 'restricted.json'): logger.warn(f"Restricted path {restricted} is invalid.") register(restricted_path=restricted, remove=True) - default_engines_folder = pathlib.Path(json_data['default_engines_folder']).resolve() + default_engines_folder = pathlib.Path(json_data.get('default_engines_folder', manifest.get_o3de_engines_folder())).resolve() if not default_engines_folder.is_dir(): new_default_engines_folder = manifest.get_o3de_folder() / 'Engines' new_default_engines_folder.mkdir(parents=True, exist_ok=True) @@ -714,7 +715,7 @@ def remove_invalid_o3de_objects() -> None: f"Default engines folder {default_engines_folder} is invalid. Set default {new_default_engines_folder}") register(default_engines_folder=new_default_engines_folder.as_posix()) - default_projects_folder = pathlib.Path(json_data['default_projects_folder']).resolve() + default_projects_folder = pathlib.Path(json_data.get('default_projects_folder', manifest.get_o3de_projects_folder())).resolve() if not default_projects_folder.is_dir(): new_default_projects_folder = manifest.get_o3de_folder() / 'Projects' new_default_projects_folder.mkdir(parents=True, exist_ok=True) @@ -722,7 +723,7 @@ def remove_invalid_o3de_objects() -> None: f"Default projects folder {default_projects_folder} is invalid. Set default {new_default_projects_folder}") register(default_projects_folder=new_default_projects_folder.as_posix()) - default_gems_folder = pathlib.Path(json_data['default_gems_folder']).resolve() + default_gems_folder = pathlib.Path(json_data.get('default_gems_folder', manifest.get_o3de_gems_folder())).resolve() if not default_gems_folder.is_dir(): new_default_gems_folder = manifest.get_o3de_folder() / 'Gems' new_default_gems_folder.mkdir(parents=True, exist_ok=True) @@ -730,7 +731,7 @@ def remove_invalid_o3de_objects() -> None: f" Set default {new_default_gems_folder}") register(default_gems_folder=new_default_gems_folder.as_posix()) - default_templates_folder = pathlib.Path(json_data['default_templates_folder']).resolve() + default_templates_folder = pathlib.Path(json_data.get('default_templates_folder', manifest.get_o3de_templates_folder())).resolve() if not default_templates_folder.is_dir(): new_default_templates_folder = manifest.get_o3de_folder() / 'Templates' new_default_templates_folder.mkdir(parents=True, exist_ok=True) @@ -739,7 +740,7 @@ def remove_invalid_o3de_objects() -> None: f" Set default {new_default_templates_folder}") register(default_templates_folder=new_default_templates_folder.as_posix()) - default_restricted_folder = pathlib.Path(json_data['default_restricted_folder']).resolve() + default_restricted_folder = pathlib.Path(json_data.get('default_restricted_folder', manifest.get_o3de_restricted_folder())).resolve() if not default_restricted_folder.is_dir(): default_restricted_folder = manifest.get_o3de_folder() / 'Restricted' default_restricted_folder.mkdir(parents=True, exist_ok=True) @@ -748,7 +749,7 @@ def remove_invalid_o3de_objects() -> None: f" Set default {default_restricted_folder}") register(default_restricted_folder=default_restricted_folder.as_posix()) - default_third_party_folder = pathlib.Path(json_data['default_third_party_folder']).resolve() + default_third_party_folder = pathlib.Path(json_data.get('default_third_party_folder', manifest.get_o3de_third_party_folder())).resolve() if not default_third_party_folder.is_dir(): default_third_party_folder = manifest.get_o3de_folder() / '3rdParty' default_third_party_folder.mkdir(parents=True, exist_ok=True)