diff --git a/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvent_AddRemoveMethod_UpdatesInSC.py b/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvent_AddRemoveMethod_UpdatesInSC.py new file mode 100644 index 0000000000..21ad40014e --- /dev/null +++ b/AutomatedTesting/Gem/PythonTests/scripting/ScriptEvent_AddRemoveMethod_UpdatesInSC.py @@ -0,0 +1,202 @@ +""" +All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +its licensors. + +For complete copyright and license terms please see the LICENSE at the root of this +distribution (the "License"). All use of this software is governed by the License, +or, if provided, by the license below or the license accompanying this file. Do not +remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +""" + + +# fmt: off +class Tests(): + new_event_created = ("New Script Event created", "New Script Event not created") + child_1_created = ("Initial Child Event created", "Initial Child Event not created") + child_2_created = ("Second Child Event created", "Second Child Event not created") + file_saved = ("Script event file saved", "Script event file did not save") + method_added = ("Method added to scriptevent file", "Method not added to scriptevent file") + method_removed = ("Method removed from scriptevent file", "Method not removed from scriptevent file") +# fmt: on + + +def ScriptEvent_AddRemoveMethod_UpdatesInSC(): + """ + Summary: + Method can be added/removed to an existing .scriptevents file + + Expected Behavior: + The Method is correctly added/removed to the asset, and Script Canvas nodes are updated accordingly. + + Test Steps: + 1) Open Asset Editor and Script Canvas windows + 2) Initially create new Script Event file with one method + 3) Verify if file is created and saved + 4) Add a new child element + 5) Update MethodNames and save file + 6) Verify if the new node exist in SC (search in node palette) + 7) Delete one method and save + 8) Verify if the node is removed in SC + 9) Close Asset Editor + + Note: + - This test file must be called from the Open 3D Engine Editor command terminal + - Any passed and failed tests are written to the Editor.log file. + Parsing the file or running a log_monitor are required to observe the test results. + + :return: None + """ + import os + from utils import TestHelper as helper + import pyside_utils + + # Open 3D Engine imports + import azlmbr.legacy.general as general + import azlmbr.editor as editor + import azlmbr.bus as bus + + # Pyside imports + from PySide2 import QtWidgets, QtTest, QtCore + + GENERAL_WAIT = 1.0 # seconds + + FILE_PATH = os.path.join("AutomatedTesting", "TestAssets", "test_file.scriptevents") + METHOD_NAME = "test_method_name" + + editor_window = pyside_utils.get_editor_main_window() + asset_editor = asset_editor_widget = container = menu_bar = None + sc = node_palette = tree = search_frame = search_box = None + + def initialize_asset_editor_qt_objects(): + nonlocal asset_editor, asset_editor_widget, container, menu_bar + asset_editor = editor_window.findChild(QtWidgets.QDockWidget, "Asset Editor") + asset_editor_widget = asset_editor.findChild(QtWidgets.QWidget, "AssetEditorWindowClass") + container = asset_editor_widget.findChild(QtWidgets.QWidget, "ContainerForRows") + menu_bar = asset_editor_widget.findChild(QtWidgets.QMenuBar) + + def initialize_sc_qt_objects(): + nonlocal sc, node_palette, tree, search_frame, search_box + sc = editor_window.findChild(QtWidgets.QDockWidget, "Script Canvas") + if sc.findChild(QtWidgets.QDockWidget, "NodePalette") is None: + action = pyside_utils.find_child_by_pattern(sc, {"text": "Node Palette", "type": QtWidgets.QAction}) + action.trigger() + node_palette = sc.findChild(QtWidgets.QDockWidget, "NodePalette") + tree = node_palette.findChild(QtWidgets.QTreeView, "treeView") + search_frame = node_palette.findChild(QtWidgets.QFrame, "searchFrame") + search_box = search_frame.findChild(QtWidgets.QLineEdit, "searchFilter") + + def save_file(): + editor.AssetEditorWidgetRequestsBus(bus.Broadcast, "SaveAssetAs", FILE_PATH) + action = pyside_utils.find_child_by_pattern(menu_bar, {"type": QtWidgets.QAction, "iconText": "Save"}) + action.trigger() + # wait till file is saved, to validate that check the text of QLabel at the bottom of the AssetEditor, + # if there are no unsaved changes we will not have any * in the text + label = asset_editor.findChild(QtWidgets.QLabel, "textEdit") + return helper.wait_for_condition(lambda: "*" not in label.text(), 3.0) + + def expand_container_rows(object_name): + children = container.findChildren(QtWidgets.QFrame, object_name) + for child in children: + check_box = child.findChild(QtWidgets.QCheckBox) + if check_box and not check_box.isChecked(): + QtTest.QTest.mouseClick(check_box, QtCore.Qt.LeftButton, QtCore.Qt.NoModifier) + + def node_palette_search(node_name): + search_box.setText(node_name) + helper.wait_for_condition(lambda: search_box.text() == node_name, 1.0) + # Try clicking ENTER in search box multiple times + for _ in range(10): + QtTest.QTest.keyClick(search_box, QtCore.Qt.Key_Enter, QtCore.Qt.NoModifier) + if pyside_utils.find_child_by_pattern(tree, {"text": node_name}) is not None: + break + + # 1) Open Asset Editor + general.idle_enable(True) + # Initially close the Asset Editor and then reopen to ensure we don't have any existing assets open + general.close_pane("Asset Editor") + general.open_pane("Asset Editor") + helper.wait_for_condition(lambda: general.is_pane_visible("Asset Editor"), 5.0) + + # 2) Initially create new Script Event file with one method + initialize_asset_editor_qt_objects() + action = pyside_utils.find_child_by_pattern(menu_bar, {"type": QtWidgets.QAction, "text": "Script Events"}) + action.trigger() + result = helper.wait_for_condition( + lambda: container.findChild(QtWidgets.QFrame, "Events") is not None + and container.findChild(QtWidgets.QFrame, "Events").findChild(QtWidgets.QToolButton, "") is not None, + 3 * GENERAL_WAIT, + ) + Report.result(Tests.new_event_created, result) + # Add new method + add_event = container.findChild(QtWidgets.QFrame, "Events").findChild(QtWidgets.QToolButton, "") + add_event.click() + result = helper.wait_for_condition( + lambda: asset_editor_widget.findChild(QtWidgets.QFrame, "EventName") is not None, GENERAL_WAIT + ) + Report.result(Tests.child_1_created, result) + editor.AssetEditorWidgetRequestsBus(bus.Broadcast, "SaveAssetAs", FILE_PATH) + + # 3) Verify if file is created and saved + result = helper.wait_for_condition(lambda: os.path.exists(FILE_PATH), 3 * GENERAL_WAIT) + Report.result(Tests.file_saved, result and save_file()) + + # 4) Add a new child element + add_event = container.findChild(QtWidgets.QFrame, "Events").findChild(QtWidgets.QToolButton, "") + add_event.click() + result = helper.wait_for_condition( + lambda: len(asset_editor_widget.findChildren(QtWidgets.QFrame, "EventName")) == 2, 2 * GENERAL_WAIT + ) + Report.result(Tests.child_2_created, result) + + # 5) Update MethodNames and save file, (update all Method names to make it easier to search in SC later) + # Expand the EventName initially + expand_container_rows("EventName") + # Expand Name fields under it + expand_container_rows("Name") + count = 0 # 2 Method names will be updated Ex: test_method_name_0, test_method_name_1 + container = asset_editor_widget.findChild(QtWidgets.QWidget, "ContainerForRows") + children = container.findChildren(QtWidgets.QFrame, "Name") + for child in children: + line_edit = child.findChild(QtWidgets.QLineEdit) + if line_edit and line_edit.text() == "MethodName": + line_edit.setText(f"{METHOD_NAME}_{count}") + count += 1 + save_file() + + # 6) Verify if the new node exist in SC (search in node palette) + general.open_pane("Script Canvas") + helper.wait_for_condition(lambda: general.is_pane_visible("Script Canvas"), 5.0) + initialize_sc_qt_objects() + node_palette_search(f"{METHOD_NAME}_1") + get_node_index = lambda: pyside_utils.find_child_by_pattern(tree, {"text": f"{METHOD_NAME}_1"}) is not None + result = helper.wait_for_condition(get_node_index, GENERAL_WAIT) + Report.result(Tests.method_added, result) + + # 7) Delete one method and save + initialize_asset_editor_qt_objects() + for child in container.findChildren(QtWidgets.QFrame, "EventName"): + if child.findChild(QtWidgets.QToolButton, ""): + child.findChild(QtWidgets.QToolButton, "").click() + break + save_file() + + # 8) Verify if the node is removed in SC (search in node palette) + initialize_sc_qt_objects() + node_palette_search(f"{METHOD_NAME}_0") + get_node_index = lambda: pyside_utils.find_child_by_pattern(tree, {"text": f"{METHOD_NAME}_0"}) is None + result = helper.wait_for_condition(get_node_index, GENERAL_WAIT) + Report.result(Tests.method_removed, result) + + # 9) Close Asset Editor + general.close_pane("Asset Editor") + general.close_pane("Script Canvas") + + +if __name__ == "__main__": + import ImportPathHelper as imports + + imports.init() + from utils import Report + + Report.start_test(ScriptEvent_AddRemoveMethod_UpdatesInSC) diff --git a/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py index 9180c1b44c..85d0b4523f 100755 --- a/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py +++ b/AutomatedTesting/Gem/PythonTests/scripting/TestSuite_Periodic.py @@ -278,6 +278,7 @@ class TestScriptCanvasTests(object): }, ], ) + def test_Pane_PropertiesChanged_RetainsOnRestart(self, request, editor, config, project, launcher_platform): hydra.launch_and_validate_results( request, @@ -289,3 +290,31 @@ class TestScriptCanvasTests(object): auto_test_mode=False, timeout=60, ) + + def test_ScriptEvent_AddRemoveMethod_UpdatesInSC(self, request, workspace, editor, launcher_platform): + def teardown(): + file_system.delete( + [os.path.join(workspace.paths.project(), "TestAssets", "test_file.scriptevents")], True, True + ) + request.addfinalizer(teardown) + file_system.delete( + [os.path.join(workspace.paths.project(), "TestAssets", "test_file.scriptevents")], True, True + ) + expected_lines = [ + "Success: New Script Event created", + "Success: Initial Child Event created", + "Success: Second Child Event created", + "Success: Script event file saved", + "Success: Method added to scriptevent file", + "Success: Method removed from scriptevent file", + ] + hydra.launch_and_validate_results( + request, + TEST_DIRECTORY, + editor, + "ScriptEvent_AddRemoveMethod_UpdatesInSC.py", + expected_lines, + auto_test_mode=False, + timeout=60, + ) + \ No newline at end of file diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp index 9ab50a803c..92711f45b2 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetPicker/AssetPickerDialog.cpp @@ -81,9 +81,20 @@ namespace AzToolsFramework m_ui->m_assetBrowserTreeViewWidget->SetName("AssetBrowserTreeView_" + name); + bool selectedAsset = false; + for (auto& assetId : selection.GetSelectedAssetIds()) { - m_ui->m_assetBrowserTreeViewWidget->SelectProduct(assetId); + if (assetId.IsValid()) + { + selectedAsset = true; + m_ui->m_assetBrowserTreeViewWidget->SelectProduct(assetId); + } + } + + if (!selectedAsset) + { + m_ui->m_assetBrowserTreeViewWidget->SelectFolder(selection.GetDefaultDirectory()); } setWindowTitle(tr("Pick %1").arg(m_selection.GetTitle())); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.cpp index 65f361dc83..83734a24c3 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.cpp @@ -93,6 +93,16 @@ namespace AzToolsFramework m_selectedAssetIds.push_back(selectedAssetId); } + void AssetSelectionModel::SetDefaultDirectory(AZStd::string_view defaultDirectory) + { + m_defaultDirectory = defaultDirectory; + } + + AZStd::string_view AssetSelectionModel::GetDefaultDirectory() const + { + return m_defaultDirectory; + } + AZStd::vector& AssetSelectionModel::GetResults() { return m_results; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.h index 59cc9d05e2..5e9d23602a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/AssetSelectionModel.h @@ -47,6 +47,9 @@ namespace AzToolsFramework const AZStd::vector& GetSelectedAssetIds() const; void SetSelectedAssetIds(const AZStd::vector& selectedAssetIds); void SetSelectedAssetId(const AZ::Data::AssetId& selectedAssetId); + + void SetDefaultDirectory(AZStd::string_view defaultDirectory); + AZStd::string_view GetDefaultDirectory() const; AZStd::vector& GetResults(); const AssetBrowserEntry* GetResult(); @@ -72,6 +75,7 @@ namespace AzToolsFramework AZStd::vector m_selectedAssetIds; AZStd::vector m_results; + AZStd::string m_defaultDirectory; QString m_title; }; diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTreeView.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTreeView.cpp index eeee433835..6cd60b0015 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTreeView.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTreeView.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -270,7 +271,20 @@ namespace AzToolsFramework return false; } - bool AssetBrowserTreeView::SelectEntry(const QModelIndex& idxParent, const AZStd::vector& entries, const uint32_t entryPathIndex) + void AssetBrowserTreeView::SelectFolder(AZStd::string_view folderPath) + { + if (folderPath.size() == 0) + { + return; + } + + AZStd::vector entries; + AZ::StringFunc::Tokenize(folderPath, entries, "/"); + + SelectEntry(QModelIndex(), entries, 0, true); + } + + bool AssetBrowserTreeView::SelectEntry(const QModelIndex& idxParent, const AZStd::vector& entries, const uint32_t entryPathIndex, bool useDisplayName) { if (entries.empty()) { @@ -285,30 +299,43 @@ namespace AzToolsFramework auto rowIdx = model()->index(idx, 0, idxParent); auto rowEntry = GetEntryFromIndex(rowIdx); - // Check if this entry name matches the query - if (rowEntry && AzFramework::StringFunc::Equal(entry.c_str(), rowEntry->GetName().c_str(), true)) + if (rowEntry) { - // Final entry found - set it as the selected element - if (entryPathIndex == entries.size() - 1) - { - selectionModel()->clear(); - selectionModel()->select(rowIdx, QItemSelectionModel::Select); - setCurrentIndex(rowIdx); - return true; - } + // Check if this entry name matches the query + AZStd::string_view compareName = useDisplayName ? (const char*)(rowEntry->GetDisplayName().toUtf8()) : rowEntry->GetName().c_str(); - // If this isn't the final entry, it needs to be a folder for the path to be valid (otherwise, early out) - if (rowEntry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Folder) + if (AzFramework::StringFunc::Equal(entry.c_str(), compareName, true)) { - // Folder found - if the final entry is found, expand this folder so the final entry is viewable in the Asset Browser (otherwise, early out) - if (SelectEntry(rowIdx, entries, entryPathIndex + 1)) + // Final entry found - set it as the selected element + if (entryPathIndex == entries.size() - 1) { - expand(rowIdx); + if (rowEntry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Folder) + { + // Expand the item itself if it is a folder + expand(rowIdx); + } + + selectionModel()->clear(); + selectionModel()->select(rowIdx, QItemSelectionModel::Select); + setCurrentIndex(rowIdx); + return true; } + + // If this isn't the final entry, it needs to be a folder for the path to be valid (otherwise, early out) + if (rowEntry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Folder) + { + // Folder found - if the final entry is found, expand this folder so the final entry is viewable in the Asset + // Browser (otherwise, early out) + if (SelectEntry(rowIdx, entries, entryPathIndex + 1, useDisplayName)) + { + expand(rowIdx); + return true; + } + } + + return false; } - - return false; } } diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTreeView.h b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTreeView.h index 697396b09e..19cbd3745a 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTreeView.h +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/AssetBrowser/Views/AssetBrowserTreeView.h @@ -60,6 +60,8 @@ namespace AzToolsFramework AZStd::vector GetSelectedAssets() const; + void SelectFolder(AZStd::string_view folderPath); + ////////////////////////////////////////////////////////////////////////// // AssetBrowserViewRequestBus void SelectProduct(AZ::Data::AssetId assetID) override; @@ -67,6 +69,7 @@ namespace AzToolsFramework void ClearFilter() override; void Update() override; + ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// @@ -105,7 +108,7 @@ namespace AzToolsFramework QString m_name; bool SelectProduct(const QModelIndex& idxParent, AZ::Data::AssetId assetID); - bool SelectEntry(const QModelIndex& idxParent, const AZStd::vector& entryPathTokens, const uint32_t entryPathIndex = 0); + bool SelectEntry(const QModelIndex& idxParent, const AZStd::vector& entryPathTokens, const uint32_t entryPathIndex = 0, bool useDisplayName = false); //! Grab one entry from the source thumbnail list and update it void UpdateSCThumbnails(); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp index d69eb5559f..23f8378df5 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.cpp @@ -769,6 +769,14 @@ namespace AzToolsFramework // Request the AssetBrowser Dialog and set a type filter AssetSelectionModel selection = GetAssetSelectionModel(); selection.SetSelectedAssetId(m_selectedAssetID); + + AZStd::string defaultDirectory; + if (m_defaultDirectoryCallback) + { + m_defaultDirectoryCallback->Invoke(m_editNotifyTarget, defaultDirectory); + selection.SetDefaultDirectory(defaultDirectory); + } + AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, parentWidget()); if (selection.IsValid()) { @@ -1080,6 +1088,11 @@ namespace AzToolsFramework m_editNotifyCallback = editNotifyCallback; } + void PropertyAssetCtrl::SetDefaultDirectoryCallback(DefaultDirectoryCallbackType* callback) + { + m_defaultDirectoryCallback = callback; + } + void PropertyAssetCtrl::SetClearNotifyCallback(ClearCallbackType* clearNotifyCallback) { m_clearNotifyCallback = clearNotifyCallback; @@ -1214,6 +1227,11 @@ namespace AzToolsFramework GUI->SetTitle(title.c_str()); } } + else if (attrib == AZ_CRC_CE("DefaultStartingDirectoryCallback")) + { + // This is assumed to be an Asset Browser path to a specific folder to be used as a default by the asset picker if provided + GUI->SetDefaultDirectoryCallback(azdynamic_cast(attrValue->GetAttribute())); + } else if (attrib == AZ_CRC("EditCallback", 0xb74f2ee1)) { PropertyAssetCtrl::EditCallbackType* func = azdynamic_cast(attrValue->GetAttribute()); diff --git a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx index e845cdf4fb..37af3d0594 100644 --- a/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx +++ b/Code/Framework/AzToolsFramework/AzToolsFramework/UI/PropertyEditor/PropertyAssetCtrl.hxx @@ -68,6 +68,7 @@ namespace AzToolsFramework // This is meant to be used with the "EditCallback" Attribute using EditCallbackType = AZ::Edit::AttributeFunction; using ClearCallbackType = AZ::Edit::AttributeFunction; + using DefaultDirectoryCallbackType = AZ::Edit::AttributeFunction; PropertyAssetCtrl(QWidget *pParent = NULL, QString optionalValidDragDropExtensions = QString()); virtual ~PropertyAssetCtrl(); @@ -119,6 +120,7 @@ namespace AzToolsFramework EditCallbackType* m_editNotifyCallback = nullptr; ClearCallbackType* m_clearNotifyCallback = nullptr; QString m_optionalValidDragDropExtensions; + DefaultDirectoryCallbackType* m_defaultDirectoryCallback = nullptr; //! The number of characters after which the autocompleter dropdown will be shown. // Prevents showing too many options. @@ -196,6 +198,7 @@ namespace AzToolsFramework void SetEditNotifyTarget(void* editNotifyTarget); void SetEditNotifyCallback(EditCallbackType* editNotifyCallback); // This is meant to be used with the "EditCallback" Attribute void SetClearNotifyCallback(ClearCallbackType* clearNotifyCallback); // This is meant to be used with the "ClearNotify" Attribute + void SetDefaultDirectoryCallback(DefaultDirectoryCallbackType* callback); // This is meant to be used with the "DefaultStartingDirectoryCallback" Attribute void SetEditButtonEnabled(bool enabled); void SetEditButtonVisible(bool visible); void SetEditButtonIcon(const QIcon& icon); diff --git a/Code/Sandbox/Editor/CryEditDoc.cpp b/Code/Sandbox/Editor/CryEditDoc.cpp index a6c5f73c7f..747921d401 100644 --- a/Code/Sandbox/Editor/CryEditDoc.cpp +++ b/Code/Sandbox/Editor/CryEditDoc.cpp @@ -58,13 +58,11 @@ #include "LevelFileDialog.h" #include "StatObjBus.h" -// LmbrCentral -#include #include #include -#include // for LmbrCentral::EditorLightComponentRequestBus - +// LmbrCentral +#include // for LmbrCentral::EditorLightComponentRequestBus //#define PROFILE_LOADING_WITH_VTUNE diff --git a/Code/Sandbox/Editor/EditorViewportWidget.cpp b/Code/Sandbox/Editor/EditorViewportWidget.cpp index f72801a4d3..ecd11da817 100644 --- a/Code/Sandbox/Editor/EditorViewportWidget.cpp +++ b/Code/Sandbox/Editor/EditorViewportWidget.cpp @@ -53,6 +53,7 @@ // AtomToolsFramework #include +#include // CryCommon #include @@ -75,7 +76,6 @@ #include "EditorPreferencesPageGeneral.h" #include "ViewportManipulatorController.h" #include "LegacyViewportCameraController.h" -#include "ModernViewportCameraController.h" #include "EditorViewportSettings.h" #include "ViewPane.h" @@ -1220,7 +1220,7 @@ void EditorViewportWidget::SetViewportId(int id) { AzFramework::ReloadCameraKeyBindings(); - auto controller = AZStd::make_shared(); + auto controller = AZStd::make_shared(); controller->SetCameraListBuilderCallback([](AzFramework::Cameras& cameras) { auto firstPersonRotateCamera = AZStd::make_shared(AzFramework::CameraFreeLookButton); diff --git a/Code/Sandbox/Editor/GotoPositionDlg.cpp b/Code/Sandbox/Editor/GotoPositionDlg.cpp index a09f594b7b..f52a45cad4 100644 --- a/Code/Sandbox/Editor/GotoPositionDlg.cpp +++ b/Code/Sandbox/Editor/GotoPositionDlg.cpp @@ -34,6 +34,7 @@ CGotoPositionDlg::CGotoPositionDlg(QWidget* pParent /*=NULL*/) { m_ui->setupUi(this); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setFixedSize(size()); OnInitDialog(); auto doubleValueChanged = static_cast(&QDoubleSpinBox::valueChanged); @@ -98,6 +99,9 @@ void CGotoPositionDlg::OnInitDialog() m_ui->m_dymSegX->setVisible(false); m_ui->m_dymSegY->setVisible(false); + // Ensure the goto button is highlighted correctly. + m_ui->pushButton->setDefault(true); + OnUpdateNumbers(); } diff --git a/Code/Sandbox/Editor/GotoPositionDlg.ui b/Code/Sandbox/Editor/GotoPositionDlg.ui index 4c93c8f037..9791b5bff1 100644 --- a/Code/Sandbox/Editor/GotoPositionDlg.ui +++ b/Code/Sandbox/Editor/GotoPositionDlg.ui @@ -6,189 +6,210 @@ 0 0 - 358 - 198 + 290 + 180 Go to Position - - - - - Go To - - - - - - - Cancel - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 22 - 20 - - - - - - - - - - - - - - - - - - - - - - - Z: - - - - - - - Y: - - - - - - - Enter position here: - - - - - - - X: - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Position: - - - - - - - X: - - - - - - - X: - - - - - - - - - - Y: - - - - - - - Y: - - - - - - - Z: - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 22 - 20 - - - - - - - - Angles: - - - - - - - Segments: - - - - - - - - - - + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 22 + 20 + + + + + + + + + + + + + + + + + + + + + + + Z: + + + + + + + Y: + + + + + + + Enter position here: + + + + + + + X: + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + Position: + + + + + + + X: + + + + + + + X: + + + + + + + + + + Y: + + + + + + + Y: + + + + + + + Z: + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 22 + 20 + + + + + + + + Angles: + + + + + + + Segments: + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + Go To + + + + + + + Cancel + + + + + + m_posEdit diff --git a/Code/Sandbox/Editor/editor_lib_files.cmake b/Code/Sandbox/Editor/editor_lib_files.cmake index 0646fb566e..e1cf18df55 100644 --- a/Code/Sandbox/Editor/editor_lib_files.cmake +++ b/Code/Sandbox/Editor/editor_lib_files.cmake @@ -823,9 +823,6 @@ set(FILES ViewportManipulatorController.h LegacyViewportCameraController.cpp LegacyViewportCameraController.h - ModernViewportCameraController.cpp - ModernViewportCameraController.h - ModernViewportCameraControllerRequestBus.h RenderViewport.cpp RenderViewport.h TopRendererWnd.cpp diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt index 72d88b06b4..d02c656b8f 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/CMakeLists.txt @@ -38,6 +38,7 @@ ly_add_target( Gem::LmbrCentral AZ::AtomCore Gem::Atom_RPI.Public + Gem::AtomToolsFramework.Static ) ly_add_dependencies(Editor ComponentEntityEditorPlugin) diff --git a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp index 884e1f9e51..5ff2debe3d 100644 --- a/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp +++ b/Code/Sandbox/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.cpp @@ -66,8 +66,8 @@ #include #include +#include -#include #include "Objects/ComponentEntityObject.h" #include "ISourceControl.h" @@ -1736,9 +1736,9 @@ void SandboxIntegrationManager::GoToEntitiesInViewports(const AzToolsFramework:: const AZ::Transform nextCameraTransform = AZ::Transform::CreateLookAt(aabb.GetCenter() - (forward * distanceToTarget), aabb.GetCenter()); - SandboxEditor::ModernViewportCameraControllerRequestBus::Event( - viewportContext->GetId(), &SandboxEditor::ModernViewportCameraControllerRequestBus::Events::InterpolateToTransform, - nextCameraTransform); + AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event( + viewportContext->GetId(), + &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::InterpolateToTransform, nextCameraTransform); } } } diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp index 3c221d6055..bbc6099f24 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.cpp @@ -12,6 +12,8 @@ #include #include +#include +#include #include #include #include @@ -25,15 +27,18 @@ namespace O3DE::ProjectManager : ScreenWidget(parent) { m_gemModel = new GemModel(this); + GemSortFilterProxyModel* proxyModel = new GemSortFilterProxyModel(m_gemModel, this); QVBoxLayout* vLayout = new QVBoxLayout(); vLayout->setMargin(0); + vLayout->setSpacing(0); setLayout(vLayout); QHBoxLayout* hLayout = new QHBoxLayout(); + hLayout->setMargin(0); vLayout->addLayout(hLayout); - m_gemListView = new GemListView(m_gemModel, this); + m_gemListView = new GemListView(proxyModel, proxyModel->GetSelectionModel(), this); m_gemInspector = new GemInspector(m_gemModel, this); m_gemInspector->setFixedWidth(320); @@ -56,8 +61,19 @@ namespace O3DE::ProjectManager } #endif - hLayout->addWidget(m_gemListView); + GemFilterWidget* filterWidget = new GemFilterWidget(proxyModel); + filterWidget->setFixedWidth(250); + + QVBoxLayout* middleVLayout = new QVBoxLayout(); + middleVLayout->setMargin(0); + middleVLayout->setSpacing(0); + middleVLayout->addWidget(m_gemListView); + + hLayout->addWidget(filterWidget); + hLayout->addLayout(middleVLayout); hLayout->addWidget(m_gemInspector); + + proxyModel->InvalidateFilter(); } QVector GemCatalogScreen::GenerateTestData() @@ -73,10 +89,12 @@ namespace O3DE::ProjectManager gem.m_documentationLink = "http://www.amazon.com"; gem.m_dependingGemUuids = QStringList({"EMotionFX", "Atom"}); gem.m_conflictingGemUuids = QStringList({"Vegetation", "Camera", "ScriptCanvas", "CloudCanvas", "Networking"}); + gem.m_types = (GemInfo::Code | GemInfo::Asset); gem.m_version = "v1.01"; gem.m_lastUpdatedDate = "24th April 2021"; gem.m_binarySizeInKB = 40; gem.m_features = QStringList({"Animation", "Assets", "Physics"}); + gem.m_gemOrigin = GemInfo::O3DEFoundation; result.push_back(gem); gem.m_name = "Atom"; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h index 6a9c88d0f5..bf4202499f 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemCatalogScreen.h @@ -9,6 +9,7 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ + #pragma once #if !defined(Q_MOC_RUN) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp new file mode 100644 index 0000000000..c6651b7295 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.cpp @@ -0,0 +1,412 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace O3DE::ProjectManager +{ + FilterCategoryWidget::FilterCategoryWidget(const QString& header, + const QVector& elementNames, + const QVector& elementCounts, + bool showAllLessButton, + int defaultShowCount, + QWidget* parent) + : QWidget(parent) + , m_defaultShowCount(defaultShowCount) + { + AZ_Assert(elementNames.size() == elementCounts.size(), "Number of element names needs to match the counts."); + + QVBoxLayout* vLayout = new QVBoxLayout(); + setLayout(vLayout); + + // Collapse button + QHBoxLayout* collapseLayout = new QHBoxLayout(); + m_collapseButton = new QPushButton(); + m_collapseButton->setCheckable(true); + m_collapseButton->setFlat(true); + m_collapseButton->setFocusPolicy(Qt::NoFocus); + m_collapseButton->setFixedWidth(s_collapseButtonSize); + m_collapseButton->setStyleSheet("border: 0px; border-radius: 0px;"); + connect(m_collapseButton, &QPushButton::clicked, this, [=]() + { + UpdateCollapseState(); + }); + collapseLayout->addWidget(m_collapseButton); + + // Category title + QLabel* headerLabel = new QLabel(header); + headerLabel->setStyleSheet("font-size: 11pt;"); + collapseLayout->addWidget(headerLabel); + vLayout->addLayout(collapseLayout); + + vLayout->addSpacing(5); + + // Everything in the main widget will be collapsed/uncollapsed + { + m_mainWidget = new QWidget(); + vLayout->addWidget(m_mainWidget); + + QVBoxLayout* mainLayout = new QVBoxLayout(); + mainLayout->setMargin(0); + mainLayout->setAlignment(Qt::AlignTop); + m_mainWidget->setLayout(mainLayout); + + // Elements + m_buttonGroup = new QButtonGroup(); + m_buttonGroup->setExclusive(false); + for (int i = 0; i < elementNames.size(); ++i) + { + QWidget* elementWidget = new QWidget(); + QHBoxLayout* elementLayout = new QHBoxLayout(); + elementLayout->setMargin(0); + elementWidget->setLayout(elementLayout); + + QCheckBox* checkbox = new QCheckBox(elementNames[i]); + checkbox->setStyleSheet("font-size: 11pt;"); + m_buttonGroup->addButton(checkbox); + elementLayout->addWidget(checkbox); + + elementLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding)); + + QLabel* countLabel = new QLabel(QString::number(elementCounts[i])); + countLabel->setStyleSheet("font-size: 11pt; background-color: #333333; border-radius: 3px; color: #94D2FF;"); + elementLayout->addWidget(countLabel); + + m_elementWidgets.push_back(elementWidget); + mainLayout->addWidget(elementWidget); + } + + // See more / less + if (showAllLessButton) + { + m_seeAllLessLabel = new LinkLabel(); + connect(m_seeAllLessLabel, &LinkLabel::clicked, this, [=]() + { + m_seeAll = !m_seeAll; + UpdateSeeMoreLess(); + }); + mainLayout->addWidget(m_seeAllLessLabel); + } + else + { + mainLayout->addSpacing(5); + } + } + + // Separating line + QFrame* hLine = new QFrame(); + hLine->setFrameShape(QFrame::HLine); + hLine->setStyleSheet("color: #666666;"); + vLayout->addWidget(hLine); + + UpdateCollapseState(); + UpdateSeeMoreLess(); + } + + void FilterCategoryWidget::UpdateCollapseState() + { + if (m_collapseButton->isChecked()) + { + m_collapseButton->setIcon(QIcon(":/Resources/ArrowDownLine.svg")); + m_mainWidget->hide(); + } + else + { + m_collapseButton->setIcon(QIcon(":/Resources/ArrowUpLine.svg")); + m_mainWidget->show(); + } + } + + void FilterCategoryWidget::UpdateSeeMoreLess() + { + if (!m_seeAllLessLabel) + { + return; + } + + if (m_elementWidgets.isEmpty()) + { + m_seeAllLessLabel->hide(); + return; + } + else + { + m_seeAllLessLabel->show(); + } + + if (!m_seeAll) + { + m_seeAllLessLabel->setText("See all"); + } + else + { + m_seeAllLessLabel->setText("See less"); + } + + int showCount = m_seeAll ? m_elementWidgets.size() : m_defaultShowCount; + showCount = AZ::GetMin(showCount, m_elementWidgets.size()); + for (int i = 0; i < showCount; ++i) + { + m_elementWidgets[i]->show(); + } + for (int i = showCount; i < m_elementWidgets.size(); ++i) + { + m_elementWidgets[i]->hide(); + } + } + + QButtonGroup* FilterCategoryWidget::GetButtonGroup() + { + return m_buttonGroup; + } + + GemFilterWidget::GemFilterWidget(GemSortFilterProxyModel* filterProxyModel, QWidget* parent) + : QScrollArea(parent) + , m_filterProxyModel(filterProxyModel) + { + m_gemModel = m_filterProxyModel->GetSourceModel(); + + setWidgetResizable(true); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + + QWidget* mainWidget = new QWidget(); + setWidget(mainWidget); + + m_mainLayout = new QVBoxLayout(); + m_mainLayout->setAlignment(Qt::AlignTop); + mainWidget->setLayout(m_mainLayout); + + QLabel* filterByLabel = new QLabel("Filter by"); + filterByLabel->setStyleSheet("font-size: 15pt;"); + m_mainLayout->addWidget(filterByLabel); + + AddGemOriginFilter(); + AddTypeFilter(); + AddPlatformFilter(); + AddFeatureFilter(); + } + + void GemFilterWidget::AddGemOriginFilter() + { + QVector elementNames; + QVector elementCounts; + const int numGems = m_gemModel->rowCount(); + for (int originIndex = 0; originIndex < GemInfo::NumGemOrigins; ++originIndex) + { + const GemInfo::GemOrigin gemOriginToBeCounted = static_cast(1 << originIndex); + + int gemOriginCount = 0; + for (int gemIndex = 0; gemIndex < numGems; ++gemIndex) + { + const GemInfo::GemOrigin gemOrigin = m_gemModel->GetGemOrigin(m_gemModel->index(gemIndex, 0)); + + // Is the gem of the given origin? + if (gemOriginToBeCounted == gemOrigin) + { + gemOriginCount++; + } + } + + elementNames.push_back(GemInfo::GetGemOriginString(gemOriginToBeCounted)); + elementCounts.push_back(gemOriginCount); + } + + FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Provider", elementNames, elementCounts, /*showAllLessButton=*/false); + m_mainLayout->addWidget(filterWidget); + + const QList buttons = filterWidget->GetButtonGroup()->buttons(); + for (int i = 0; i < buttons.size(); ++i) + { + const GemInfo::GemOrigin gemOrigin = static_cast(1 << i); + QAbstractButton* button = buttons[i]; + + connect(button, &QAbstractButton::toggled, this, [=](bool checked) + { + GemInfo::GemOrigins gemOrigins = m_filterProxyModel->GetGemOrigins(); + if (checked) + { + gemOrigins |= gemOrigin; + } + else + { + gemOrigins &= ~gemOrigin; + } + m_filterProxyModel->SetGemOrigins(gemOrigins); + }); + } + } + + void GemFilterWidget::AddTypeFilter() + { + QVector elementNames; + QVector elementCounts; + const int numGems = m_gemModel->rowCount(); + for (int typeIndex = 0; typeIndex < GemInfo::NumTypes; ++typeIndex) + { + const GemInfo::Type type = static_cast(1 << typeIndex); + + int typeGemCount = 0; + for (int gemIndex = 0; gemIndex < numGems; ++gemIndex) + { + const GemInfo::Types types = m_gemModel->GetTypes(m_gemModel->index(gemIndex, 0)); + + // Is type (Asset, Code, Tool) part of the gem? + if (types & type) + { + typeGemCount++; + } + } + + elementNames.push_back(GemInfo::GetTypeString(type)); + elementCounts.push_back(typeGemCount); + } + + FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Type", elementNames, elementCounts, /*showAllLessButton=*/false); + m_mainLayout->addWidget(filterWidget); + + const QList buttons = filterWidget->GetButtonGroup()->buttons(); + for (int i = 0; i < buttons.size(); ++i) + { + const GemInfo::Type type = static_cast(1 << i); + QAbstractButton* button = buttons[i]; + + connect(button, &QAbstractButton::toggled, this, [=](bool checked) + { + GemInfo::Types types = m_filterProxyModel->GetTypes(); + if (checked) + { + types |= type; + } + else + { + types &= ~type; + } + m_filterProxyModel->SetTypes(types); + }); + } + } + + void GemFilterWidget::AddPlatformFilter() + { + QVector elementNames; + QVector elementCounts; + const int numGems = m_gemModel->rowCount(); + for (int platformIndex = 0; platformIndex < GemInfo::NumPlatforms; ++platformIndex) + { + const GemInfo::Platform platform = static_cast(1 << platformIndex); + + int platformGemCount = 0; + for (int gemIndex = 0; gemIndex < numGems; ++gemIndex) + { + const GemInfo::Platforms platforms = m_gemModel->GetPlatforms(m_gemModel->index(gemIndex, 0)); + + // Is platform supported? + if (platforms & platform) + { + platformGemCount++; + } + } + + elementNames.push_back(GemInfo::GetPlatformString(platform)); + elementCounts.push_back(platformGemCount); + } + + FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Supported Platforms", elementNames, elementCounts, /*showAllLessButton=*/false); + m_mainLayout->addWidget(filterWidget); + + const QList buttons = filterWidget->GetButtonGroup()->buttons(); + for (int i = 0; i < buttons.size(); ++i) + { + const GemInfo::Platform platform = static_cast(1 << i); + QAbstractButton* button = buttons[i]; + + connect(button, &QAbstractButton::toggled, this, [=](bool checked) + { + GemInfo::Platforms platforms = m_filterProxyModel->GetPlatforms(); + if (checked) + { + platforms |= platform; + } + else + { + platforms &= ~platform; + } + m_filterProxyModel->SetPlatforms(platforms); + }); + } + } + + void GemFilterWidget::AddFeatureFilter() + { + // Alphabetically sorted, unique features and their number of occurrences in the gem database. + QMap uniqueFeatureCounts; + const int numGems = m_gemModel->rowCount(); + for (int gemIndex = 0; gemIndex < numGems; ++gemIndex) + { + const QStringList features = m_gemModel->GetFeatures(m_gemModel->index(gemIndex, 0)); + for (const QString& feature : features) + { + if (!uniqueFeatureCounts.contains(feature)) + { + uniqueFeatureCounts.insert(feature, 1); + } + else + { + int& featureeCount = uniqueFeatureCounts[feature]; + featureeCount++; + } + } + } + + QVector elementNames; + QVector elementCounts; + for (auto iterator = uniqueFeatureCounts.begin(); iterator != uniqueFeatureCounts.end(); iterator++) + { + elementNames.push_back(iterator.key()); + elementCounts.push_back(iterator.value()); + } + + FilterCategoryWidget* filterWidget = new FilterCategoryWidget("Features", elementNames, elementCounts, + /*showAllLessButton=*/true, /*defaultShowCount=*/5); + m_mainLayout->addWidget(filterWidget); + + const QList buttons = filterWidget->GetButtonGroup()->buttons(); + for (int i = 0; i < buttons.size(); ++i) + { + const QString& feature = elementNames[i]; + QAbstractButton* button = buttons[i]; + + connect(button, &QAbstractButton::toggled, this, [=](bool checked) + { + QSet features = m_filterProxyModel->GetFeatures(); + if (checked) + { + features.insert(feature); + } + else + { + features.remove(feature); + } + m_filterProxyModel->SetFeatures(features); + }); + } + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.h new file mode 100644 index 0000000000..017eadc020 --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemFilterWidget.h @@ -0,0 +1,79 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +QT_FORWARD_DECLARE_CLASS(QButtonGroup) + +namespace O3DE::ProjectManager +{ + class FilterCategoryWidget + : public QWidget + { + Q_OBJECT // AUTOMOC + + public: + explicit FilterCategoryWidget(const QString& header, + const QVector& elementNames, + const QVector& elementCounts, + bool showAllLessButton = true, + int defaultShowCount = 4, + QWidget* parent = nullptr); + + QButtonGroup* GetButtonGroup(); + + private: + void UpdateCollapseState(); + void UpdateSeeMoreLess(); + + inline constexpr static int s_collapseButtonSize = 16; + QPushButton* m_collapseButton = nullptr; + + QWidget* m_mainWidget = nullptr; + QButtonGroup* m_buttonGroup = nullptr; + QVector m_elementWidgets; //! Includes checkbox and the count labl. + LinkLabel* m_seeAllLessLabel = nullptr; + int m_defaultShowCount = 0; + bool m_seeAll = false; + }; + + class GemFilterWidget + : public QScrollArea + { + Q_OBJECT // AUTOMOC + + public: + explicit GemFilterWidget(GemSortFilterProxyModel* filterProxyModel, QWidget* parent = nullptr); + ~GemFilterWidget() = default; + + private: + void AddGemOriginFilter(); + void AddTypeFilter(); + void AddPlatformFilter(); + void AddFeatureFilter(); + + QVBoxLayout* m_mainLayout = nullptr; + GemModel* m_gemModel = nullptr; + GemSortFilterProxyModel* m_filterProxyModel = nullptr; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp index 5b7127bdbe..791085f47a 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.cpp @@ -62,6 +62,19 @@ namespace O3DE::ProjectManager } } + QString GemInfo::GetGemOriginString(GemOrigin origin) + { + switch (origin) + { + case O3DEFoundation: + return "Open 3D Foundation"; + case Local: + return "Local"; + default: + return ""; + } + } + bool GemInfo::IsPlatformSupported(Platform platform) const { return (m_platforms & platform); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h index 28b2fab451..b96a1f242f 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInfo.h @@ -46,6 +46,15 @@ namespace O3DE::ProjectManager Q_DECLARE_FLAGS(Types, Type) static QString GetTypeString(Type type); + enum GemOrigin + { + O3DEFoundation = 1 << 0, + Local = 1 << 1, + NumGemOrigins = 2 + }; + Q_DECLARE_FLAGS(GemOrigins, GemOrigin) + static QString GetGemOriginString(GemOrigin origin); + GemInfo() = default; GemInfo(const QString& name, const QString& creator, const QString& summary, Platforms platforms, bool isAdded); bool IsPlatformSupported(Platform platform) const; @@ -57,6 +66,7 @@ namespace O3DE::ProjectManager QString m_displayName; AZ::Uuid m_uuid; QString m_creator; + GemOrigin m_gemOrigin = Local; bool m_isAdded = false; //! Is the gem currently added and enabled in the project? QString m_summary; Platforms m_platforms; @@ -74,3 +84,4 @@ namespace O3DE::ProjectManager Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::Platforms) Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::Types) +Q_DECLARE_OPERATORS_FOR_FLAGS(O3DE::ProjectManager::GemInfo::GemOrigins) diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp index e7c682afd1..6276ddc996 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemInspector.cpp @@ -70,8 +70,8 @@ namespace O3DE::ProjectManager m_documentationLinkLabel->SetUrl(m_model->GetDocLink(modelIndex)); // Depending and conflicting gems - m_dependingGems->Update("Depending Gems", "The following Gems will be automatically enabled with this Gem.", m_model->GetDependingGems(modelIndex)); - m_conflictingGems->Update("Conflicting Gems", "The following Gems will be automatically disabled with this Gem.", m_model->GetConflictingGems(modelIndex)); + m_dependingGems->Update("Depending Gems", "The following Gems will be automatically enabled with this Gem.", m_model->GetDependingGemNames(modelIndex)); + m_conflictingGems->Update("Conflicting Gems", "The following Gems will be automatically disabled with this Gem.", m_model->GetConflictingGemNames(modelIndex)); // Additional information m_versionLabel->setText(QString("Gem Version: %1").arg(m_model->GetVersion(modelIndex))); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp index 9a45600f70..a40e5eb447 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.cpp @@ -10,7 +10,7 @@ * */ -#include "GemItemDelegate.h" +#include #include "GemModel.h" #include #include @@ -18,9 +18,9 @@ namespace O3DE::ProjectManager { - GemItemDelegate::GemItemDelegate(GemModel* gemModel, QObject* parent) + GemItemDelegate::GemItemDelegate(QAbstractItemModel* model, QObject* parent) : QStyledItemDelegate(parent) - , m_gemModel(gemModel) + , m_model(model) { AddPlatformIcon(GemInfo::Android, ":/Android.svg"); AddPlatformIcon(GemInfo::iOS, ":/iOS.svg"); @@ -78,7 +78,7 @@ namespace O3DE::ProjectManager } // Gem name - const QString gemName = m_gemModel->GetName(modelIndex); + const QString gemName = GemModel::GetName(modelIndex); QFont gemNameFont(options.font); gemNameFont.setPixelSize(s_gemNameFontSize); gemNameFont.setBold(true); @@ -90,7 +90,7 @@ namespace O3DE::ProjectManager painter->drawText(gemNameRect, Qt::TextSingleLine, gemName); // Gem creator - const QString gemCreator = m_gemModel->GetCreator(modelIndex); + const QString gemCreator = GemModel::GetCreator(modelIndex); QRect gemCreatorRect = GetTextRect(standardFont, gemCreator, s_fontSize); gemCreatorRect.moveTo(contentRect.left(), contentRect.top() + gemNameRect.height()); @@ -105,7 +105,7 @@ namespace O3DE::ProjectManager painter->setFont(standardFont); painter->setPen(m_textColor); - const QString summary = m_gemModel->GetSummary(modelIndex); + const QString summary = GemModel::GetSummary(modelIndex); painter->drawText(summaryRect, Qt::AlignLeft | Qt::TextWordWrap, summary); @@ -158,7 +158,7 @@ namespace O3DE::ProjectManager void GemItemDelegate::DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const { - const GemInfo::Platforms platforms = m_gemModel->GetPlatforms(modelIndex); + const GemInfo::Platforms platforms = GemModel::GetPlatforms(modelIndex); int startX = 0; // Iterate and draw the platforms in the order they are defined in the enum. @@ -188,7 +188,7 @@ namespace O3DE::ProjectManager QPoint circleCenter; QString buttonText; - const bool isAdded = m_gemModel->IsAdded(modelIndex); + const bool isAdded = GemModel::IsAdded(modelIndex); if (isAdded) { painter->setBrush(m_buttonEnabledColor); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h index ee0392e188..d43b5d15f6 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemItemDelegate.h @@ -15,7 +15,7 @@ #if !defined(Q_MOC_RUN) #include #include "GemInfo.h" -#include "GemModel.h" +#include #include #endif @@ -29,22 +29,13 @@ namespace O3DE::ProjectManager Q_OBJECT // AUTOMOC public: - explicit GemItemDelegate(GemModel* gemModel, QObject* parent = nullptr); + explicit GemItemDelegate(QAbstractItemModel* model, QObject* parent = nullptr); ~GemItemDelegate() = default; void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override; bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& modelIndex) override; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& modelIndex) const override; - private: - void CalcRects(const QStyleOptionViewItem& option, const QModelIndex& modelIndex, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const; - QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const; - QRect CalcButtonRect(const QRect& contentRect) const; - void DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const; - void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const; - - GemModel* m_gemModel = nullptr; - // Colors const QColor m_textColor = QColor("#FFFFFF"); const QColor m_linkColor = QColor("#94D2FF"); @@ -71,6 +62,15 @@ namespace O3DE::ProjectManager inline constexpr static int s_buttonCircleRadius = s_buttonBorderRadius - 3; inline constexpr static qreal s_buttonFontSize = 12.0; + private: + void CalcRects(const QStyleOptionViewItem& option, const QModelIndex& modelIndex, QRect& outFullRect, QRect& outItemRect, QRect& outContentRect) const; + QRect GetTextRect(QFont& font, const QString& text, qreal fontSize) const; + QRect CalcButtonRect(const QRect& contentRect) const; + void DrawPlatformIcons(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const; + void DrawButton(QPainter* painter, const QRect& contentRect, const QModelIndex& modelIndex) const; + + QAbstractItemModel* m_model = nullptr; + // Platform icons void AddPlatformIcon(GemInfo::Platform platform, const QString& iconPath); inline constexpr static int s_platformIconSize = 16; diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp index ad75272c8f..2838277696 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.cpp @@ -18,17 +18,15 @@ namespace O3DE::ProjectManager { - GemListView::GemListView(GemModel* model, QWidget *parent) : - QListView(parent) + GemListView::GemListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent) + : QListView(parent) { setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); - QPalette palette; - palette.setColor(QPalette::Window, QColor("#333333")); - setPalette(palette); + setStyleSheet("background-color: #333333;"); setModel(model); - setSelectionModel(model->GetSelectionModel()); + setSelectionModel(selectionModel); setItemDelegate(new GemItemDelegate(model, this)); } } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.h index 79e16bd211..178de2395f 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemListView.h @@ -14,7 +14,8 @@ #if !defined(Q_MOC_RUN) #include "GemInfo.h" -#include "GemModel.h" +#include +#include #include #endif @@ -24,8 +25,9 @@ namespace O3DE::ProjectManager : public QListView { Q_OBJECT // AUTOMOC + public: - explicit GemListView(GemModel* model, QWidget *parent = nullptr); + explicit GemListView(QAbstractItemModel* model, QItemSelectionModel* selectionModel, QWidget* parent = nullptr); ~GemListView() = default; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp index addf59783d..724a8fa630 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.cpp @@ -36,11 +36,11 @@ namespace O3DE::ProjectManager const QString uuidString = gemInfo.m_uuid.ToString().c_str(); item->setData(uuidString, RoleUuid); item->setData(gemInfo.m_creator, RoleCreator); + item->setData(gemInfo.m_gemOrigin, RoleGemOrigin); item->setData(aznumeric_cast(gemInfo.m_platforms), RolePlatforms); item->setData(aznumeric_cast(gemInfo.m_types), RoleTypes); item->setData(gemInfo.m_summary, RoleSummary); item->setData(gemInfo.m_isAdded, RoleIsAdded); - item->setData(gemInfo.m_directoryLink, RoleDirectoryLink); item->setData(gemInfo.m_documentationLink, RoleDocLink); item->setData(gemInfo.m_dependingGemUuids, RoleDependingGems); @@ -48,12 +48,12 @@ namespace O3DE::ProjectManager item->setData(gemInfo.m_version, RoleVersion); item->setData(gemInfo.m_lastUpdatedDate, RoleLastUpdated); item->setData(gemInfo.m_binarySizeInKB, RoleBinarySize); - item->setData(gemInfo.m_features, RoleFeatures); appendRow(item); - m_uuidToNameMap[uuidString] = gemInfo.m_displayName; + const QModelIndex modelIndex = index(rowCount()-1, 0); + m_uuidToIndexMap[uuidString] = modelIndex; } void GemModel::Clear() @@ -71,6 +71,11 @@ namespace O3DE::ProjectManager return modelIndex.data(RoleCreator).toString(); } + GemInfo::GemOrigin GemModel::GetGemOrigin(const QModelIndex& modelIndex) + { + return static_cast(modelIndex.data(RoleGemOrigin).toInt()); + } + QString GemModel::GetUuidString(const QModelIndex& modelIndex) { return modelIndex.data(RoleUuid).toString(); @@ -106,42 +111,63 @@ namespace O3DE::ProjectManager return modelIndex.data(RoleDocLink).toString(); } - AZ::Outcome GemModel::FindGemNameByUuidString(const QString& uuidString) const + QModelIndex GemModel::FindIndexByUuidString(const QString& uuidString) const { - const auto iterator = m_uuidToNameMap.find(uuidString); - if (iterator != m_uuidToNameMap.end()) + const auto iterator = m_uuidToIndexMap.find(uuidString); + if (iterator != m_uuidToIndexMap.end()) { - return AZ::Success(iterator.value()); + return iterator.value(); } - return AZ::Failure(); + return {}; } - QStringList GemModel::GetDependingGems(const QModelIndex& modelIndex) + void GemModel::FindGemNamesByUuidStrings(QStringList& inOutGemNames) { - QStringList result = modelIndex.data(RoleDependingGems).toStringList(); + for (QString& dependingGemString : inOutGemNames) + { + QModelIndex modelIndex = FindIndexByUuidString(dependingGemString); + if (modelIndex.isValid()) + { + dependingGemString = GetName(modelIndex); + } + } + } + + QStringList GemModel::GetDependingGemUuids(const QModelIndex& modelIndex) + { + return modelIndex.data(RoleDependingGems).toStringList(); + } + + QStringList GemModel::GetDependingGemNames(const QModelIndex& modelIndex) + { + QStringList result = GetDependingGemUuids(modelIndex); if (result.isEmpty()) { return {}; } - for (QString& dependingGemString : result) - { - AZ::Outcome gemNameOutcome = FindGemNameByUuidString(dependingGemString); - if (gemNameOutcome.IsSuccess()) - { - dependingGemString = gemNameOutcome.GetValue(); - } - } - + FindGemNamesByUuidStrings(result); return result; } - QStringList GemModel::GetConflictingGems(const QModelIndex& modelIndex) + QStringList GemModel::GetConflictingGemUuids(const QModelIndex& modelIndex) { return modelIndex.data(RoleConflictingGems).toStringList(); } + QStringList GemModel::GetConflictingGemNames(const QModelIndex& modelIndex) + { + QStringList result = GetConflictingGemUuids(modelIndex); + if (result.isEmpty()) + { + return {}; + } + + FindGemNamesByUuidStrings(result); + return result; + } + QString GemModel::GetVersion(const QModelIndex& modelIndex) { return modelIndex.data(RoleVersion).toString(); diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h index 76211b1f22..480f4c74d3 100644 --- a/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemModel.h @@ -13,7 +13,6 @@ #pragma once #if !defined(Q_MOC_RUN) -#include #include #include #include @@ -34,11 +33,16 @@ namespace O3DE::ProjectManager void AddGem(const GemInfo& gemInfo); void Clear(); - AZ::Outcome FindGemNameByUuidString(const QString& uuidString) const; - QStringList GetDependingGems(const QModelIndex& modelIndex); + QModelIndex FindIndexByUuidString(const QString& uuidString) const; + void FindGemNamesByUuidStrings(QStringList& inOutGemNames); + QStringList GetDependingGemUuids(const QModelIndex& modelIndex); + QStringList GetDependingGemNames(const QModelIndex& modelIndex); + QStringList GetConflictingGemUuids(const QModelIndex& modelIndex); + QStringList GetConflictingGemNames(const QModelIndex& modelIndex); static QString GetName(const QModelIndex& modelIndex); static QString GetCreator(const QModelIndex& modelIndex); + static GemInfo::GemOrigin GetGemOrigin(const QModelIndex& modelIndex); static QString GetUuidString(const QModelIndex& modelIndex); static GemInfo::Platforms GetPlatforms(const QModelIndex& modelIndex); static GemInfo::Types GetTypes(const QModelIndex& modelIndex); @@ -46,7 +50,6 @@ namespace O3DE::ProjectManager static bool IsAdded(const QModelIndex& modelIndex); static QString GetDirectoryLink(const QModelIndex& modelIndex); static QString GetDocLink(const QModelIndex& modelIndex); - static QStringList GetConflictingGems(const QModelIndex& modelIndex); static QString GetVersion(const QModelIndex& modelIndex); static QString GetLastUpdated(const QModelIndex& modelIndex); static int GetBinarySizeInKB(const QModelIndex& modelIndex); @@ -58,6 +61,7 @@ namespace O3DE::ProjectManager RoleName = Qt::UserRole, RoleUuid, RoleCreator, + RoleGemOrigin, RolePlatforms, RoleSummary, RoleIsAdded, @@ -72,7 +76,7 @@ namespace O3DE::ProjectManager RoleTypes }; - QHash m_uuidToNameMap; + QHash m_uuidToIndexMap; QItemSelectionModel* m_selectionModel = nullptr; }; } // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp new file mode 100644 index 0000000000..33936f417e --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.cpp @@ -0,0 +1,133 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#include +#include + +namespace O3DE::ProjectManager +{ + GemSortFilterProxyModel::GemSortFilterProxyModel(GemModel* sourceModel, QObject* parent) + : QSortFilterProxyModel(parent) + , m_sourceModel(sourceModel) + { + setSourceModel(sourceModel); + m_selectionProxyModel = new AzQtComponents::SelectionProxyModel(sourceModel->GetSelectionModel(), this, parent); + } + + bool GemSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const + { + // Do not use sourceParent->child because an invalid parent does not produce valid children (which our index function does) + QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent); + if (!sourceIndex.isValid()) + { + return false; + } + + if (!m_sourceModel->GetName(sourceIndex).contains(m_searchString, Qt::CaseInsensitive)) + { + return false; + } + + // Gem origins + if (m_gemOriginFilter) + { + bool supportsAnyFilteredGemOrigin = false; + for (int i = 0; i < GemInfo::NumGemOrigins; ++i) + { + const GemInfo::GemOrigin filteredGemOrigin = static_cast(1 << i); + if (m_gemOriginFilter & filteredGemOrigin) + { + if ((GemModel::GetGemOrigin(sourceIndex) == filteredGemOrigin)) + { + supportsAnyFilteredGemOrigin = true; + break; + } + } + } + if (!supportsAnyFilteredGemOrigin) + { + return false; + } + } + + // Platform + if (m_platformFilter) + { + bool supportsAnyFilteredPlatform = false; + for (int i = 0; i < GemInfo::NumPlatforms; ++i) + { + const GemInfo::Platform filteredPlatform = static_cast(1 << i); + if (m_platformFilter & filteredPlatform) + { + if ((GemModel::GetPlatforms(sourceIndex) & filteredPlatform)) + { + supportsAnyFilteredPlatform = true; + break; + } + } + } + if (!supportsAnyFilteredPlatform) + { + return false; + } + } + + // Types (Asset, Code, Tool) + if (m_typeFilter) + { + bool supportsAnyFilteredType = false; + for (int i = 0; i < GemInfo::NumTypes; ++i) + { + const GemInfo::Type filteredType = static_cast(1 << i); + if (m_typeFilter & filteredType) + { + if ((GemModel::GetTypes(sourceIndex) & filteredType)) + { + supportsAnyFilteredType = true; + break; + } + } + } + if (!supportsAnyFilteredType) + { + return false; + } + } + + // Features + if (!m_featureFilter.isEmpty()) + { + bool containsFilterFeature = false; + const QStringList features = m_sourceModel->GetFeatures(sourceIndex); + for (const QString& feature : features) + { + if (m_featureFilter.contains(feature)) + { + containsFilterFeature = true; + break; + } + } + if (!containsFilterFeature) + { + return false; + } + } + + return true; + } + + void GemSortFilterProxyModel::InvalidateFilter() + { + invalidate(); + emit OnInvalidated(); + } +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h new file mode 100644 index 0000000000..e5554c020c --- /dev/null +++ b/Code/Tools/ProjectManager/Source/GemCatalog/GemSortFilterProxyModel.h @@ -0,0 +1,68 @@ +/* +* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or +* its licensors. +* +* For complete copyright and license terms please see the LICENSE at the root of this +* distribution (the "License"). All use of this software is governed by the License, +* or, if provided, by the license below or the license accompanying this file. Do not +* remove or modify any license notices. This file is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* +*/ + +#pragma once + +#if !defined(Q_MOC_RUN) +#include +#include +#include +#include +#endif + +QT_FORWARD_DECLARE_CLASS(QItemSelectionModel) + +namespace O3DE::ProjectManager +{ + class GemSortFilterProxyModel + : public QSortFilterProxyModel + { + Q_OBJECT // AUTOMOC + + public: + GemSortFilterProxyModel(GemModel* sourceModel, QObject* parent = nullptr); + + bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override; + + GemModel* GetSourceModel() const { return m_sourceModel; } + AzQtComponents::SelectionProxyModel* GetSelectionModel() const { return m_selectionProxyModel; } + + void SetSearchString(const QString& searchString) { m_searchString = searchString; InvalidateFilter(); } + + GemInfo::GemOrigins GetGemOrigins() const { return m_gemOriginFilter; } + void SetGemOrigins(const GemInfo::GemOrigins& gemOrigins) { m_gemOriginFilter = gemOrigins; InvalidateFilter(); } + + GemInfo::Platforms GetPlatforms() const { return m_platformFilter; } + void SetPlatforms(const GemInfo::Platforms& platforms) { m_platformFilter = platforms; InvalidateFilter(); } + + GemInfo::Types GetTypes() const { return m_typeFilter; } + void SetTypes(const GemInfo::Types& types) { m_typeFilter = types; InvalidateFilter(); } + + const QSet& GetFeatures() const { return m_featureFilter; } + void SetFeatures(const QSet& features) { m_featureFilter = features; InvalidateFilter(); } + + void InvalidateFilter(); + + signals: + void OnInvalidated(); + + private: + GemModel* m_sourceModel = nullptr; + AzQtComponents::SelectionProxyModel* m_selectionProxyModel = nullptr; + + QString m_searchString; + GemInfo::GemOrigins m_gemOriginFilter = {}; + GemInfo::Platforms m_platformFilter = {}; + GemInfo::Types m_typeFilter = {}; + QSet m_featureFilter; + }; +} // namespace O3DE::ProjectManager diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp index 121add657f..4136b9eb8c 100644 --- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp +++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.cpp @@ -32,8 +32,6 @@ namespace O3DE::ProjectManager layout->setSpacing(0); layout->setContentsMargins(0, 0, 0, 0); - setFixedSize(this->geometry().width(), this->geometry().height()); - m_pythonBindings = AZStd::make_unique(engineRootPath); m_screensCtrl = new ScreensCtrl(); diff --git a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui index 4e33511bff..633cd61182 100644 --- a/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui +++ b/Code/Tools/ProjectManager/Source/ProjectManagerWindow.ui @@ -11,7 +11,7 @@ - + 0 0 diff --git a/Code/Tools/ProjectManager/project_manager_files.cmake b/Code/Tools/ProjectManager/project_manager_files.cmake index 858fb972aa..16bc8cf965 100644 --- a/Code/Tools/ProjectManager/project_manager_files.cmake +++ b/Code/Tools/ProjectManager/project_manager_files.cmake @@ -57,6 +57,8 @@ set(FILES Source/TagWidget.cpp Source/GemCatalog/GemCatalogScreen.h Source/GemCatalog/GemCatalogScreen.cpp + Source/GemCatalog/GemFilterWidget.h + Source/GemCatalog/GemFilterWidget.cpp Source/GemCatalog/GemInfo.h Source/GemCatalog/GemInfo.cpp Source/GemCatalog/GemInspector.h @@ -67,4 +69,6 @@ set(FILES Source/GemCatalog/GemListView.cpp Source/GemCatalog/GemModel.h Source/GemCatalog/GemModel.cpp + Source/GemCatalog/GemSortFilterProxyModel.h + Source/GemCatalog/GemSortFilterProxyModel.cpp ) diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/DllMain.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/DllMain.cpp index 6fd664eee4..3dc14814de 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/DllMain.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/DllMain.cpp @@ -41,6 +41,18 @@ namespace AZ static AZ::SceneAPI::FbxSceneImporter::FbxImportRequestHandler* g_fbxImporter = nullptr; static AZStd::vector g_componentDescriptors; + void Initialize() + { + // Currently it's still needed to explicitly create an instance of this instead of letting + // it be a normal component. This is because ResourceCompilerScene needs to return + // the list of available extensions before it can start the application. + if (!g_fbxImporter) + { + g_fbxImporter = aznew AZ::SceneAPI::FbxSceneImporter::FbxImportRequestHandler(); + g_fbxImporter->Activate(); + } + } + void Reflect(AZ::SerializeContext* /*context*/) { // Descriptor registration is done in Reflect instead of Initialize because the ResourceCompilerScene initializes the libraries before @@ -52,7 +64,6 @@ namespace AZ { // Global importer and behavior g_componentDescriptors.push_back(FbxSceneBuilder::FbxImporter::CreateDescriptor()); - g_componentDescriptors.push_back(FbxSceneImporter::FbxImportRequestHandler::CreateDescriptor()); // Node and attribute importers g_componentDescriptors.push_back(AssImpBitangentStreamImporter::CreateDescriptor()); @@ -114,11 +125,7 @@ namespace AZ extern "C" AZ_DLL_EXPORT void InitializeDynamicModule(void* env) { AZ::Environment::Attach(static_cast(env)); - if (!AZ::SceneAPI::FbxSceneBuilder::g_fbxImporter) - { - AZ::SceneAPI::FbxSceneBuilder::g_fbxImporter = aznew AZ::SceneAPI::FbxSceneImporter::FbxImportRequestHandler(); - AZ::SceneAPI::FbxSceneBuilder::g_fbxImporter->Activate(); - } + AZ::SceneAPI::FbxSceneBuilder::Initialize(); } extern "C" AZ_DLL_EXPORT void Reflect(AZ::SerializeContext* context) { diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp index ebdb57e452..155209f1b5 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.cpp @@ -10,16 +10,12 @@ * */ -#include -#include #include -#include -#include -#include -#include +#include #include #include #include +#include namespace AZ { @@ -27,23 +23,10 @@ namespace AZ { namespace FbxSceneImporter { - void SceneImporterSettings::Reflect(AZ::ReflectContext* context) - { - if (auto serializeContext = azrtti_cast(context); serializeContext) - { - serializeContext->Class() - ->Version(1) - ->Field("SupportedFileTypeExtensions", &SceneImporterSettings::m_supportedFileTypeExtensions); - } - } + const char* FbxImportRequestHandler::s_extension = ".fbx"; void FbxImportRequestHandler::Activate() { - if (auto* settingsRegistry = AZ::SettingsRegistry::Get()) - { - settingsRegistry->GetObject(m_settings, "/O3DE/SceneAPI/AssetImporter"); - } - BusConnect(); } @@ -54,38 +37,21 @@ namespace AZ void FbxImportRequestHandler::Reflect(ReflectContext* context) { - SceneImporterSettings::Reflect(context); - SerializeContext* serializeContext = azrtti_cast(context); if (serializeContext) { - serializeContext->Class()->Version(1)->Attribute( - AZ::Edit::Attributes::SystemComponentTags, - AZStd::vector({AssetBuilderSDK::ComponentTags::AssetBuilder})); - + serializeContext->Class()->Version(1); } } void FbxImportRequestHandler::GetSupportedFileExtensions(AZStd::unordered_set& extensions) { - // It's unlikely an empty file extension list is intentional, - // so if it's empty, try reloading it from the registry. - if (m_settings.m_supportedFileTypeExtensions.empty()) - { - if (auto* settingsRegistry = AZ::SettingsRegistry::Get()) - { - settingsRegistry->GetObject(m_settings, "/O3DE/SceneAPI/AssetImporter"); - } - } - extensions.insert(m_settings.m_supportedFileTypeExtensions.begin(), m_settings.m_supportedFileTypeExtensions.end()); + extensions.insert(s_extension); } Events::LoadingResult FbxImportRequestHandler::LoadAsset(Containers::Scene& scene, const AZStd::string& path, const Uuid& guid, [[maybe_unused]] RequestingApplication requester) { - AZStd::string extension; - StringFunc::Path::GetExtension(path.c_str(), extension); - - if (!m_settings.m_supportedFileTypeExtensions.contains(extension)) + if (!AzFramework::StringFunc::Path::IsExtension(path.c_str(), s_extension)) { return Events::LoadingResult::Ignored; } @@ -107,11 +73,6 @@ namespace AZ return Events::LoadingResult::AssetFailure; } } - - void FbxImportRequestHandler::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided) - { - provided.emplace_back(AZ_CRC_CE("AssetImportRequestHandler")); - } } // namespace Import } // namespace SceneAPI } // namespace AZ diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h b/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h index 12c7c6f877..8b33051f1e 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h @@ -21,21 +21,12 @@ namespace AZ { namespace FbxSceneImporter { - struct SceneImporterSettings - { - AZ_TYPE_INFO(SceneImporterSettings, "{8BB6C7AD-BF99-44DC-9DA1-E7AD3F03DC10}"); - - static void Reflect(AZ::ReflectContext* context); - - AZStd::unordered_set m_supportedFileTypeExtensions; - }; - class FbxImportRequestHandler - : public AZ::Component + : public SceneCore::BehaviorComponent , public Events::AssetImportRequestBus::Handler { public: - AZ_COMPONENT(FbxImportRequestHandler, "{9F4B189C-0A96-4F44-A5F0-E087FF1561F8}"); + AZ_COMPONENT(FbxImportRequestHandler, "{9F4B189C-0A96-4F44-A5F0-E087FF1561F8}", SceneCore::BehaviorComponent); ~FbxImportRequestHandler() override = default; @@ -47,13 +38,8 @@ namespace AZ Events::LoadingResult LoadAsset(Containers::Scene& scene, const AZStd::string& path, const Uuid& guid, RequestingApplication requester) override; - static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided); - private: - - SceneImporterSettings m_settings; - - static constexpr const char* SettingsFilename = "AssetImporterSettings.json"; + static const char* s_extension; }; } // namespace FbxSceneImporter } // namespace SceneAPI diff --git a/Code/Sandbox/Editor/ModernViewportCameraController.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h similarity index 87% rename from Code/Sandbox/Editor/ModernViewportCameraController.h rename to Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h index 39e3c9cbb3..1318deb355 100644 --- a/Code/Sandbox/Editor/ModernViewportCameraController.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h @@ -12,17 +12,16 @@ #pragma once -#include - #include +#include #include #include #include -namespace SandboxEditor +namespace AtomToolsFramework { class ModernViewportCameraControllerInstance; - class ModernViewportCameraController + class ModularViewportCameraController : public AzFramework::MultiViewportController< ModernViewportCameraControllerInstance, AzFramework::ViewportControllerPriority::DispatchToAllPriorities> { @@ -39,19 +38,19 @@ namespace SandboxEditor }; class ModernViewportCameraControllerInstance final - : public AzFramework::MultiViewportControllerInstanceInterface, - public ModernViewportCameraControllerRequestBus::Handler, + : public AzFramework::MultiViewportControllerInstanceInterface, + public ModularViewportCameraControllerRequestBus::Handler, private AzFramework::ViewportDebugDisplayEventBus::Handler { public: - explicit ModernViewportCameraControllerInstance(AzFramework::ViewportId viewportId, ModernViewportCameraController* controller); + explicit ModernViewportCameraControllerInstance(AzFramework::ViewportId viewportId, ModularViewportCameraController* controller); ~ModernViewportCameraControllerInstance() override; // MultiViewportControllerInstanceInterface overrides ... bool HandleInputChannelEvent(const AzFramework::ViewportControllerInputEvent& event) override; void UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) override; - // ModernViewportCameraControllerRequestBus overrides ... + // ModularViewportCameraControllerRequestBus overrides ... void InterpolateToTransform(const AZ::Transform& worldFromLocal) override; private: @@ -76,4 +75,4 @@ namespace SandboxEditor AZ::RPI::ViewportContext::MatrixChangedEvent::Handler m_cameraViewMatrixChangeHandler; }; -} // namespace SandboxEditor +} // namespace AtomToolsFramework diff --git a/Code/Sandbox/Editor/ModernViewportCameraControllerRequestBus.h b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h similarity index 78% rename from Code/Sandbox/Editor/ModernViewportCameraControllerRequestBus.h rename to Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h index 966facc8e9..5b90119372 100644 --- a/Code/Sandbox/Editor/ModernViewportCameraControllerRequestBus.h +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h @@ -20,11 +20,11 @@ namespace AZ class Transform; } -namespace SandboxEditor +namespace AtomToolsFramework { //! Provides an interface to control the modern viewport camera controller from the Editor. //! @note The bus is addressed by viewport id. - class ModernViewportCameraControllerRequests : public AZ::EBusTraits + class ModularViewportCameraControllerRequests : public AZ::EBusTraits { public: using BusIdType = AzFramework::ViewportId; @@ -35,8 +35,8 @@ namespace SandboxEditor virtual void InterpolateToTransform(const AZ::Transform& worldFromLocal) = 0; protected: - ~ModernViewportCameraControllerRequests() = default; + ~ModularViewportCameraControllerRequests() = default; }; - using ModernViewportCameraControllerRequestBus = AZ::EBus; -} // namespace SandboxEditor + using ModularViewportCameraControllerRequestBus = AZ::EBus; +} // namespace AtomToolsFramework diff --git a/Code/Sandbox/Editor/ModernViewportCameraController.cpp b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp similarity index 91% rename from Code/Sandbox/Editor/ModernViewportCameraController.cpp rename to Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp index 0779542878..6fb3edfa22 100644 --- a/Code/Sandbox/Editor/ModernViewportCameraController.cpp +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/Source/Viewport/ModularViewportCameraController.cpp @@ -10,10 +10,9 @@ * */ -#include "ModernViewportCameraController.h" - #include #include +#include #include #include #include @@ -23,7 +22,7 @@ #include #include -namespace SandboxEditor +namespace AtomToolsFramework { // debug void DrawPreviewAxis(AzFramework::DebugDisplayRequests& display, const AZ::Transform& transform, const float axisLength) @@ -53,12 +52,12 @@ namespace SandboxEditor return viewportContext; } - void ModernViewportCameraController::SetCameraListBuilderCallback(const CameraListBuilder& builder) + void ModularViewportCameraController::SetCameraListBuilderCallback(const CameraListBuilder& builder) { m_cameraListBuilder = builder; } - void ModernViewportCameraController::SetupCameras(AzFramework::Cameras& cameras) + void ModularViewportCameraController::SetupCameras(AzFramework::Cameras& cameras) { if (m_cameraListBuilder) { @@ -67,8 +66,8 @@ namespace SandboxEditor } ModernViewportCameraControllerInstance::ModernViewportCameraControllerInstance( - const AzFramework::ViewportId viewportId, ModernViewportCameraController* controller) - : MultiViewportControllerInstanceInterface(viewportId, controller) + const AzFramework::ViewportId viewportId, ModularViewportCameraController* controller) + : MultiViewportControllerInstanceInterface(viewportId, controller) { controller->SetupCameras(m_cameraSystem.m_cameras); @@ -88,12 +87,12 @@ namespace SandboxEditor } AzFramework::ViewportDebugDisplayEventBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId()); - ModernViewportCameraControllerRequestBus::Handler::BusConnect(viewportId); + ModularViewportCameraControllerRequestBus::Handler::BusConnect(viewportId); } ModernViewportCameraControllerInstance::~ModernViewportCameraControllerInstance() { - ModernViewportCameraControllerRequestBus::Handler::BusDisconnect(); + ModularViewportCameraControllerRequestBus::Handler::BusDisconnect(); AzFramework::ViewportDebugDisplayEventBus::Handler::BusDisconnect(); } @@ -182,4 +181,4 @@ namespace SandboxEditor m_transformStart = m_camera.Transform(); m_transformEnd = worldFromLocal; } -} // namespace SandboxEditor +} // namespace AtomToolsFramework diff --git a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake index d8ceccc724..f28ba89b92 100644 --- a/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake +++ b/Gems/Atom/Tools/AtomToolsFramework/Code/atomtoolsframework_files.cmake @@ -24,6 +24,8 @@ set(FILES Include/AtomToolsFramework/Util/MaterialPropertyUtil.h Include/AtomToolsFramework/Util/Util.h Include/AtomToolsFramework/Viewport/RenderViewportWidget.h + Include/AtomToolsFramework/Viewport/ModularViewportCameraController.h + Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h Source/Communication/LocalServer.cpp Source/Communication/LocalSocket.cpp Source/Debug/TraceRecorder.cpp @@ -38,4 +40,5 @@ set(FILES Source/Util/MaterialPropertyUtil.cpp Source/Util/Util.cpp Source/Viewport/RenderViewportWidget.cpp + Source/Viewport/ModularViewportCameraController.cpp ) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/InputController/MaterialEditorViewportInputControllerBus.h b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/InputController/MaterialEditorViewportInputControllerBus.h index 2acdc79286..837762b49c 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/InputController/MaterialEditorViewportInputControllerBus.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Include/Atom/Viewport/InputController/MaterialEditorViewportInputControllerBus.h @@ -47,6 +47,9 @@ namespace MaterialEditor //! @param distanceMax furthest camera can be from the target virtual void GetExtents(float& distanceMin, float& distanceMax) const = 0; + //! Get bounding sphere radius of the active model + virtual float GetRadius() const = 0; + //! Reset camera to default position and rotation virtual void Reset() = 0; diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/Behavior.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/Behavior.cpp index 159d3339be..877a3affb1 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/Behavior.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/Behavior.cpp @@ -44,6 +44,8 @@ namespace MaterialEditor MaterialEditorViewportInputControllerRequestBus::BroadcastResult( m_targetPosition, &MaterialEditorViewportInputControllerRequestBus::Handler::GetTargetPosition); + MaterialEditorViewportInputControllerRequestBus::BroadcastResult( + m_radius, &MaterialEditorViewportInputControllerRequestBus::Handler::GetRadius); } void Behavior::End() @@ -119,7 +121,8 @@ namespace MaterialEditor float Behavior::GetSensitivityZ() { - return 0.001f; + // adjust zooming sensitivity by model size, so that large models zoom at the same speed as smaller ones + return 0.001f * AZ::GetMax(0.5f, m_radius); } AZ::Quaternion Behavior::LookRotation(AZ::Vector3 forward) diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/Behavior.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/Behavior.h index 7c32ed33a0..205301c90e 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/Behavior.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/Behavior.h @@ -54,6 +54,8 @@ namespace MaterialEditor float m_y = 0; //! delta scroll wheel accumulated during current frame float m_z = 0; + //! Model radius + float m_radius = 1.0f; AZ::EntityId m_cameraEntityId; AZ::Vector3 m_targetPosition = AZ::Vector3::CreateZero(); diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp index 36e4b76cec..420e2732d0 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.cpp @@ -114,6 +114,11 @@ namespace MaterialEditor distanceMax = m_distanceMax; } + float MaterialEditorViewportInputController::GetRadius() const + { + return m_radius; + } + void MaterialEditorViewportInputController::UpdateViewport(const AzFramework::ViewportControllerUpdateEvent& event) { if (m_keysChanged) @@ -306,11 +311,10 @@ namespace MaterialEditor if (modelAsset.IsReady()) { const AZ::Aabb& aabb = modelAsset->GetAabb(); - float radius; - aabb.GetAsSphere(m_modelCenter, radius); + aabb.GetAsSphere(m_modelCenter, m_radius); m_distanceMin = 0.5f * AZ::GetMin(AZ::GetMin(aabb.GetExtents().GetX(), aabb.GetExtents().GetY()), aabb.GetExtents().GetZ()) + DepthNear; - m_distanceMax = radius * MaxDistanceMultiplier; + m_distanceMax = m_radius * MaxDistanceMultiplier; } } } diff --git a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.h b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.h index ee40b5c259..7308ce4ea1 100644 --- a/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.h +++ b/Gems/Atom/Tools/MaterialEditor/Code/Source/Viewport/InputController/MaterialEditorViewportInputController.h @@ -43,6 +43,7 @@ namespace MaterialEditor void SetTargetPosition(const AZ::Vector3& targetPosition) override; float GetDistanceToTarget() const override; void GetExtents(float& distanceMin, float& distanceMax) const override; + float GetRadius() const override; void Reset() override; void SetFieldOfView(float value) override; bool IsCameraCentered() const override; @@ -96,6 +97,8 @@ namespace MaterialEditor float m_distanceMin = 1.0f; //! Maximum distance from camera to target float m_distanceMax = 10.0f; + //! Model radius + float m_radius = 1.0f; //! True if camera is centered on a model bool m_isCameraCentered = true; diff --git a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.cpp b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.cpp index 25faca3667..e71a5207d0 100644 --- a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.cpp +++ b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.cpp @@ -72,11 +72,6 @@ namespace SceneBuilder m_sceneBuilder.BusDisconnect(); } - void BuilderPluginComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required) - { - required.emplace_back(AZ_CRC_CE("AssetImportRequestHandler")); - } - void BuilderPluginComponent::Reflect(AZ::ReflectContext* context) { AZ::SerializeContext* serializeContext = azrtti_cast(context); @@ -86,4 +81,5 @@ namespace SceneBuilder ->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector({ AssetBuilderSDK::ComponentTags::AssetBuilder })); } } + } // namespace SceneBuilder diff --git a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.h b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.h index aed5e1b026..c1fc6ebb36 100644 --- a/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.h +++ b/Gems/SceneProcessing/Code/Source/SceneBuilder/SceneBuilderComponent.h @@ -32,8 +32,6 @@ namespace SceneBuilder void Activate() override; void Deactivate() override; - static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required); - private: SceneBuilderWorker m_sceneBuilder; }; diff --git a/Registry/sceneassetimporter.setreg b/Registry/sceneassetimporter.setreg deleted file mode 100644 index bd7c4d0705..0000000000 --- a/Registry/sceneassetimporter.setreg +++ /dev/null @@ -1,16 +0,0 @@ -{ - "O3DE": - { - "SceneAPI": - { - "AssetImporter": - { - "SupportedFileTypeExtensions": - [ - ".fbx", - ".stl" - ] - } - } - } -} \ No newline at end of file diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index ba610b1883..fbeffa94eb 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -29,15 +29,15 @@ string(TOLOWER ${PROJECT_NAME} _project_name_lower) set(CPACK_PACKAGE_FILE_NAME "${_project_name_lower}_${LY_VERSION_STRING}_installer") set(DEFAULT_LICENSE_NAME "Apache-2.0") -set(DEFAULT_LICENSE_FILE "${CMAKE_SOURCE_DIR}/LICENSE.txt") +set(DEFAULT_LICENSE_FILE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt") set(CPACK_RESOURCE_FILE_LICENSE ${DEFAULT_LICENSE_FILE}) set(CPACK_LICENSE_URL ${LY_INSTALLER_LICENSE_URL}) set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_VENDOR}/${CPACK_PACKAGE_VERSION}") -# CMAKE_SOURCE_DIR doesn't equate to anything during execution of pre/post build scripts -set(CPACK_SOURCE_DIR ${CMAKE_SOURCE_DIR}/cmake) +# neither of the SOURCE_DIR variables equate to anything during execution of pre/post build scripts +set(CPACK_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # attempt to apply platform specific settings ly_get_absolute_pal_filename(pal_dir ${CPACK_SOURCE_DIR}/Platform/${PAL_HOST_PLATFORM_NAME})