{lyn8578} adding UX for assinging a Python scene builder (#7551)

* {lyn8578} adding UX for assinging a Python scene builder

Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com>

* improved the Reset and Assign script logic

Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com>

* GUI updates to highlight the scene script


Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com>

* save off the script file name instead of holding onto the rule
update the header display name separate from setting the scene

Signed-off-by: Allen Jackson <23512001+jackalbe@users.noreply.github.com>
monroegm-disable-blank-issue-2
Allen Jackson 4 years ago committed by GitHub
parent 7fbcab9f13
commit de97ad6ade
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -44,6 +44,9 @@ class CXTPDockingPaneLayout; // Needed for settings.h
#include <SceneAPI/SceneUI/SceneWidgets/SceneGraphInspectWidget.h>
#include <SceneAPI/SceneCore/Events/AssetImportRequest.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/Rules/ScriptProcessorRule.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IScriptProcessorRule.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
const char* AssetImporterWindow::s_documentationWebAddress = "http://docs.aws.amazon.com/lumberyard/latest/userguide/char-fbx-importer.html";
const AZ::Uuid AssetImporterWindow::s_browseTag = AZ::Uuid::CreateString("{C240D2E1-BFD2-4FFA-BB5B-CC0FA389A5D3}");
@ -198,7 +201,7 @@ void AssetImporterWindow::Init()
// Filling the initial browse prompt text to be programmatically set from available extensions
AZStd::unordered_set<AZStd::string> extensions;
EBUS_EVENT(AZ::SceneAPI::Events::AssetImportRequestBus, GetSupportedFileExtensions, extensions);
AZ_Assert(!extensions.empty(), "No file extensions defined for assets.");
AZ_Error(AZ::SceneAPI::Utilities::ErrorWindow, !extensions.empty(), "No file extensions defined for assets.");
if (!extensions.empty())
{
for (AZStd::string& extension : extensions)
@ -252,6 +255,7 @@ void AssetImporterWindow::OpenFileInternal(const AZStd::string& filePath)
[this, filePath]()
{
m_assetImporterDocument->LoadScene(filePath);
UpdateSceneDisplay({});
},
[this]()
{
@ -290,6 +294,11 @@ void AssetImporterWindow::UpdateClicked()
AZ_Assert(!m_processingOverlay, "Attempted to update asset while processing is in progress.");
return;
}
else if (!m_scriptProcessorRuleFilename.empty())
{
AZ_TracePrintf(AZ::SceneAPI::Utilities::WarningWindow, "A script updates the manifest; will not save.");
return;
}
m_processingOverlay.reset(new ProcessingOverlayWidget(m_overlay.data(), ProcessingOverlayWidget::Layout::Exporting, s_browseTag));
connect(m_processingOverlay.data(), &ProcessingOverlayWidget::Closing, this, &AssetImporterWindow::ClearProcessingOverlay);
@ -383,6 +392,18 @@ void AssetImporterWindow::OnSceneResetRequested()
m_rootDisplay->HandleSceneWasReset(m_assetImporterDocument->GetScene());
}, this);
// reset the script rule from the .assetinfo file if it exists
if (!m_scriptProcessorRuleFilename.empty())
{
m_scriptProcessorRuleFilename.clear();
if (QFile::exists(m_assetImporterDocument->GetScene()->GetManifestFilename().c_str()))
{
QFile file(m_assetImporterDocument->GetScene()->GetManifestFilename().c_str());
file.remove();
}
}
UpdateSceneDisplay({});
m_processingOverlay.reset(new ProcessingOverlayWidget(m_overlay.data(), ProcessingOverlayWidget::Layout::Resetting, s_browseTag));
m_processingOverlay->SetAndStartProcessingHandler(asyncLoadHandler);
m_processingOverlay->SetAutoCloseOnSuccess(true);
@ -390,6 +411,51 @@ void AssetImporterWindow::OnSceneResetRequested()
m_processingOverlayIndex = m_processingOverlay->PushToOverlay();
}
void AssetImporterWindow::OnAssignScript()
{
using namespace AZ::SceneAPI;
using namespace AZ::SceneAPI::Events;
using namespace AZ::SceneAPI::SceneUI;
using namespace AZ::SceneAPI::Utilities;
// use QFileDialog to select a Python script to embed into a scene manifest file
QString pyFilename = QFileDialog::getOpenFileName(this,
tr("Select scene builder Python script"),
Path::GetEditingGameDataFolder().c_str(),
tr("Python (*.py)"));
if (pyFilename.isNull())
{
return;
}
// reset the script rule from the .assetinfo file if it exists
if (!m_scriptProcessorRuleFilename.empty())
{
m_scriptProcessorRuleFilename.clear();
if (QFile::exists(m_assetImporterDocument->GetScene()->GetManifestFilename().c_str()))
{
QFile file(m_assetImporterDocument->GetScene()->GetManifestFilename().c_str());
file.remove();
}
}
// find the path relative to the project folder
pyFilename = Path::GetRelativePath(pyFilename, true);
// create a script rule
auto scriptProcessorRule = AZStd::make_shared<SceneData::ScriptProcessorRule>();
scriptProcessorRule->SetScriptFilename(pyFilename.toUtf8().toStdString().c_str());
// add the script rule to the manifest & save off the scene manifest
Containers::SceneManifest sceneManifest;
sceneManifest.AddEntry(scriptProcessorRule);
if (sceneManifest.SaveToFile(m_assetImporterDocument->GetScene()->GetManifestFilename()))
{
OpenFile(m_assetImporterDocument->GetScene()->GetSourceFilename());
}
}
void AssetImporterWindow::ResetMenuAccess(WindowState state)
{
if (state == WindowState::FileLoaded)
@ -480,7 +546,7 @@ void AssetImporterWindow::SetTitle(const char* filePath)
}
AZStd::string fileName;
AzFramework::StringFunc::Path::GetFileName(filePath, fileName);
converted->setWindowTitle(QString("%1 Settings (PREVIEW) - %2").arg(extension.c_str(), fileName.c_str()));
converted->setWindowTitle(QString("%1 Settings - %2").arg(extension.c_str(), fileName.c_str()));
break;
}
else
@ -490,6 +556,28 @@ void AssetImporterWindow::SetTitle(const char* filePath)
}
}
void AssetImporterWindow::UpdateSceneDisplay(const AZStd::shared_ptr<AZ::SceneAPI::Containers::Scene> scene) const
{
AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
AZ::IO::FixedMaxPath relativeSourcePath = AZ::IO::PathView(m_fullSourcePath).LexicallyProximate(projectPath);
auto sceneHeaderText = QString::fromUtf8(relativeSourcePath.c_str(), static_cast<int>(relativeSourcePath.Native().size()));
if (!m_scriptProcessorRuleFilename.empty())
{
sceneHeaderText.append("\n Assigned Python builder script (")
.append(m_scriptProcessorRuleFilename.c_str())
.append(")");
}
if (scene)
{
m_rootDisplay->SetSceneDisplay(sceneHeaderText, scene);
}
else
{
m_rootDisplay->SetSceneHeaderText(sceneHeaderText);
}
}
void AssetImporterWindow::HandleAssetLoadingCompleted()
{
if (!m_assetImporterDocument->GetScene())
@ -501,10 +589,24 @@ void AssetImporterWindow::HandleAssetLoadingCompleted()
m_fullSourcePath = m_assetImporterDocument->GetScene()->GetSourceFilename();
SetTitle(m_fullSourcePath.c_str());
AZ::IO::FixedMaxPath projectPath = AZ::Utils::GetProjectPath();
AZ::IO::FixedMaxPath relativeSourcePath = AZ::IO::PathView(m_fullSourcePath).LexicallyProximate(projectPath);
auto userFriendlyFileName = QString::fromUtf8(relativeSourcePath.c_str(), static_cast<int>(relativeSourcePath.Native().size()));
m_rootDisplay->SetSceneDisplay(userFriendlyFileName, m_assetImporterDocument->GetScene());
using namespace AZ::SceneAPI;
m_scriptProcessorRuleFilename.clear();
// load up the source scene manifest file
Containers::SceneManifest sceneManifest;
if (sceneManifest.LoadFromFile(m_assetImporterDocument->GetScene()->GetManifestFilename()))
{
// check a Python script rule is in that source manifest
auto view = Containers::MakeDerivedFilterView<DataTypes::IScriptProcessorRule>(sceneManifest.GetValueStorage());
if (!view.empty())
{
// record the info about the rule in the class
const auto scriptProcessorRule = &*view.begin();
m_scriptProcessorRuleFilename = scriptProcessorRule->GetScriptFilename();
}
}
UpdateSceneDisplay(m_assetImporterDocument->GetScene());
// Once we've browsed to something successfully, we need to hide the initial browse button layer and
// show the main area where all the actual work takes place

@ -47,6 +47,10 @@ namespace AZ
{
class ProcessingOverlayWidget;
}
namespace DataTypes
{
class IScriptProcessorRule;
}
}
}
@ -80,6 +84,7 @@ public:
public slots:
void OnSceneResetRequested();
void OnAssignScript();
void OnOpenDocumentation();
void OnInspect();
@ -105,6 +110,7 @@ private slots:
void OverlayLayerAdded();
void OverlayLayerRemoved();
void UpdateSceneDisplay(const AZStd::shared_ptr<AZ::SceneAPI::Containers::Scene> scene = {}) const;
private:
static const AZ::Uuid s_browseTag;
@ -122,4 +128,6 @@ private:
int m_processingOverlayIndex;
QSharedPointer<AZ::SceneAPI::SceneUI::ProcessingOverlayWidget> m_processingOverlay;
AZStd::string m_scriptProcessorRuleFilename;
};

@ -25,7 +25,8 @@
<string>&amp;Edit</string>
</property>
<addaction name="m_actionResetSettings"/>
</widget>
<addaction name="m_actionAssignScript"/>
</widget>
<widget class="QMenu" name="helpMenu">
<property name="title">
<string>&amp;Help</string>
@ -49,7 +50,7 @@
<enum>QLayout::SetMaximumSize</enum>
</property>
<!-- When an fbx is loaded -->
<!-- When a source scene file (i.e. FBX) is loaded -->
<item>
<widget class="QWidget" name="m_mainArea">
<property name="sizePolicy">
@ -175,7 +176,16 @@
<string>Reset the settings for this file (note: you will have to update to commit)</string>
</property>
</action>
<action name="m_actionAssignScript">
<property name="text">
<string>Assign Build Script...</string>
</property>
<property name="toolTip">
<string>Assign a Python build script that will override the scene's build rules</string>
</property>
</action>
<action name="actionOpenDocumentation">
<property name="text">
<string>Documentation</string>
@ -204,6 +214,12 @@
<receiver>AssetImporterWindow</receiver>
<slot>OnSceneResetRequested()</slot>
</connection>
<connection>
<sender>m_actionAssignScript</sender>
<signal>triggered()</signal>
<receiver>AssetImporterWindow</receiver>
<slot>OnAssignScript()</slot>
</connection>
<connection>
<sender>m_actionInspect</sender>
<signal>triggered()</signal>

@ -44,6 +44,11 @@ AZ::SceneAPI::UI::ManifestWidget* ImporterRootDisplay::GetManifestWidget()
return m_manifestWidget.data();
}
void ImporterRootDisplay::SetSceneHeaderText(const QString& headerText)
{
ui->m_filePathText->setText(headerText);
}
void ImporterRootDisplay::SetSceneDisplay(const QString& headerText, const AZStd::shared_ptr<AZ::SceneAPI::Containers::Scene>& scene)
{
AZ_PROFILE_FUNCTION(Editor);
@ -53,7 +58,7 @@ void ImporterRootDisplay::SetSceneDisplay(const QString& headerText, const AZStd
return;
}
ui->m_filePathText->setText(headerText);
SetSceneHeaderText(headerText);
HandleSceneWasReset(scene);

@ -63,6 +63,7 @@ public:
AZ::SceneAPI::UI::ManifestWidget* GetManifestWidget();
void SetSceneDisplay(const QString& headerText, const AZStd::shared_ptr<AZ::SceneAPI::Containers::Scene>& scene);
void SetSceneHeaderText(const QString& headerText);
void HandleSceneWasReset(const AZStd::shared_ptr<AZ::SceneAPI::Containers::Scene>& scene);
void HandleSaveWasSuccessful();
bool HasUnsavedChanges() const;

@ -40,7 +40,7 @@
</size>
</property>
<property name="styleSheet">
<string notr="true">#m_filePathText { margin: 2px; color: grey; }</string>
<string notr="true">#m_filePathText { margin: 2px; color: white; }</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>

@ -21,16 +21,6 @@ namespace AZ
{
namespace SceneData
{
const AZStd::string& ScriptProcessorRule::GetScriptFilename() const
{
return m_scriptFilename;
}
DataTypes::ScriptProcessorFallbackLogic ScriptProcessorRule::GetScriptProcessorFallbackLogic() const
{
return m_fallbackLogic;
}
void ScriptProcessorRule::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);

@ -28,14 +28,20 @@ namespace AZ
~ScriptProcessorRule() override = default;
const AZStd::string& GetScriptFilename() const override;
inline const AZStd::string& GetScriptFilename() const override
{
return m_scriptFilename;
}
inline void SetScriptFilename(AZStd::string scriptFilename)
{
m_scriptFilename = AZStd::move(scriptFilename);
}
DataTypes::ScriptProcessorFallbackLogic GetScriptProcessorFallbackLogic() const override;
inline DataTypes::ScriptProcessorFallbackLogic GetScriptProcessorFallbackLogic() const override
{
return m_fallbackLogic;
}
static void Reflect(ReflectContext* context);

Loading…
Cancel
Save