Atom Tools: updated document and windows systems and buses to support multiple instances

• This change is partially to unblock physics tool prototyping. It introduces a tool ID that is passed down into systems and acts as a context for document, window, and other systems and buses.
• The document system component is no longer a component. It is just a system class that can be constructed with a tool ID. Internally, it will connect to its buses and be addressable by tool ID. More than one can be instantiated, each with a unique tool ID.
• These changes are still backward compatible because most of the buses were using broadcast for standalone applications. All of those calls have been updated but not all of the scripts, which should still work as is.
• Got rid of the window factory request bus in favor of just instantiating the main window or any other UI in the application layer.
• Fixed a couple of bugs that were discovered while making these changes.

Signed-off-by: Guthrie Adams <guthadam@amazon.com>
monroegm-disable-blank-issue-2
Guthrie Adams 4 years ago
parent 257f3cb1ce
commit c6ba1ef064

@ -162,11 +162,11 @@ def select_model_config(configname):
azlmbr.materialeditor.MaterialViewportRequestBus(azlmbr.bus.Broadcast, "SelectModelPresetByName", configname)
def destroy_main_window():
def exit():
"""
Closes the Material Editor window
Closes the Material Editor
"""
azlmbr.atomtools.AtomToolsMainWindowFactoryRequestBus(azlmbr.bus.Broadcast, "DestroyMainWindow")
azlmbr.atomtools.general.exit()
def wait_for_condition(function, timeout_in_seconds=1.0):

@ -214,7 +214,7 @@ def run():
(not material_editor.is_open(document1_id)) and
(not material_editor.is_open(document2_id)) and
(not material_editor.is_open(document3_id)), 2.0)
material_editor.destroy_main_window()
material_editor.exit()
if __name__ == "__main__":

@ -39,16 +39,16 @@ namespace AtomToolsFramework
{
public:
AZ_TYPE_INFO(AtomTools::AtomToolsApplication, "{A0DF25BA-6F74-4F11-9F85-0F99278D5986}");
AZ_DISABLE_COPY_MOVE(AtomToolsApplication);
using Base = AzFramework::Application;
AtomToolsApplication(int* argc, char*** argv);
AtomToolsApplication(const AZStd::string& targetName, int* argc, char*** argv);
~AtomToolsApplication();
virtual bool LaunchLocalServer();
//////////////////////////////////////////////////////////////////////////
// AzFramework::Application
// AzFramework::Application overrides...
void CreateReflectionManager() override;
void Reflect(AZ::ReflectContext* context) override;
void RegisterCoreComponents() override;
@ -57,43 +57,25 @@ namespace AtomToolsFramework
const char* GetCurrentConfigurationName() const override;
void StartCommon(AZ::Entity* systemEntity) override;
void Tick() override;
void Stop() override;
void Destroy() override;
protected:
//////////////////////////////////////////////////////////////////////////
// AtomsToolMainWindowNotificationBus::Handler overrides...
void OnMainWindowClosing() override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// AssetDatabaseRequestsBus::Handler overrides...
bool GetAssetDatabaseLocation(AZStd::string& result) override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// AzFramework::Application overrides...
void Destroy() override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// AZ::ComponentApplication overrides...
void QueryApplicationType(AZ::ApplicationTypeQuery& appType) const override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// AZ::UserSettingsOwnerRequestBus::Handler overrides...
void SaveSettings() override;
//////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// EditorPythonConsoleNotificationBus::Handler overrides...
void OnTraceMessage(AZStd::string_view message) override;
void OnErrorMessage(AZStd::string_view message) override;
void OnExceptionMessage(AZStd::string_view message) override;
////////////////////////////////////////////////////////////////////////
//! Executable target name generally used as a prefix for logging and other saved files
virtual AZStd::string GetBuildTargetName() const;
//! List of filters for assets that need to be pre-built to run the application
virtual AZStd::vector<AZStd::string> GetCriticalAssetFilters() const;
@ -121,5 +103,8 @@ namespace AtomToolsFramework
AtomToolsFramework::LocalSocket m_socket;
AtomToolsFramework::LocalServer m_server;
const AZStd::string m_targetName;
const AZ::Crc32 m_toolId = {};
};
} // namespace AtomToolsFramework

@ -23,9 +23,9 @@ namespace AtomToolsFramework
public:
AZ_RTTI(AtomToolsDocument, "{8992DF74-88EC-438C-B280-6E71D4C0880B}");
AZ_CLASS_ALLOCATOR(AtomToolsDocument, AZ::SystemAllocator, 0);
AZ_DISABLE_COPY(AtomToolsDocument);
AZ_DISABLE_COPY_MOVE(AtomToolsDocument);
AtomToolsDocument();
AtomToolsDocument(const AZ::Crc32& toolId);
virtual ~AtomToolsDocument();
const AZ::Uuid& GetId() const;
@ -66,8 +66,10 @@ namespace AtomToolsFramework
//! This can be overridden to restore additional data.
virtual bool ReopenRestoreState();
const AZ::Crc32 m_toolId = {};
//! The unique id of this document, used for all bus notifications and requests.
AZ::Uuid m_id = AZ::Uuid::CreateRandom();
const AZ::Uuid m_id = AZ::Uuid::CreateRandom();
//! The absolute path to the document source file.
AZStd::string m_absolutePath;

@ -9,6 +9,7 @@
#pragma once
#include <AtomToolsFramework/Application/AtomToolsApplication.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentSystem.h>
namespace AtomToolsFramework
{
@ -16,13 +17,20 @@ namespace AtomToolsFramework
: public AtomToolsApplication
{
public:
AZ_TYPE_INFO(AtomToolsDocumentApplication, "{F4B43677-EB95-4CBB-8B8E-9EF4247E6F0D}");
AZ_TYPE_INFO(AtomToolsDocumentApplication, "{AC892170-D353-404A-A3D8-BB039C717295}");
AZ_DISABLE_COPY_MOVE(AtomToolsDocumentApplication);
using Base = AtomToolsApplication;
AtomToolsDocumentApplication(int* argc, char*** argv);
AtomToolsDocumentApplication(const AZStd::string& targetName, int* argc, char*** argv);
protected:
// AtomToolsApplication overrides...
void Reflect(AZ::ReflectContext* context) override;
void StartCommon(AZ::Entity* systemEntity) override;
void Destroy() override;
void ProcessCommandLine(const AZ::CommandLine& commandLine) override;
AZStd::unique_ptr<AtomToolsDocumentSystem> m_documentSystem;
};
} // namespace AtomToolsFramework

@ -28,7 +28,7 @@ namespace AtomToolsFramework
using Base = AtomToolsMainWindow;
AtomToolsDocumentMainWindow(QWidget* parent = 0);
AtomToolsDocumentMainWindow(const AZ::Crc32& toolId, QWidget* parent = 0);
~AtomToolsDocumentMainWindow();
protected:

@ -18,8 +18,9 @@ namespace AtomToolsFramework
: public AZ::EBusTraits
{
public:
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
typedef AZ::Crc32 BusIdType;
//! Signal that a document was created
//! @param documentId unique id of document for which the notification is sent

@ -8,60 +8,34 @@
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/Asset/AssetCommon.h>
#include <AtomToolsFramework/Document/AtomToolsDocument.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QFileInfo>
#include <QString>
AZ_POP_DISABLE_WARNING
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Memory/Memory.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
namespace AtomToolsFramework
{
//! AtomToolsDocumentSystemComponent is the central component for managing documents
class AtomToolsDocumentSystemComponent
: public AZ::Component
, private AtomToolsDocumentNotificationBus::Handler
, private AtomToolsDocumentSystemRequestBus::Handler
//! AtomToolsDocumentSystem Is responsible for creation, management, and requests related to documents
class AtomToolsDocumentSystem
: public AtomToolsDocumentNotificationBus::Handler
, public AtomToolsDocumentSystemRequestBus::Handler
{
public:
AZ_COMPONENT(AtomToolsDocumentSystemComponent, "{343A3383-6A59-4343-851B-BF84FC6CB18E}");
AtomToolsDocumentSystemComponent();
~AtomToolsDocumentSystemComponent() = default;
AtomToolsDocumentSystemComponent(const AtomToolsDocumentSystemComponent&) = delete;
AtomToolsDocumentSystemComponent& operator=(const AtomToolsDocumentSystemComponent&) = delete;
AZ_CLASS_ALLOCATOR(AtomToolsFramework::AtomToolsDocumentSystem, AZ::SystemAllocator, 0);
AZ_RTTI(AtomToolsFramework::AtomToolsDocumentSystem, "{9D31F309-6B20-40C5-813C-F1226180E1F8}");
AZ_DISABLE_COPY_MOVE(AtomToolsDocumentSystem);
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
private:
////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Init() override;
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// AtomToolsDocumentNotificationBus::Handler overrides...
void OnDocumentDependencyModified(const AZ::Uuid& documentId) override;
void OnDocumentExternallyModified(const AZ::Uuid& documentId) override;
//////////////////////////////////////////////////////////////////////////
void QueueReopenDocuments();
void ReopenDocuments();
AtomToolsDocumentSystem() = default;
AtomToolsDocumentSystem(const AZ::Crc32& toolId);
~AtomToolsDocumentSystem();
////////////////////////////////////////////////////////////////////////
// AtomToolsDocumentSystemRequestBus::Handler overrides...
void RegisterDocumentType(AZStd::function<AtomToolsDocument*()> documentCreator) override;
void RegisterDocumentType(const AtomToolsDocumentFactoryCallback& documentCreator) override;
AZ::Uuid CreateDocument() override;
bool DestroyDocument(const AZ::Uuid& documentId) override;
AZ::Uuid OpenDocument(AZStd::string_view sourcePath) override;
@ -74,11 +48,19 @@ namespace AtomToolsFramework
bool SaveDocumentAsChild(const AZ::Uuid& documentId, AZStd::string_view targetPath) override;
bool SaveAllDocuments() override;
AZ::u32 GetDocumentCount() const override;
////////////////////////////////////////////////////////////////////////
private:
// AtomToolsDocumentNotificationBus::Handler overrides...
void OnDocumentDependencyModified(const AZ::Uuid& documentId) override;
void OnDocumentExternallyModified(const AZ::Uuid& documentId) override;
void QueueReopenDocuments();
void ReopenDocuments();
AZ::Uuid OpenDocumentImpl(AZStd::string_view sourcePath, bool checkIfAlreadyOpen);
AZStd::function<AtomToolsDocument*()> m_documentCreator;
const AZ::Crc32 m_toolId = {};
AtomToolsDocumentFactoryCallback m_documentCreator;
AZStd::unordered_map<AZ::Uuid, AZStd::shared_ptr<AtomToolsDocument>> m_documentMap;
AZStd::unordered_set<AZ::Uuid> m_documentIdsWithExternalChanges;
AZStd::unordered_set<AZ::Uuid> m_documentIdsWithDependencyChanges;

@ -14,16 +14,19 @@ namespace AtomToolsFramework
{
class AtomToolsDocument;
//! AtomToolsDocumentSystemRequestBus provides high level requests for menus, scripts, etc.
using AtomToolsDocumentFactoryCallback = AZStd::function<AtomToolsDocument*(const AZ::Crc32&)>;
//! AtomToolsDocumentSystemRequestBus is an interface that provides requests for high level user interactions with a system of documents
class AtomToolsDocumentSystemRequests
: public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
typedef AZ::Crc32 BusIdType;
//! Register a document factory function used to create specific document types
virtual void RegisterDocumentType(AZStd::function<AtomToolsDocument*()> documentCreator) = 0;
virtual void RegisterDocumentType(const AtomToolsDocumentFactoryCallback& documentCreator) = 0;
//! Create a document
//! @return Uuid of new document, or null Uuid if failed

@ -25,7 +25,7 @@ namespace AtomToolsFramework
, protected AtomToolsMainWindowRequestBus::Handler
{
public:
AtomToolsMainWindow(QWidget* parent = 0);
AtomToolsMainWindow(const AZ::Crc32& toolId, QWidget* parent = 0);
~AtomToolsMainWindow();
protected:
@ -48,6 +48,9 @@ namespace AtomToolsFramework
virtual void SetupMetrics();
virtual void UpdateMetrics();
virtual void UpdateWindowTitle();
const AZ::Crc32 m_toolId = {};
AzQtComponents::FancyDocking* m_advancedDockManager = {};

@ -1,30 +0,0 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/EBus/EBus.h>
namespace AtomToolsFramework
{
//! AtomToolsMainWindowFactoryRequestBus provides
class AtomToolsMainWindowFactoryRequests : public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
/// Creates and shows main window
virtual void CreateMainWindow() = 0;
//! Destroys main window and releases all cached assets
virtual void DestroyMainWindow() = 0;
};
using AtomToolsMainWindowFactoryRequestBus = AZ::EBus<AtomToolsMainWindowFactoryRequests>;
} // namespace AtomToolsFramework

@ -16,7 +16,8 @@ namespace AtomToolsFramework
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
typedef AZ::Crc32 BusIdType;
virtual void OnMainWindowClosing(){};
};

@ -16,12 +16,14 @@ class QWidget;
namespace AtomToolsFramework
{
//! AtomToolsMainWindowRequestBus provides
//! AtomToolsMainWindowRequestBus provides an interface to common main application window functions like adding docked windows,
//! resizing the viewport, and other operations
class AtomToolsMainWindowRequests : public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::ById;
typedef AZ::Crc32 BusIdType;
//! Bring main window to foreground
virtual void ActivateWindow() = 0;
@ -58,6 +60,7 @@ namespace AtomToolsFramework
//! Releases the viewport's render target resolution lock, allowing it to match the viewport widget again.
virtual void UnlockViewportRenderTargetSize() {};
};
using AtomToolsMainWindowRequestBus = AZ::EBus<AtomToolsMainWindowRequests>;
} // namespace AtomToolsFramework

@ -9,7 +9,6 @@
#include <Atom/RPI.Public/RPISystemInterface.h>
#include <AtomToolsFramework/Application/AtomToolsApplication.h>
#include <AtomToolsFramework/Util/Util.h>
#include <AtomToolsFramework/Window/AtomToolsMainWindowFactoryRequestBus.h>
#include <AtomToolsFramework/Window/AtomToolsMainWindowRequestBus.h>
#include <AzCore/Component/ComponentApplicationLifecycle.h>
@ -46,26 +45,16 @@ AZ_POP_DISABLE_WARNING
namespace AtomToolsFramework
{
AZStd::string AtomToolsApplication::GetBuildTargetName() const
{
return AZStd::string("AtomTools");
}
const char* AtomToolsApplication::GetCurrentConfigurationName() const
{
#if defined(_RELEASE)
return "ReleaseAtomTools";
#elif defined(_DEBUG)
return "DebugAtomTools";
#else
return "ProfileAtomTools";
#endif
}
AtomToolsApplication::AtomToolsApplication(int* argc, char*** argv)
AtomToolsApplication::AtomToolsApplication(const AZStd::string& targetName, int* argc, char*** argv)
: Application(argc, argv)
, AzQtApplication(*argc, *argv)
, m_targetName(targetName)
, m_toolId(targetName)
{
// The settings registry has been created at this point, so add the CMake target
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(
*AZ::SettingsRegistry::Get(), m_targetName);
// Suppress spam from the Source Control system
m_traceLogger.AddWindowFilter(AzToolsFramework::SCC_WINDOW);
@ -80,18 +69,26 @@ namespace AtomToolsFramework
m_styleManager.reset(new AzQtComponents::StyleManager(this));
m_styleManager->initialize(this, engineRootPath);
m_timer.setInterval(1);
const AZ::u64 updateIntervalWhenActive =
GetSettingOrDefault<AZ::u64>("/O3DE/AtomToolsFramework/Application/UpdateIntervalWhenActive", 1);
const AZ::u64 updateIntervalWhenNotActive =
GetSettingOrDefault<AZ::u64>("/O3DE/AtomToolsFramework/Application/UpdateIntervalWhenNotActive", 64);
m_timer.setInterval(updateIntervalWhenActive);
connect(&m_timer, &QTimer::timeout, this, [this]()
{
this->PumpSystemEventLoopUntilEmpty();
this->Tick();
});
connect(this, &QGuiApplication::applicationStateChanged, this, [this]()
connect(this, &QGuiApplication::applicationStateChanged, this, [this, updateIntervalWhenActive, updateIntervalWhenNotActive]()
{
// Limit the update interval when not in focus to reduce power consumption and interference with other applications
this->m_timer.setInterval((applicationState() & Qt::ApplicationActive) ? 1 : 32);
this->m_timer.setInterval(
(applicationState() & Qt::ApplicationActive) ? updateIntervalWhenActive : updateIntervalWhenNotActive);
});
AtomToolsMainWindowNotificationBus::Handler::BusConnect(m_toolId);
}
AtomToolsApplication ::~AtomToolsApplication()
@ -108,6 +105,17 @@ namespace AtomToolsFramework
GetSerializeContext()->CreateEditContext();
}
const char* AtomToolsApplication::GetCurrentConfigurationName() const
{
#if defined(_RELEASE)
return "ReleaseAtomTools";
#elif defined(_DEBUG)
return "DebugAtomTools";
#else
return "ProfileAtomTools";
#endif
}
void AtomToolsApplication::Reflect(AZ::ReflectContext* context)
{
Base::Reflect(context);
@ -181,7 +189,7 @@ namespace AtomToolsFramework
Base::StartCommon(systemEntity);
const bool clearLogFile = GetSettingOrDefault("/O3DE/AtomToolsFramework/Application/ClearLogOnStart", false);
m_traceLogger.OpenLogFile(GetBuildTargetName() + ".log", clearLogFile);
m_traceLogger.OpenLogFile(m_targetName + ".log", clearLogFile);
ConnectToAssetProcessor();
@ -200,9 +208,6 @@ namespace AtomToolsFramework
LoadSettings();
AtomToolsMainWindowNotificationBus::Handler::BusConnect();
AtomToolsMainWindowFactoryRequestBus::Broadcast(&AtomToolsMainWindowFactoryRequestBus::Handler::CreateMainWindow);
auto editorPythonEventsInterface = AZ::Interface<AzToolsFramework::EditorPythonEventsInterface>::Get();
if (editorPythonEventsInterface)
{
@ -218,16 +223,22 @@ namespace AtomToolsFramework
m_timer.start();
}
void AtomToolsApplication::OnMainWindowClosing()
void AtomToolsApplication::Tick()
{
ExitMainLoop();
TickSystem();
Base::Tick();
if (WasExitMainLoopRequested())
{
m_timer.disconnect();
quit();
}
}
void AtomToolsApplication::Destroy()
{
// before modules are unloaded, destroy UI to free up any assets it cached
AtomToolsMainWindowFactoryRequestBus::Broadcast(&AtomToolsMainWindowFactoryRequestBus::Handler::DestroyMainWindow);
m_styleManager.reset();
UnloadSettings();
AzToolsFramework::EditorPythonConsoleNotificationBus::Handler::BusDisconnect();
AzToolsFramework::AssetDatabase::AssetDatabaseRequestsBus::Handler::BusDisconnect();
@ -241,6 +252,11 @@ namespace AtomToolsFramework
#endif
}
void AtomToolsApplication::OnMainWindowClosing()
{
ExitMainLoop();
}
AZStd::vector<AZStd::string> AtomToolsApplication::GetCriticalAssetFilters() const
{
return AZStd::vector<AZStd::string>({});
@ -255,14 +271,12 @@ namespace AtomToolsFramework
// and able to negotiate a connection when running a debug build
// and to negotiate a connection
const auto targetName = GetBuildTargetName();
AzFramework::AssetSystem::ConnectionSettings connectionSettings;
AzFramework::AssetSystem::ReadConnectionSettingsFromSettingsRegistry(connectionSettings);
connectionSettings.m_connectionDirection =
AzFramework::AssetSystem::ConnectionSettings::ConnectionDirection::ConnectToAssetProcessor;
connectionSettings.m_connectionIdentifier = targetName;
connectionSettings.m_loggingCallback = [targetName]([[maybe_unused]] AZStd::string_view logData)
connectionSettings.m_connectionIdentifier = m_targetName;
connectionSettings.m_loggingCallback = [targetName = m_targetName]([[maybe_unused]] AZStd::string_view logData)
{
AZ_UNUSED(targetName); // Prevent unused warning in release builds
AZ_TracePrintf(targetName.c_str(), "%.*s", aznumeric_cast<int>(logData.size()), logData.data());
@ -279,7 +293,7 @@ namespace AtomToolsFramework
void AtomToolsApplication::CompileCriticalAssets()
{
AZ_TracePrintf(GetBuildTargetName().c_str(), "Compiling critical assets.\n");
AZ_TracePrintf(m_targetName.c_str(), "Compiling critical assets.\n");
QStringList failedAssets;
@ -288,7 +302,7 @@ namespace AtomToolsFramework
// So the asset id won't be found right after CompileAssetSync call.
for (const AZStd::string& assetFilters : GetCriticalAssetFilters())
{
AZ_TracePrintf(GetBuildTargetName().c_str(), "Compiling critical asset matching: %s.\n", assetFilters.c_str());
AZ_TracePrintf(m_targetName.c_str(), "Compiling critical asset matching: %s.\n", assetFilters.c_str());
// Wait for the asset be compiled
AzFramework::AssetSystem::AssetStatus status = AzFramework::AssetSystem::AssetStatus_Unknown;
@ -335,7 +349,7 @@ namespace AtomToolsFramework
AZ_Assert(context, "No serialize context");
char resolvedPath[AZ_MAX_PATH_LEN] = "";
AZStd::string fileName = "@user@/" + GetBuildTargetName() + "UserSettings.xml";
AZStd::string fileName = "@user@/" + m_targetName + "UserSettings.xml";
AZ::IO::FileIOBase::GetInstance()->ResolvePath(
fileName.c_str(), resolvedPath, AZ_ARRAY_SIZE(resolvedPath));
@ -350,7 +364,7 @@ namespace AtomToolsFramework
AZ_Assert(context, "No serialize context");
char resolvedPath[AZ_MAX_PATH_LEN] = "";
AZStd::string fileName = "@user@/" + GetBuildTargetName() + "UserSettings.xml";
AZStd::string fileName = "@user@/" + m_targetName + "UserSettings.xml";
AZ::IO::FileIOBase::GetInstance()->ResolvePath(fileName.c_str(), resolvedPath, AZ_MAX_PATH_LEN);
@ -376,8 +390,7 @@ namespace AtomToolsFramework
const AZStd::string activateWindowSwitchName = "activatewindow";
if (commandLine.HasSwitch(activateWindowSwitchName))
{
AtomToolsFramework::AtomToolsMainWindowRequestBus::Broadcast(
&AtomToolsFramework::AtomToolsMainWindowRequestBus::Handler::ActivateWindow);
AtomToolsMainWindowRequestBus::Event(m_toolId, &AtomToolsMainWindowRequestBus::Handler::ActivateWindow);
}
const AZStd::string timeoputSwitchName = "timeout";
@ -385,12 +398,9 @@ namespace AtomToolsFramework
{
const AZStd::string& timeoutValue = commandLine.GetSwitchValue(timeoputSwitchName, 0);
const uint32_t timeoutInMs = atoi(timeoutValue.c_str());
AZ_Printf(GetBuildTargetName().c_str(), "Timeout scheduled, shutting down in %u ms", timeoutInMs);
QTimer::singleShot(
timeoutInMs,
[this]
{
AZ_Printf(GetBuildTargetName().c_str(), "Timeout reached, shutting down");
AZ_Printf(m_targetName.c_str(), "Timeout scheduled, shutting down in %u ms", timeoutInMs);
QTimer::singleShot(timeoutInMs, [this] {
AZ_Printf(m_targetName.c_str(), "Timeout reached, shutting down");
ExitMainLoop();
});
}
@ -403,7 +413,7 @@ namespace AtomToolsFramework
const AZStd::string runPythonScriptPath = commandLine.GetSwitchValue(runPythonScriptSwitchName, runPythonScriptIndex);
AZStd::vector<AZStd::string_view> runPythonArgs;
AZ_Printf(GetBuildTargetName().c_str(), "Launching script: %s", runPythonScriptPath.c_str());
AZ_Printf(m_targetName.c_str(), "Launching script: %s", runPythonScriptPath.c_str());
AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(
&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilenameWithArgs, runPythonScriptPath, runPythonArgs);
}
@ -486,27 +496,6 @@ namespace AtomToolsFramework
return false;
}
void AtomToolsApplication::Tick()
{
TickSystem();
Base::Tick();
if (WasExitMainLoopRequested())
{
m_timer.disconnect();
quit();
}
}
void AtomToolsApplication::Stop()
{
AtomToolsMainWindowFactoryRequestBus::Broadcast(&AtomToolsMainWindowFactoryRequestBus::Handler::DestroyMainWindow);
m_styleManager.reset();
UnloadSettings();
Base::Stop();
}
void AtomToolsApplication::QueryApplicationType(AZ::ApplicationTypeQuery& appType) const
{
appType.m_maskValue = AZ::ApplicationTypeQuery::Masks::Tool;
@ -524,7 +513,7 @@ namespace AtomToolsFramework
for (auto& line : lines)
{
AZ_TracePrintf(GetBuildTargetName().c_str(), "Python: %s\n", line.c_str());
AZ_TracePrintf(m_targetName.c_str(), "Python: %s\n", line.c_str());
}
#endif
}
@ -537,7 +526,7 @@ namespace AtomToolsFramework
void AtomToolsApplication::OnExceptionMessage([[maybe_unused]] AZStd::string_view message)
{
AZ_Error(GetBuildTargetName().c_str(), false, "Python: " AZ_STRING_FORMAT, AZ_STRING_ARG(message));
AZ_Error(m_targetName.c_str(), false, "Python: " AZ_STRING_FORMAT, AZ_STRING_ARG(message));
}
// Copied from PyIdleWaitFrames in CryEdit.cpp
@ -577,6 +566,8 @@ namespace AtomToolsFramework
void AtomToolsApplication::PyExit()
{
QTimer::singleShot(0, []() {
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::ExitMainLoop);
});
}
} // namespace AtomToolsFramework

@ -89,13 +89,14 @@ namespace AtomToolsFramework
void AtomToolsAssetBrowser::SelectEntries(const AZStd::string& absolutePath)
{
if (!absolutePath.empty())
AZ::TickBus::Handler::BusDisconnect();
m_pathToSelect = absolutePath;
if (!m_pathToSelect.empty() && AzFramework::StringFunc::Path::Normalize(m_pathToSelect))
{
// Selecting a new asset in the browser is not guaranteed to happen immediately.
// The asset browser model notifications are sent before the model is updated.
// Instead of relying on the notifications, queue the selection and process it on tick until this change occurs.
m_pathToSelect = absolutePath;
AzFramework::StringFunc::Path::Normalize(m_pathToSelect);
AZ::TickBus::Handler::BusConnect();
}
}
@ -201,8 +202,13 @@ namespace AtomToolsFramework
AZ_UNUSED(time);
AZ_UNUSED(deltaTime);
if (!m_pathToSelect.empty())
if (m_pathToSelect.empty())
{
AZ::TickBus::Handler::BusDisconnect();
m_pathToSelect.clear();
return;
}
// Attempt to select the new path
AzToolsFramework::AssetBrowser::AssetBrowserViewRequestBus::Broadcast(
&AzToolsFramework::AssetBrowser::AssetBrowserViewRequestBus::Events::SelectFileAtPath, m_pathToSelect);
@ -223,7 +229,6 @@ namespace AtomToolsFramework
}
}
}
}
} // namespace AtomToolsFramework
#include <AtomToolsFramework/AssetBrowser/moc_AtomToolsAssetBrowser.cpp>

@ -8,7 +8,6 @@
#include <AtomToolsFrameworkModule.h>
#include <AtomToolsFrameworkSystemComponent.h>
#include <Document/AtomToolsDocumentSystemComponent.h>
#include <Window/AtomToolsMainWindowSystemComponent.h>
#include <PerformanceMonitor/PerformanceMonitorSystemComponent.h>
#include <PreviewRenderer/PreviewRendererSystemComponent.h>
@ -19,7 +18,6 @@ namespace AtomToolsFramework
{
m_descriptors.insert(m_descriptors.end(), {
AtomToolsFrameworkSystemComponent::CreateDescriptor(),
AtomToolsDocumentSystemComponent::CreateDescriptor(),
AtomToolsMainWindowSystemComponent::CreateDescriptor(),
PerformanceMonitorSystemComponent::CreateDescriptor(),
PreviewRendererSystemComponent::CreateDescriptor(),
@ -30,7 +28,6 @@ namespace AtomToolsFramework
{
return AZ::ComponentTypeList{
azrtti_typeid<AtomToolsFrameworkSystemComponent>(),
azrtti_typeid<AtomToolsDocumentSystemComponent>(),
azrtti_typeid<AtomToolsMainWindowSystemComponent>(),
azrtti_typeid<PerformanceMonitorSystemComponent>(),
azrtti_typeid<PreviewRendererSystemComponent>(),

@ -13,17 +13,18 @@
namespace AtomToolsFramework
{
AtomToolsDocument::AtomToolsDocument()
AtomToolsDocument::AtomToolsDocument(const AZ::Crc32& toolId)
: m_toolId(toolId)
{
AtomToolsDocumentRequestBus::Handler::BusConnect(m_id);
AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentCreated, m_id);
AtomToolsDocumentNotificationBus::Event(m_toolId, &AtomToolsDocumentNotificationBus::Events::OnDocumentCreated, m_id);
}
AtomToolsDocument::~AtomToolsDocument()
{
AzToolsFramework::AssetSystemBus::Handler::BusDisconnect();
AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentDestroyed, m_id);
AtomToolsDocumentNotificationBus::Event(m_toolId, &AtomToolsDocumentNotificationBus::Events::OnDocumentDestroyed, m_id);
AtomToolsDocumentRequestBus::Handler::BusDisconnect();
AzToolsFramework::AssetSystemBus::Handler::BusDisconnect();
}
const AZ::Uuid& AtomToolsDocument::GetId() const
@ -80,10 +81,10 @@ namespace AtomToolsFramework
return false;
}
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentModified, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentModified, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
return true;
}
@ -169,8 +170,8 @@ namespace AtomToolsFramework
AZ_TracePrintf("AtomToolsDocument", "Document closed: '%s'.\n", m_absolutePath.c_str());
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentClosed, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentClosed, m_id);
// Clearing after notification so paths are still available
Clear();
@ -211,8 +212,8 @@ namespace AtomToolsFramework
// The history index is one beyond the last executed command. Decrement the index then execute undo.
m_undoHistory[--m_undoHistoryIndex].first();
AZ_TracePrintf("AtomToolsDocument", "Document undo: '%s'.\n", m_absolutePath.c_str());
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
return true;
}
return false;
@ -225,8 +226,8 @@ namespace AtomToolsFramework
// Execute the current redo command then move the history index to the next position.
m_undoHistory[m_undoHistoryIndex++].second();
AZ_TracePrintf("AtomToolsDocument", "Document redo: '%s'.\n", m_absolutePath.c_str());
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
return true;
}
return false;
@ -259,8 +260,8 @@ namespace AtomToolsFramework
{
AZ_TracePrintf("AtomToolsDocument", "Document opened: '%s'.\n", m_absolutePath.c_str());
AzToolsFramework::AssetSystemBus::Handler::BusConnect();
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, m_id);
return true;
}
@ -282,8 +283,8 @@ namespace AtomToolsFramework
&AzToolsFramework::SourceControlCommandBus::Events::RequestEdit, m_savePathNormalized.c_str(), true,
[](bool, const AzToolsFramework::SourceControlFileInfo&) {});
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentSaved, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentSaved, m_id);
return true;
}
@ -319,8 +320,8 @@ namespace AtomToolsFramework
// Assign the index to the end of history
m_undoHistoryIndex = aznumeric_cast<int>(m_undoHistory.size());
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentUndoStateChanged, m_id);
}
void AtomToolsDocument::SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, [[maybe_unused]] AZ::Uuid sourceUUID)
@ -333,16 +334,16 @@ namespace AtomToolsFramework
if (!m_ignoreSourceFileChangeToSelf)
{
AZ_TracePrintf("AtomToolsDocument", "Document changed externally: '%s'.\n", m_absolutePath.c_str());
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentExternallyModified, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentExternallyModified, m_id);
}
m_ignoreSourceFileChangeToSelf = false;
}
else if (m_sourceDependencies.find(sourcePath) != m_sourceDependencies.end())
{
AZ_TracePrintf("AtomToolsDocument", "Document dependency changed: '%s'.\n", m_absolutePath.c_str());
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentDependencyModified, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentDependencyModified, m_id);
}
}

@ -11,11 +11,29 @@
namespace AtomToolsFramework
{
AtomToolsDocumentApplication::AtomToolsDocumentApplication(int* argc, char*** argv)
: Base(argc, argv)
AtomToolsDocumentApplication::AtomToolsDocumentApplication(const AZStd::string& targetName, int* argc, char*** argv)
: Base(targetName, argc, argv)
{
}
void AtomToolsDocumentApplication::Reflect(AZ::ReflectContext* context)
{
Base::Reflect(context);
AtomToolsDocumentSystem::Reflect(context);
}
void AtomToolsDocumentApplication::StartCommon(AZ::Entity* systemEntity)
{
Base::StartCommon(systemEntity);
m_documentSystem.reset(aznew AtomToolsDocumentSystem(m_toolId));
}
void AtomToolsDocumentApplication::Destroy()
{
m_documentSystem.reset();
Base::Destroy();
}
void AtomToolsDocumentApplication::ProcessCommandLine(const AZ::CommandLine& commandLine)
{
// Process command line options for opening documents on startup
@ -24,8 +42,8 @@ namespace AtomToolsFramework
{
const AZStd::string openDocumentPath = commandLine.GetMiscValue(openDocumentIndex);
AZ_Printf(GetBuildTargetName().c_str(), "Opening document: %s", openDocumentPath.c_str());
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath);
AZ_Printf(m_targetName.c_str(), "Opening document: %s", openDocumentPath.c_str());
AtomToolsDocumentSystemRequestBus::Event(m_toolId, &AtomToolsDocumentSystemRequestBus::Events::OpenDocument, openDocumentPath);
}
Base::ProcessCommandLine(commandLine);

@ -25,13 +25,13 @@ AZ_POP_DISABLE_WARNING
namespace AtomToolsFramework
{
AtomToolsDocumentMainWindow::AtomToolsDocumentMainWindow(QWidget* parent /* = 0 */)
: AtomToolsMainWindow(parent)
AtomToolsDocumentMainWindow::AtomToolsDocumentMainWindow(const AZ::Crc32& toolId, QWidget* parent /* = 0 */)
: AtomToolsMainWindow(toolId, parent)
{
setObjectName("AtomToolsDocumentMainWindow");
AddDocumentMenus();
AddDocumentTabBar();
AtomToolsDocumentNotificationBus::Handler::BusConnect();
AtomToolsDocumentNotificationBus::Handler::BusConnect(m_toolId);
}
AtomToolsDocumentMainWindow::~AtomToolsDocumentMainWindow()
@ -49,8 +49,8 @@ namespace AtomToolsFramework
AZStd::string savePath;
if (GetCreateDocumentParams(openPath, savePath))
{
AtomToolsDocumentSystemRequestBus::Broadcast(
&AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, openPath, savePath);
AtomToolsDocumentSystemRequestBus::Event(
m_toolId, &AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile, openPath, savePath);
}
}, QKeySequence::New);
m_menuFile->insertAction(insertPostion, m_actionNew);
@ -59,7 +59,7 @@ namespace AtomToolsFramework
AZStd::string openPath;
if (GetOpenDocumentParams(openPath))
{
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::OpenDocument, openPath);
AtomToolsDocumentSystemRequestBus::Event(m_toolId, &AtomToolsDocumentSystemRequestBus::Events::OpenDocument, openPath);
}
}, QKeySequence::Open);
m_menuFile->insertAction(insertPostion, m_actionOpen);
@ -68,7 +68,8 @@ namespace AtomToolsFramework
m_actionSave = CreateAction("&Save", [this]() {
const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex());
bool result = false;
AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId);
AtomToolsDocumentSystemRequestBus::EventResult(
result, m_toolId, &AtomToolsDocumentSystemRequestBus::Events::SaveDocument, documentId);
if (!result)
{
SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId)));
@ -81,8 +82,9 @@ namespace AtomToolsFramework
const QString documentPath = GetDocumentPath(documentId);
bool result = false;
AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsCopy,
documentId, GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData());
AtomToolsDocumentSystemRequestBus::EventResult(
result, m_toolId, &AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsCopy, documentId,
GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData());
if (!result)
{
SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId)));
@ -95,8 +97,9 @@ namespace AtomToolsFramework
const QString documentPath = GetDocumentPath(documentId);
bool result = false;
AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsChild,
documentId, GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData());
AtomToolsDocumentSystemRequestBus::EventResult(
result, m_toolId, &AtomToolsDocumentSystemRequestBus::Events::SaveDocumentAsChild, documentId,
GetSaveFileInfo(documentPath).absoluteFilePath().toUtf8().constData());
if (!result)
{
SetStatusError(tr("Document save failed: %1").arg(GetDocumentPath(documentId)));
@ -106,7 +109,8 @@ namespace AtomToolsFramework
m_actionSaveAll = CreateAction("Save A&ll", [this]() {
bool result = false;
AtomToolsDocumentSystemRequestBus::BroadcastResult(result, &AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments);
AtomToolsDocumentSystemRequestBus::EventResult(
result, m_toolId, &AtomToolsDocumentSystemRequestBus::Events::SaveAllDocuments);
if (!result)
{
SetStatusError(tr("Document save all failed"));
@ -117,18 +121,19 @@ namespace AtomToolsFramework
m_actionClose = CreateAction("&Close", [this]() {
const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex());
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId);
AtomToolsDocumentSystemRequestBus::Event(m_toolId, &AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId);
}, QKeySequence::Close);
m_menuFile->insertAction(insertPostion, m_actionClose);
m_actionCloseAll = CreateAction("Close All", []() {
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments);
m_actionCloseAll = CreateAction("Close All", [this]() {
AtomToolsDocumentSystemRequestBus::Event(m_toolId, &AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments);
});
m_menuFile->insertAction(insertPostion, m_actionCloseAll);
m_actionCloseOthers = CreateAction("Close Others", [this]() {
const AZ::Uuid documentId = GetDocumentTabId(m_tabWidget->currentIndex());
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId);
AtomToolsDocumentSystemRequestBus::Event(
m_toolId, &AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId);
});
m_menuFile->insertAction(insertPostion, m_actionCloseOthers);
m_menuFile->insertSeparator(insertPostion);
@ -194,12 +199,12 @@ namespace AtomToolsFramework
// This should automatically clear the active document
connect(m_tabWidget, &QTabWidget::currentChanged, this, [this](int tabIndex) {
const AZ::Uuid documentId = GetDocumentTabId(tabIndex);
AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId);
AtomToolsDocumentNotificationBus::Event(m_toolId,&AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId);
});
connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, [this](int tabIndex) {
const AZ::Uuid documentId = GetDocumentTabId(tabIndex);
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId);
AtomToolsDocumentSystemRequestBus::Event(m_toolId, &AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId);
});
// Add context menu for right-clicking on tabs
@ -341,15 +346,18 @@ namespace AtomToolsFramework
const QString selectActionName = (currentTabIndex == clickedTabIndex) ? "Select in Browser" : "Select";
tabMenu.addAction(selectActionName, [this, clickedTabIndex]() {
const AZ::Uuid documentId = GetDocumentTabId(clickedTabIndex);
AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId);
AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId);
});
tabMenu.addAction("Close", [this, clickedTabIndex]() {
const AZ::Uuid documentId = GetDocumentTabId(clickedTabIndex);
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId);
AtomToolsDocumentSystemRequestBus::Event(
m_toolId, &AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId);
});
auto closeOthersAction = tabMenu.addAction("Close Others", [this, clickedTabIndex]() {
const AZ::Uuid documentId = GetDocumentTabId(clickedTabIndex);
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId);
AtomToolsDocumentSystemRequestBus::Event(
m_toolId, &AtomToolsDocumentSystemRequestBus::Events::CloseAllDocumentsExcept, documentId);
});
closeOthersAction->setEnabled(tabBar->count() > 1);
tabMenu.exec(QCursor::pos());
@ -472,14 +480,14 @@ namespace AtomToolsFramework
void AtomToolsDocumentMainWindow::closeEvent(QCloseEvent* closeEvent)
{
bool didClose = true;
AtomToolsDocumentSystemRequestBus::BroadcastResult(didClose, &AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments);
AtomToolsDocumentSystemRequestBus::EventResult(didClose, m_toolId, &AtomToolsDocumentSystemRequestBus::Events::CloseAllDocuments);
if (!didClose)
{
closeEvent->ignore();
return;
}
AtomToolsMainWindowNotificationBus::Broadcast(&AtomToolsMainWindowNotifications::OnMainWindowClosing);
AtomToolsMainWindowNotificationBus::Event(m_toolId, &AtomToolsMainWindowNotifications::OnMainWindowClosing);
}
template<typename Functor>

@ -9,6 +9,7 @@
#include <AtomToolsFramework/Debug/TraceRecorder.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentNotificationBus.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentRequestBus.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentSystem.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
#include <AtomToolsFramework/Util/Util.h>
#include <AzCore/RTTI/BehaviorContext.h>
@ -17,7 +18,6 @@
#include <AzFramework/Asset/AssetSystemBus.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <Document/AtomToolsDocumentSystemComponent.h>
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
#include <QApplication>
@ -28,20 +28,16 @@ AZ_POP_DISABLE_WARNING
namespace AtomToolsFramework
{
AtomToolsDocumentSystemComponent::AtomToolsDocumentSystemComponent()
void AtomToolsDocumentSystem::Reflect(AZ::ReflectContext* context)
{
}
void AtomToolsDocumentSystemComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
if (auto serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<AtomToolsDocumentSystemComponent, AZ::Component>()
serialize->Class<AtomToolsDocumentSystem>()
->Version(0);
if (AZ::EditContext* ec = serialize->GetEditContext())
if (auto editContext = serialize->GetEditContext())
{
ec->Class<AtomToolsDocumentSystemComponent>("AtomToolsDocumentSystemComponent", "")
editContext->Class<AtomToolsDocumentSystem>("AtomToolsDocumentSystem", "")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
@ -49,7 +45,7 @@ namespace AtomToolsFramework
}
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<AtomToolsDocumentSystemRequestBus>("AtomToolsDocumentSystemRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
@ -93,40 +89,26 @@ namespace AtomToolsFramework
}
}
void AtomToolsDocumentSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("AtomToolsDocumentSystemService"));
}
void AtomToolsDocumentSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
AtomToolsDocumentSystem::AtomToolsDocumentSystem(const AZ::Crc32& toolId)
: m_toolId(toolId)
{
incompatible.push_back(AZ_CRC_CE("AtomToolsDocumentSystemService"));
AtomToolsDocumentSystemRequestBus::Handler::BusConnect(m_toolId);
AtomToolsDocumentNotificationBus::Handler::BusConnect(m_toolId);
}
void AtomToolsDocumentSystemComponent::Init()
{
}
void AtomToolsDocumentSystemComponent::Activate()
AtomToolsDocumentSystem::~AtomToolsDocumentSystem()
{
m_documentMap.clear();
AtomToolsDocumentSystemRequestBus::Handler::BusConnect();
AtomToolsDocumentNotificationBus::Handler::BusConnect();
}
void AtomToolsDocumentSystemComponent::Deactivate()
{
AtomToolsDocumentNotificationBus::Handler::BusDisconnect();
AtomToolsDocumentSystemRequestBus::Handler::BusDisconnect();
m_documentMap.clear();
}
void AtomToolsDocumentSystemComponent::RegisterDocumentType(AZStd::function<AtomToolsDocument*()> documentCreator)
void AtomToolsDocumentSystem::RegisterDocumentType(const AtomToolsDocumentFactoryCallback& documentCreator)
{
m_documentCreator = documentCreator;
}
AZ::Uuid AtomToolsDocumentSystemComponent::CreateDocument()
AZ::Uuid AtomToolsDocumentSystem::CreateDocument()
{
if (!m_documentCreator)
{
@ -134,7 +116,7 @@ namespace AtomToolsFramework
return AZ::Uuid::CreateNull();
}
AZStd::unique_ptr<AtomToolsDocument> document(m_documentCreator());
AZStd::unique_ptr<AtomToolsDocument> document(m_documentCreator(m_toolId));
if (!document)
{
AZ_Error("AtomToolsDocument", false, "Failed to create new document");
@ -146,112 +128,17 @@ namespace AtomToolsFramework
return documentId;
}
bool AtomToolsDocumentSystemComponent::DestroyDocument(const AZ::Uuid& documentId)
bool AtomToolsDocumentSystem::DestroyDocument(const AZ::Uuid& documentId)
{
return m_documentMap.erase(documentId) != 0;
}
void AtomToolsDocumentSystemComponent::OnDocumentExternallyModified(const AZ::Uuid& documentId)
{
m_documentIdsWithExternalChanges.insert(documentId);
QueueReopenDocuments();
}
void AtomToolsDocumentSystemComponent::OnDocumentDependencyModified(const AZ::Uuid& documentId)
{
m_documentIdsWithDependencyChanges.insert(documentId);
QueueReopenDocuments();
}
void AtomToolsDocumentSystemComponent::QueueReopenDocuments()
{
if (!m_queueReopenDocuments)
{
m_queueReopenDocuments = true;
QTimer::singleShot(0, [this] { ReopenDocuments(); });
}
}
void AtomToolsDocumentSystemComponent::ReopenDocuments()
{
const bool enableHotReload = GetSettingOrDefault<bool>("/O3DE/AtomToolsFramework/DocumentSystem/EnableHotReload", true);
if (!enableHotReload)
{
m_documentIdsWithDependencyChanges.clear();
m_documentIdsWithExternalChanges.clear();
m_queueReopenDocuments = false;
}
const bool enableHotReloadPrompts =
GetSettingOrDefault<bool>("/O3DE/AtomToolsFramework/DocumentSystem/EnableHotReloadPrompts", true);
for (const AZ::Uuid& documentId : m_documentIdsWithExternalChanges)
{
m_documentIdsWithDependencyChanges.erase(documentId);
AZStd::string documentPath;
AtomToolsDocumentRequestBus::EventResult(documentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
if (enableHotReloadPrompts &&
(QMessageBox::question(QApplication::activeWindow(),
QString("Document was externally modified"),
QString("Would you like to reopen the document:\n%1?").arg(documentPath.c_str()),
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes))
{
continue;
}
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
bool openResult = false;
AtomToolsDocumentRequestBus::EventResult(openResult, documentId, &AtomToolsDocumentRequestBus::Events::Open, documentPath);
if (!openResult)
{
QMessageBox::critical(
QApplication::activeWindow(), QString("Document could not be opened"),
QString("Failed to open: \n%1\n\n%2").arg(documentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId);
}
}
for (const AZ::Uuid& documentId : m_documentIdsWithDependencyChanges)
{
AZStd::string documentPath;
AtomToolsDocumentRequestBus::EventResult(documentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
if (enableHotReloadPrompts &&
(QMessageBox::question(QApplication::activeWindow(),
QString("Document dependencies have changed"),
QString("Would you like to update the document with these changes:\n%1?").arg(documentPath.c_str()),
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes))
{
continue;
}
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
bool openResult = false;
AtomToolsDocumentRequestBus::EventResult(openResult, documentId, &AtomToolsDocumentRequestBus::Events::Reopen);
if (!openResult)
{
QMessageBox::critical(
QApplication::activeWindow(), QString("Document could not be opened"),
QString("Failed to open: \n%1\n\n%2").arg(documentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::CloseDocument, documentId);
}
}
m_documentIdsWithDependencyChanges.clear();
m_documentIdsWithExternalChanges.clear();
m_queueReopenDocuments = false;
}
AZ::Uuid AtomToolsDocumentSystemComponent::OpenDocument(AZStd::string_view sourcePath)
AZ::Uuid AtomToolsDocumentSystem::OpenDocument(AZStd::string_view sourcePath)
{
return OpenDocumentImpl(sourcePath, true);
}
AZ::Uuid AtomToolsDocumentSystemComponent::CreateDocumentFromFile(AZStd::string_view sourcePath, AZStd::string_view targetPath)
AZ::Uuid AtomToolsDocumentSystem::CreateDocumentFromFile(AZStd::string_view sourcePath, AZStd::string_view targetPath)
{
const AZ::Uuid documentId = OpenDocumentImpl(sourcePath, false);
if (documentId.IsNull())
@ -266,18 +153,18 @@ namespace AtomToolsFramework
}
// Send document open notification after creating new one
AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId);
AtomToolsDocumentNotificationBus::Event(m_toolId, &AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentId);
return documentId;
}
bool AtomToolsDocumentSystemComponent::CloseDocument(const AZ::Uuid& documentId)
bool AtomToolsDocumentSystem::CloseDocument(const AZ::Uuid& documentId)
{
bool isOpen = false;
AtomToolsDocumentRequestBus::EventResult(isOpen, documentId, &AtomToolsDocumentRequestBus::Events::IsOpen);
if (!isOpen)
{
// immediately destroy unopened documents
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::DestroyDocument, documentId);
DestroyDocument(documentId);
return true;
}
@ -289,8 +176,8 @@ namespace AtomToolsFramework
if (isModified)
{
auto selection = QMessageBox::question(QApplication::activeWindow(),
QString("Document has unsaved changes"),
QString("Do you want to save changes to\n%1?").arg(documentPath.c_str()),
QObject::tr("Document has unsaved changes"),
QObject::tr("Do you want to save changes to\n%1?").arg(documentPath.c_str()),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if (selection == QMessageBox::Cancel)
{
@ -307,23 +194,24 @@ namespace AtomToolsFramework
}
}
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
bool closeResult = true;
AtomToolsDocumentRequestBus::EventResult(closeResult, documentId, &AtomToolsDocumentRequestBus::Events::Close);
if (!closeResult)
{
QMessageBox::critical(
QApplication::activeWindow(), QString("Document could not be closed"),
QString("Failed to close: \n%1\n\n%2").arg(documentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
QApplication::activeWindow(),
QObject::tr("Document could not be closed"),
QObject::tr("Failed to close: \n%1\n\n%2").arg(documentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
return false;
}
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::DestroyDocument, documentId);
DestroyDocument(documentId);
return true;
}
bool AtomToolsDocumentSystemComponent::CloseAllDocuments()
bool AtomToolsDocumentSystem::CloseAllDocuments()
{
bool result = true;
auto documentMap = m_documentMap;
@ -338,7 +226,7 @@ namespace AtomToolsFramework
return result;
}
bool AtomToolsDocumentSystemComponent::CloseAllDocumentsExcept(const AZ::Uuid& documentId)
bool AtomToolsDocumentSystem::CloseAllDocumentsExcept(const AZ::Uuid& documentId)
{
bool result = true;
auto documentMap = m_documentMap;
@ -356,7 +244,7 @@ namespace AtomToolsFramework
return result;
}
bool AtomToolsDocumentSystemComponent::SaveDocument(const AZ::Uuid& documentId)
bool AtomToolsDocumentSystem::SaveDocument(const AZ::Uuid& documentId)
{
AZStd::string saveDocumentPath;
AtomToolsDocumentRequestBus::EventResult(saveDocumentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
@ -369,26 +257,30 @@ namespace AtomToolsFramework
const QFileInfo saveInfo(saveDocumentPath.c_str());
if (saveInfo.exists() && !saveInfo.isWritable())
{
QMessageBox::critical(QApplication::activeWindow(), "Error", QString("Document could not be overwritten:\n%1").arg(saveDocumentPath.c_str()));
QMessageBox::critical(
QApplication::activeWindow(),
QObject::tr("Document could not be saved"),
QObject::tr("Document could not be overwritten:\n%1").arg(saveDocumentPath.c_str()));
return false;
}
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
bool result = false;
AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::Save);
if (!result)
{
QMessageBox::critical(
QApplication::activeWindow(), QString("Document could not be saved"),
QString("Failed to save: \n%1\n\n%2").arg(saveDocumentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
QApplication::activeWindow(),
QObject::tr("Document could not be saved"),
QObject::tr("Failed to save: \n%1\n\n%2").arg(saveDocumentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
return false;
}
return true;
}
bool AtomToolsDocumentSystemComponent::SaveDocumentAsCopy(const AZ::Uuid& documentId, AZStd::string_view targetPath)
bool AtomToolsDocumentSystem::SaveDocumentAsCopy(const AZ::Uuid& documentId, AZStd::string_view targetPath)
{
AZStd::string saveDocumentPath = targetPath;
if (saveDocumentPath.empty() || !AzFramework::StringFunc::Path::Normalize(saveDocumentPath))
@ -399,26 +291,29 @@ namespace AtomToolsFramework
const QFileInfo saveInfo(saveDocumentPath.c_str());
if (saveInfo.exists() && !saveInfo.isWritable())
{
QMessageBox::critical(QApplication::activeWindow(), "Error", QString("Document could not be overwritten:\n%1").arg(saveDocumentPath.c_str()));
QMessageBox::critical(QApplication::activeWindow(),
QObject::tr("Document could not be saved"),
QObject::tr("Document could not be overwritten:\n%1").arg(saveDocumentPath.c_str()));
return false;
}
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
bool result = false;
AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::SaveAsCopy, saveDocumentPath);
if (!result)
{
QMessageBox::critical(
QApplication::activeWindow(), QString("Document could not be saved"),
QString("Failed to save: \n%1\n\n%2").arg(saveDocumentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
QApplication::activeWindow(),
QObject::tr("Document could not be saved"),
QObject::tr("Failed to save: \n%1\n\n%2").arg(saveDocumentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
return false;
}
return true;
}
bool AtomToolsDocumentSystemComponent::SaveDocumentAsChild(const AZ::Uuid& documentId, AZStd::string_view targetPath)
bool AtomToolsDocumentSystem::SaveDocumentAsChild(const AZ::Uuid& documentId, AZStd::string_view targetPath)
{
AZStd::string saveDocumentPath = targetPath;
if (saveDocumentPath.empty() || !AzFramework::StringFunc::Path::Normalize(saveDocumentPath))
@ -429,26 +324,30 @@ namespace AtomToolsFramework
const QFileInfo saveInfo(saveDocumentPath.c_str());
if (saveInfo.exists() && !saveInfo.isWritable())
{
QMessageBox::critical(QApplication::activeWindow(), "Error", QString("Document could not be overwritten:\n%1").arg(saveDocumentPath.c_str()));
QMessageBox::critical(
QApplication::activeWindow(),
QObject::tr("Document could not be saved"),
QObject::tr("Document could not be overwritten:\n%1").arg(saveDocumentPath.c_str()));
return false;
}
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
bool result = false;
AtomToolsDocumentRequestBus::EventResult(result, documentId, &AtomToolsDocumentRequestBus::Events::SaveAsChild, saveDocumentPath);
if (!result)
{
QMessageBox::critical(
QApplication::activeWindow(), QString("Document could not be saved"),
QString("Failed to save: \n%1\n\n%2").arg(saveDocumentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
QApplication::activeWindow(),
QObject::tr("Document could not be saved"),
QObject::tr("Failed to save: \n%1\n\n%2").arg(saveDocumentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
return false;
}
return true;
}
bool AtomToolsDocumentSystemComponent::SaveAllDocuments()
bool AtomToolsDocumentSystem::SaveAllDocuments()
{
bool result = true;
for (const auto& documentPair : m_documentMap)
@ -462,12 +361,110 @@ namespace AtomToolsFramework
return result;
}
AZ::u32 AtomToolsDocumentSystemComponent::GetDocumentCount() const
AZ::u32 AtomToolsDocumentSystem::GetDocumentCount() const
{
return aznumeric_cast<AZ::u32>(m_documentMap.size());
}
AZ::Uuid AtomToolsDocumentSystemComponent::OpenDocumentImpl(AZStd::string_view sourcePath, bool checkIfAlreadyOpen)
void AtomToolsDocumentSystem::OnDocumentExternallyModified(const AZ::Uuid& documentId)
{
m_documentIdsWithExternalChanges.insert(documentId);
QueueReopenDocuments();
}
void AtomToolsDocumentSystem::OnDocumentDependencyModified(const AZ::Uuid& documentId)
{
m_documentIdsWithDependencyChanges.insert(documentId);
QueueReopenDocuments();
}
void AtomToolsDocumentSystem::QueueReopenDocuments()
{
if (!m_queueReopenDocuments)
{
m_queueReopenDocuments = true;
QTimer::singleShot(0, [this] { ReopenDocuments(); });
}
}
void AtomToolsDocumentSystem::ReopenDocuments()
{
const bool enableHotReload = GetSettingOrDefault<bool>("/O3DE/AtomToolsFramework/AtomToolsDocumentSystem/EnableHotReload", true);
if (!enableHotReload)
{
m_documentIdsWithDependencyChanges.clear();
m_documentIdsWithExternalChanges.clear();
m_queueReopenDocuments = false;
}
const bool enableHotReloadPrompts =
GetSettingOrDefault<bool>("/O3DE/AtomToolsFramework/AtomToolsDocumentSystem/EnableHotReloadPrompts", true);
for (const AZ::Uuid& documentId : m_documentIdsWithExternalChanges)
{
m_documentIdsWithDependencyChanges.erase(documentId);
AZStd::string documentPath;
AtomToolsDocumentRequestBus::EventResult(documentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
if (enableHotReloadPrompts &&
(QMessageBox::question(QApplication::activeWindow(),
QObject::tr("Document was externally modified"),
QObject::tr("Would you like to reopen the document:\n%1?").arg(documentPath.c_str()),
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes))
{
continue;
}
TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
bool openResult = false;
AtomToolsDocumentRequestBus::EventResult(openResult, documentId, &AtomToolsDocumentRequestBus::Events::Open, documentPath);
if (!openResult)
{
QMessageBox::critical(
QApplication::activeWindow(),
QObject::tr("Document could not be opened"),
QObject::tr("Failed to open: \n%1\n\n%2").arg(documentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
CloseDocument(documentId);
}
}
for (const AZ::Uuid& documentId : m_documentIdsWithDependencyChanges)
{
AZStd::string documentPath;
AtomToolsDocumentRequestBus::EventResult(documentPath, documentId, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
if (enableHotReloadPrompts &&
(QMessageBox::question(QApplication::activeWindow(),
QObject::tr("Document dependencies have changed"),
QObject::tr("Would you like to update the document with these changes:\n%1?").arg(documentPath.c_str()),
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes))
{
continue;
}
TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
bool openResult = false;
AtomToolsDocumentRequestBus::EventResult(openResult, documentId, &AtomToolsDocumentRequestBus::Events::Reopen);
if (!openResult)
{
QMessageBox::critical(
QApplication::activeWindow(),
QObject::tr("Document could not be opened"),
QObject::tr("Failed to open: \n%1\n\n%2").arg(documentPath.c_str()).arg(traceRecorder.GetDump().c_str()));
CloseDocument(documentId);
}
}
m_documentIdsWithDependencyChanges.clear();
m_documentIdsWithExternalChanges.clear();
m_queueReopenDocuments = false;
}
AZ::Uuid AtomToolsDocumentSystem::OpenDocumentImpl(AZStd::string_view sourcePath, bool checkIfAlreadyOpen)
{
AZStd::string requestedPath = sourcePath;
if (requestedPath.empty())
@ -477,7 +474,9 @@ namespace AtomToolsFramework
if (!AzFramework::StringFunc::Path::Normalize(requestedPath))
{
QMessageBox::critical(QApplication::activeWindow(), "Error", QString("Document path is invalid:\n%1").arg(requestedPath.c_str()));
QMessageBox::critical(QApplication::activeWindow(),
QObject::tr("Document could not be opened"),
QObject::tr("Document path is invalid:\n%1").arg(requestedPath.c_str()));
return AZ::Uuid::CreateNull();
}
@ -490,21 +489,22 @@ namespace AtomToolsFramework
AtomToolsDocumentRequestBus::EventResult(openDocumentPath, documentPair.first, &AtomToolsDocumentRequestBus::Events::GetAbsolutePath);
if (openDocumentPath == requestedPath)
{
AtomToolsDocumentNotificationBus::Broadcast(&AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentPair.first);
AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsDocumentNotificationBus::Events::OnDocumentOpened, documentPair.first);
return documentPair.first;
}
}
}
AtomToolsFramework::TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
TraceRecorder traceRecorder(m_maxMessageBoxLineCount);
AZ::Uuid documentId = AZ::Uuid::CreateNull();
AtomToolsDocumentSystemRequestBus::BroadcastResult(documentId, &AtomToolsDocumentSystemRequestBus::Events::CreateDocument);
AZ::Uuid documentId = CreateDocument();
if (documentId.IsNull())
{
QMessageBox::critical(
QApplication::activeWindow(), QString("Document could not be created"),
QString("Failed to create: \n%1\n\n%2").arg(requestedPath.c_str()).arg(traceRecorder.GetDump().c_str()));
QApplication::activeWindow(),
QObject::tr("Document could not be opened"),
QObject::tr("Failed to create: \n%1\n\n%2").arg(requestedPath.c_str()).arg(traceRecorder.GetDump().c_str()));
return AZ::Uuid::CreateNull();
}
@ -513,18 +513,20 @@ namespace AtomToolsFramework
if (!openResult)
{
QMessageBox::critical(
QApplication::activeWindow(), QString("Document could not be opened"),
QString("Failed to open: \n%1\n\n%2").arg(requestedPath.c_str()).arg(traceRecorder.GetDump().c_str()));
AtomToolsDocumentSystemRequestBus::Broadcast(&AtomToolsDocumentSystemRequestBus::Events::DestroyDocument, documentId);
QApplication::activeWindow(),
QObject::tr("Document could not be opened"),
QObject::tr("Failed to open: \n%1\n\n%2").arg(requestedPath.c_str()).arg(traceRecorder.GetDump().c_str()));
DestroyDocument(documentId);
return AZ::Uuid::CreateNull();
}
else if (traceRecorder.GetWarningCount(true) > 0)
{
QMessageBox::warning(
QApplication::activeWindow(), QString("Document opened with warnings"),
QString("Warnings encountered: \n%1\n\n%2").arg(requestedPath.c_str()).arg(traceRecorder.GetDump().c_str()));
QApplication::activeWindow(),
QObject::tr("Document opened with warnings"),
QObject::tr("Warnings encountered: \n%1\n\n%2").arg(requestedPath.c_str()).arg(traceRecorder.GetDump().c_str()));
}
return documentId;
}
}
} // namespace AtomToolsFramework

@ -6,8 +6,11 @@
*
*/
#include <Atom/RHI/Factory.h>
#include <AtomToolsFramework/PerformanceMonitor/PerformanceMonitorRequestBus.h>
#include <AtomToolsFramework/Window/AtomToolsMainWindow.h>
#include <AzCore/Name/Name.h>
#include <AzCore/Utils/Utils.h>
#include <AzToolsFramework/API/EditorPythonRunnerRequestsBus.h>
#include <AzToolsFramework/PythonTerminal/ScriptTermDialog.h>
@ -19,11 +22,11 @@
namespace AtomToolsFramework
{
AtomToolsMainWindow::AtomToolsMainWindow(QWidget* parent)
AtomToolsMainWindow::AtomToolsMainWindow(const AZ::Crc32& toolId, QWidget* parent)
: AzQtComponents::DockMainWindow(parent)
, m_toolId(toolId)
, m_advancedDockManager(new AzQtComponents::FancyDocking(this))
{
m_advancedDockManager = new AzQtComponents::FancyDocking(this);
setDockNestingEnabled(true);
setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
@ -42,20 +45,21 @@ namespace AtomToolsFramework
centralWidget->setLayout(centralWidgetLayout);
setCentralWidget(centralWidget);
m_assetBrowser = new AtomToolsFramework::AtomToolsAssetBrowser(this);
m_assetBrowser = new AtomToolsAssetBrowser(this);
AddDockWidget("Asset Browser", m_assetBrowser, Qt::BottomDockWidgetArea, Qt::Horizontal);
AddDockWidget("Python Terminal", new AzToolsFramework::CScriptTermDialog, Qt::BottomDockWidgetArea, Qt::Horizontal);
SetDockWidgetVisible("Python Terminal", false);
SetupMetrics();
UpdateWindowTitle();
resize(1280, 1024);
AtomToolsMainWindowRequestBus::Handler::BusConnect();
AtomToolsMainWindowRequestBus::Handler::BusConnect(m_toolId);
}
AtomToolsMainWindow::~AtomToolsMainWindow()
{
AtomToolsFramework::PerformanceMonitorRequestBus::Broadcast(
&AtomToolsFramework::PerformanceMonitorRequestBus::Handler::SetProfilerEnabled, false);
PerformanceMonitorRequestBus::Broadcast(&PerformanceMonitorRequestBus::Handler::SetProfilerEnabled, false);
AtomToolsMainWindowRequestBus::Handler::BusDisconnect();
}
@ -160,10 +164,12 @@ namespace AtomToolsFramework
m_menuHelp = menuBar()->addMenu("&Help");
m_menuFile->addAction("Run &Python...", [this]() {
const QString script = QFileDialog::getOpenFileName(this, "Run Script", QString(), QString("*.py"));
const QString script = QFileDialog::getOpenFileName(
this, QObject::tr("Run Script"), QString(AZ::Utils::GetProjectPath().c_str()), QString("*.py"));
if (!script.isEmpty())
{
AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilename, script.toUtf8().constData());
AzToolsFramework::EditorPythonRunnerRequestBus::Broadcast(
&AzToolsFramework::EditorPythonRunnerRequestBus::Events::ExecuteByFilename, script.toUtf8().constData());
}
});
@ -213,21 +219,34 @@ namespace AtomToolsFramework
m_metricsTimer.start();
connect(&m_metricsTimer, &QTimer::timeout, this, &AtomToolsMainWindow::UpdateMetrics);
AtomToolsFramework::PerformanceMonitorRequestBus::Broadcast(
&AtomToolsFramework::PerformanceMonitorRequestBus::Handler::SetProfilerEnabled, true);
PerformanceMonitorRequestBus::Broadcast(&PerformanceMonitorRequestBus::Handler::SetProfilerEnabled, true);
UpdateMetrics();
}
void AtomToolsMainWindow::UpdateMetrics()
{
AtomToolsFramework::PerformanceMetrics metrics = {};
AtomToolsFramework::PerformanceMonitorRequestBus::BroadcastResult(
metrics, &AtomToolsFramework::PerformanceMonitorRequestBus::Handler::GetMetrics);
PerformanceMetrics metrics = {};
PerformanceMonitorRequestBus::BroadcastResult(metrics, &PerformanceMonitorRequestBus::Handler::GetMetrics);
m_statusBarCpuTime->setText(tr("CPU Time %1 ms").arg(QString::number(metrics.m_cpuFrameTimeMs, 'f', 2)));
m_statusBarGpuTime->setText(tr("GPU Time %1 ms").arg(QString::number(metrics.m_gpuFrameTimeMs, 'f', 2)));
int frameRate = metrics.m_cpuFrameTimeMs > 0 ? aznumeric_cast<int>(1000 / metrics.m_cpuFrameTimeMs) : 0;
m_statusBarFps->setText(tr("FPS %1").arg(QString::number(frameRate)));
}
void AtomToolsMainWindow::UpdateWindowTitle()
{
AZ::Name apiName = AZ::RHI::Factory::Get().GetName();
if (!apiName.IsEmpty())
{
QString title = QString{ "%1 (%2)" }.arg(QApplication::applicationName()).arg(apiName.GetCStr());
setWindowTitle(title);
}
else
{
AZ_Assert(false, "Render API name not found");
setWindowTitle(QApplication::applicationName());
}
}
} // namespace AtomToolsFramework

@ -6,7 +6,6 @@
*
*/
#include <AtomToolsFramework/Window/AtomToolsMainWindowFactoryRequestBus.h>
#include <AtomToolsFramework/Window/AtomToolsMainWindowRequestBus.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzCore/Serialization/EditContext.h>
@ -25,14 +24,6 @@ namespace AtomToolsFramework
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<AtomToolsMainWindowFactoryRequestBus>("AtomToolsMainWindowFactoryRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "Editor")
->Attribute(AZ::Script::Attributes::Module, "atomtools")
->Event("CreateMainWindow", &AtomToolsMainWindowFactoryRequestBus::Events::CreateMainWindow)
->Event("DestroyMainWindow", &AtomToolsMainWindowFactoryRequestBus::Events::DestroyMainWindow)
;
behaviorContext->EBus<AtomToolsMainWindowRequestBus>("AtomToolsMainWindowRequestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
->Attribute(AZ::Script::Attributes::Category, "Editor")

@ -15,6 +15,7 @@ set(FILES
Include/AtomToolsFramework/Communication/LocalSocket.h
Include/AtomToolsFramework/Debug/TraceRecorder.h
Include/AtomToolsFramework/Document/AtomToolsDocument.h
Include/AtomToolsFramework/Document/AtomToolsDocumentSystem.h
Include/AtomToolsFramework/Document/AtomToolsDocumentApplication.h
Include/AtomToolsFramework/Document/AtomToolsDocumentMainWindow.h
Include/AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h
@ -38,7 +39,6 @@ set(FILES
Include/AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h
Include/AtomToolsFramework/Window/AtomToolsMainWindow.h
Include/AtomToolsFramework/Window/AtomToolsMainWindowRequestBus.h
Include/AtomToolsFramework/Window/AtomToolsMainWindowFactoryRequestBus.h
Include/AtomToolsFramework/Window/AtomToolsMainWindowNotificationBus.h
Source/Application/AtomToolsApplication.cpp
Source/AssetBrowser/AtomToolsAssetBrowser.cpp
@ -53,8 +53,7 @@ set(FILES
Source/Document/AtomToolsDocument.cpp
Source/Document/AtomToolsDocumentApplication.cpp
Source/Document/AtomToolsDocumentMainWindow.cpp
Source/Document/AtomToolsDocumentSystemComponent.cpp
Source/Document/AtomToolsDocumentSystemComponent.h
Source/Document/AtomToolsDocumentSystem.cpp
Source/DynamicProperty/DynamicProperty.cpp
Source/DynamicProperty/DynamicPropertyGroup.cpp
Source/Inspector/InspectorWidget.cpp

@ -21,8 +21,8 @@
namespace MaterialEditor
{
MaterialDocument::MaterialDocument()
: AtomToolsFramework::AtomToolsDocument()
MaterialDocument::MaterialDocument(const AZ::Crc32& toolId)
: AtomToolsFramework::AtomToolsDocument(toolId)
{
MaterialDocumentRequestBus::Handler::BusConnect(m_id);
}
@ -86,12 +86,12 @@ namespace MaterialEditor
}
}
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentObjectInfoChanged, m_id,
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentObjectInfoChanged, m_id,
GetObjectInfoFromDynamicPropertyGroup(group.get()), false);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentModified, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentModified, m_id);
return false;
}
}
@ -826,8 +826,8 @@ namespace MaterialEditor
if (groupChange || groupRebuilt)
{
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentObjectInfoChanged, m_id,
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentObjectInfoChanged, m_id,
GetObjectInfoFromDynamicPropertyGroup(group.get()), groupRebuilt);
}
return true;

@ -31,9 +31,9 @@ namespace MaterialEditor
public:
AZ_RTTI(MaterialDocument, "{DBA269AE-892B-415C-8FA1-166B94B0E045}");
AZ_CLASS_ALLOCATOR(MaterialDocument, AZ::SystemAllocator, 0);
AZ_DISABLE_COPY(MaterialDocument);
AZ_DISABLE_COPY_MOVE(MaterialDocument);
MaterialDocument();
MaterialDocument(const AZ::Crc32& toolId);
virtual ~MaterialDocument();
// AtomToolsFramework::AtomToolsDocument overrides...

@ -42,24 +42,26 @@ void InitMaterialEditorResources()
namespace MaterialEditor
{
static const char* GetBuildTargetName()
{
#if !defined(LY_CMAKE_TARGET)
#error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target"
#endif
return LY_CMAKE_TARGET;
}
MaterialEditorApplication::MaterialEditorApplication(int* argc, char*** argv)
: Base(argc, argv)
: Base(GetBuildTargetName(), argc, argv)
{
InitMaterialEditorResources();
QApplication::setApplicationName("O3DE Material Editor");
// The settings registry has been created at this point, so add the CMake target
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(
*AZ::SettingsRegistry::Get(), GetBuildTargetName());
AzToolsFramework::EditorWindowRequestBus::Handler::BusConnect();
AtomToolsFramework::AtomToolsMainWindowFactoryRequestBus::Handler::BusConnect();
}
MaterialEditorApplication::~MaterialEditorApplication()
{
AtomToolsFramework::AtomToolsMainWindowFactoryRequestBus::Handler::BusDisconnect();
AzToolsFramework::EditorWindowRequestBus::Handler::BusDisconnect();
m_window.reset();
}
@ -101,35 +103,20 @@ namespace MaterialEditor
{
Base::StartCommon(systemEntity);
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Handler::RegisterDocumentType,
[]() { return aznew MaterialDocument(); });
}
AZStd::string MaterialEditorApplication::GetBuildTargetName() const
{
#if !defined(LY_CMAKE_TARGET)
#error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target"
#endif
//! Returns the build system target name of "MaterialEditor"
return AZStd::string{ LY_CMAKE_TARGET };
}
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Handler::RegisterDocumentType,
[](const AZ::Crc32& toolId) { return aznew MaterialDocument(toolId); });
AZStd::vector<AZStd::string> MaterialEditorApplication::GetCriticalAssetFilters() const
{
return AZStd::vector<AZStd::string>({ "passes/", "config/", "MaterialEditor/" });
}
m_window.reset(aznew MaterialEditorWindow(m_toolId));
void MaterialEditorApplication::CreateMainWindow()
{
m_window.reset(aznew MaterialEditorWindow);
m_assetBrowserInteractions.reset(aznew AtomToolsFramework::AtomToolsAssetBrowserInteractions);
m_assetBrowserInteractions->RegisterContextMenuActions(
[](const AtomToolsFramework::AtomToolsAssetBrowserInteractions::AssetBrowserEntryVector& entries)
{
return entries.front()->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Source;
},
[]([[maybe_unused]] QWidget* caller, QMenu* menu, const AtomToolsFramework::AtomToolsAssetBrowserInteractions::AssetBrowserEntryVector& entries)
[this]([[maybe_unused]] QWidget* caller, QMenu* menu, const AtomToolsFramework::AtomToolsAssetBrowserInteractions::AssetBrowserEntryVector& entries)
{
const bool isMaterial = AzFramework::StringFunc::Path::IsExtension(
entries.front()->GetFullPath().c_str(), AZ::RPI::MaterialSourceData::Extension);
@ -137,17 +124,17 @@ namespace MaterialEditor
entries.front()->GetFullPath().c_str(), AZ::RPI::MaterialTypeSourceData::Extension);
if (isMaterial || isMaterialType)
{
menu->addAction(QObject::tr("Open"), [entries]()
menu->addAction(QObject::tr("Open"), [entries, this]()
{
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument,
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument,
entries.front()->GetFullPath());
});
const QString createActionName =
isMaterialType ? QObject::tr("Create Material...") : QObject::tr("Create Child Material...");
menu->addAction(createActionName, [entries]()
menu->addAction(createActionName, [entries, this]()
{
const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo(
QString(AZ::Utils::GetProjectPath().c_str()) +
@ -155,8 +142,8 @@ namespace MaterialEditor
AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." +
AZ::RPI::MaterialSourceData::Extension).absoluteFilePath();
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile,
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile,
entries.front()->GetFullPath(),
AtomToolsFramework::GetSaveFileInfo(defaultPath).absoluteFilePath().toUtf8().constData());
});
@ -175,9 +162,9 @@ namespace MaterialEditor
{
return entries.front()->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Folder;
},
[](QWidget* caller, QMenu* menu, const AtomToolsFramework::AtomToolsAssetBrowserInteractions::AssetBrowserEntryVector& entries)
[this](QWidget* caller, QMenu* menu, const AtomToolsFramework::AtomToolsAssetBrowserInteractions::AssetBrowserEntryVector& entries)
{
menu->addAction(QObject::tr("Create Material..."), [caller, entries]()
menu->addAction(QObject::tr("Create Material..."), [caller, entries, this]()
{
CreateMaterialDialog createDialog(entries.front()->GetFullPath().c_str(), caller);
createDialog.adjustSize();
@ -186,8 +173,8 @@ namespace MaterialEditor
!createDialog.m_materialFileInfo.absoluteFilePath().isEmpty() &&
!createDialog.m_materialTypeFileInfo.absoluteFilePath().isEmpty())
{
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile,
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::CreateDocumentFromFile,
createDialog.m_materialTypeFileInfo.absoluteFilePath().toUtf8().constData(),
createDialog.m_materialFileInfo.absoluteFilePath().toUtf8().constData());
}
@ -195,9 +182,15 @@ namespace MaterialEditor
});
}
void MaterialEditorApplication::DestroyMainWindow()
void MaterialEditorApplication::Destroy()
{
m_window.reset();
Base::Destroy();
}
AZStd::vector<AZStd::string> MaterialEditorApplication::GetCriticalAssetFilters() const
{
return AZStd::vector<AZStd::string>({ "passes/", "config/", "MaterialEditor/" });
}
QWidget* MaterialEditorApplication::GetAppMainWindow()

@ -10,7 +10,6 @@
#include <AtomToolsFramework/AssetBrowser/AtomToolsAssetBrowserInteractions.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentApplication.h>
#include <AtomToolsFramework/Window/AtomToolsMainWindowFactoryRequestBus.h>
#include <AzToolsFramework/API/EditorWindowRequestBus.h>
#include <Window/MaterialEditorWindow.h>
@ -21,7 +20,6 @@ namespace MaterialEditor
class MaterialEditorApplication
: public AtomToolsFramework::AtomToolsDocumentApplication
, private AzToolsFramework::EditorWindowRequestBus::Handler
, private AtomToolsFramework::AtomToolsMainWindowFactoryRequestBus::Handler
{
public:
AZ_TYPE_INFO(MaterialEditor::MaterialEditorApplication, "{30F90CA5-1253-49B5-8143-19CEE37E22BB}");
@ -36,15 +34,11 @@ namespace MaterialEditor
void CreateStaticModules(AZStd::vector<AZ::Module*>& outModules) override;
const char* GetCurrentConfigurationName() const override;
void StartCommon(AZ::Entity* systemEntity) override;
void Destroy() override;
// AtomToolsFramework::AtomToolsApplication overrides...
AZStd::string GetBuildTargetName() const override;
AZStd::vector<AZStd::string> GetCriticalAssetFilters() const override;
// AtomToolsMainWindowFactoryRequestBus::Handler overrides...
void CreateMainWindow() override;
void DestroyMainWindow() override;
// AzToolsFramework::EditorWindowRequests::Bus::Handler
QWidget* GetAppMainWindow() override;

@ -60,9 +60,10 @@ namespace MaterialEditor
{
static constexpr float DepthNear = 0.01f;
MaterialViewportWidget::MaterialViewportWidget(QWidget* parent)
MaterialViewportWidget::MaterialViewportWidget(const AZ::Crc32& toolId, QWidget* parent)
: AtomToolsFramework::RenderViewportWidget(parent)
, m_ui(new Ui::MaterialViewportWidget)
, m_toolId(toolId)
, m_viewportController(AZStd::make_shared<MaterialEditorViewportInputController>())
{
m_ui->setupUi(this);
@ -252,7 +253,7 @@ namespace MaterialEditor
OnFieldOfViewChanged(viewportSettings->m_fieldOfView);
OnDisplayMapperOperationTypeChanged(viewportSettings->m_displayMapperOperationType);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect();
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(m_toolId);
MaterialViewportNotificationBus::Handler::BusConnect();
AZ::TickBus::Handler::BusConnect();
AZ::TransformNotificationBus::MultiHandler::BusConnect(m_cameraEntity->GetId());

@ -57,7 +57,7 @@ namespace MaterialEditor
, public AZ::TransformNotificationBus::MultiHandler
{
public:
MaterialViewportWidget(QWidget* parent = nullptr);
MaterialViewportWidget(const AZ::Crc32& toolId, QWidget* parent = nullptr);
~MaterialViewportWidget();
private:
@ -84,6 +84,8 @@ namespace MaterialEditor
// AZ::TransformNotificationBus::MultiHandler overrides...
void OnTransformChanged(const AZ::Transform&, const AZ::Transform&) override;
const AZ::Crc32 m_toolId = {};
using DirectionalLightHandle = AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle;
AZ::Data::Instance<AZ::RPI::SwapChainPass> m_swapChainPass;

@ -6,7 +6,6 @@
*
*/
#include <Atom/RHI/Factory.h>
#include <Atom/RPI.Edit/Material/MaterialSourceData.h>
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentSystemRequestBus.h>
@ -36,11 +35,9 @@ AZ_POP_DISABLE_WARNING
namespace MaterialEditor
{
MaterialEditorWindow::MaterialEditorWindow(QWidget* parent /* = 0 */)
: Base(parent)
MaterialEditorWindow::MaterialEditorWindow(const AZ::Crc32& toolId, QWidget* parent)
: Base(toolId, parent)
{
resize(1280, 1024);
// Among other things, we need the window wrapper to save the main window size, position, and state
auto mainWindowWrapper =
new AzQtComponents::WindowDecorationWrapper(AzQtComponents::WindowDecorationWrapper::OptionAutoTitleBarButtons);
@ -52,36 +49,24 @@ namespace MaterialEditor
QApplication::setWindowIcon(QIcon(":/Icons/materialeditor.svg"));
AZ::Name apiName = AZ::RHI::Factory::Get().GetName();
if (!apiName.IsEmpty())
{
QString title = QString{ "%1 (%2)" }.arg(QApplication::applicationName()).arg(apiName.GetCStr());
setWindowTitle(title);
}
else
{
AZ_Assert(false, "Render API name not found");
setWindowTitle(QApplication::applicationName());
}
setObjectName("MaterialEditorWindow");
m_toolBar = new MaterialEditorToolBar(this);
m_toolBar->setObjectName("ToolBar");
addToolBar(m_toolBar);
m_materialViewport = new MaterialViewportWidget(centralWidget());
m_materialViewport = new MaterialViewportWidget(m_toolId, centralWidget());
m_materialViewport->setObjectName("Viewport");
m_materialViewport->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
centralWidget()->layout()->addWidget(m_materialViewport);
m_assetBrowser->SetFilterState("", AZ::RPI::StreamingImageAsset::Group, true);
m_assetBrowser->SetFilterState("", AZ::RPI::MaterialAsset::Group, true);
m_assetBrowser->SetOpenHandler([](const AZStd::string& absolutePath) {
m_assetBrowser->SetOpenHandler([this](const AZStd::string& absolutePath) {
if (AzFramework::StringFunc::Path::IsExtension(absolutePath.c_str(), AZ::RPI::MaterialSourceData::Extension))
{
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, absolutePath);
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, absolutePath);
return;
}
@ -93,7 +78,7 @@ namespace MaterialEditor
QDesktopServices::openUrl(QUrl::fromLocalFile(absolutePath.c_str()));
});
AddDockWidget("Inspector", new MaterialInspector, Qt::RightDockWidgetArea, Qt::Vertical);
AddDockWidget("Inspector", new MaterialInspector(m_toolId), Qt::RightDockWidgetArea, Qt::Vertical);
AddDockWidget("Viewport Settings", new ViewportSettingsInspector, Qt::LeftDockWidgetArea, Qt::Vertical);
SetDockWidgetVisible("Viewport Settings", false);

@ -32,7 +32,7 @@ namespace MaterialEditor
using Base = AtomToolsFramework::AtomToolsDocumentMainWindow;
MaterialEditorWindow(QWidget* parent = 0);
MaterialEditorWindow(const AZ::Crc32& toolId, QWidget* parent = 0);
protected:
void ResizeViewportRenderTarget(uint32_t width, uint32_t height) override;

@ -15,13 +15,14 @@
namespace MaterialEditor
{
MaterialInspector::MaterialInspector(QWidget* parent)
MaterialInspector::MaterialInspector(const AZ::Crc32& toolId, QWidget* parent)
: AtomToolsFramework::InspectorWidget(parent)
, m_toolId(toolId)
{
m_windowSettings = AZ::UserSettings::CreateFind<MaterialEditorWindowSettings>(
AZ::Crc32("MaterialEditorWindowSettings"), AZ::UserSettings::CT_GLOBAL);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect();
AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(m_toolId);
}
MaterialInspector::~MaterialInspector()

@ -29,7 +29,7 @@ namespace MaterialEditor
public:
AZ_CLASS_ALLOCATOR(MaterialInspector, AZ::SystemAllocator, 0);
explicit MaterialInspector(QWidget* parent = nullptr);
MaterialInspector(const AZ::Crc32& toolId, QWidget* parent = nullptr);
~MaterialInspector() override;
// AtomToolsFramework::InspectorRequestBus::Handler overrides...
@ -59,6 +59,8 @@ namespace MaterialEditor
void RequestPropertyContextMenu([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode, const QPoint&) override {}
void PropertySelectionChanged([[maybe_unused]] AzToolsFramework::InstanceDataNode* pNode, bool) override {}
const AZ::Crc32 m_toolId = {};
// Tracking the property that is activiley being edited in the inspector
const AtomToolsFramework::DynamicProperty* m_activeProperty = {};

@ -14,8 +14,8 @@
namespace ShaderManagementConsole
{
ShaderManagementConsoleDocument::ShaderManagementConsoleDocument()
: AtomToolsFramework::AtomToolsDocument()
ShaderManagementConsoleDocument::ShaderManagementConsoleDocument(const AZ::Crc32& toolId)
: AtomToolsFramework::AtomToolsDocument(toolId)
{
ShaderManagementConsoleDocumentRequestBus::Handler::BusConnect(m_id);
}
@ -37,8 +37,8 @@ namespace ShaderManagementConsole
AZ_Error("ShaderManagementConsoleDocument", false, "Could not load shader asset: %s.", shaderPath.c_str());
}
AtomToolsFramework::AtomToolsDocumentNotificationBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentModified, m_id);
AtomToolsFramework::AtomToolsDocumentNotificationBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentNotificationBus::Events::OnDocumentModified, m_id);
}
const AZ::RPI::ShaderVariantListSourceData& ShaderManagementConsoleDocument::GetShaderVariantListSourceData() const

@ -24,11 +24,11 @@ namespace ShaderManagementConsole
, public ShaderManagementConsoleDocumentRequestBus::Handler
{
public:
AZ_RTTI(ShaderManagementConsoleDocument, "{DBA269AE-892B-415C-8FA1-166B94B0E045}");
AZ_RTTI(ShaderManagementConsoleDocument, "{504A74BA-F5DD-49E0-BA5E-A381F61DD524}");
AZ_CLASS_ALLOCATOR(ShaderManagementConsoleDocument, AZ::SystemAllocator, 0);
AZ_DISABLE_COPY(ShaderManagementConsoleDocument);
AZ_DISABLE_COPY_MOVE(ShaderManagementConsoleDocument);
ShaderManagementConsoleDocument();
ShaderManagementConsoleDocument(const AZ::Crc32& toolId);
~ShaderManagementConsoleDocument();
// AtomToolsFramework::AtomToolsDocument overrides...

@ -47,27 +47,29 @@ void InitShaderManagementConsoleResources()
namespace ShaderManagementConsole
{
static const char* GetBuildTargetName()
{
#if !defined(LY_CMAKE_TARGET)
#error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target"
#endif
return LY_CMAKE_TARGET;
}
ShaderManagementConsoleApplication::ShaderManagementConsoleApplication(int* argc, char*** argv)
: Base(argc, argv)
: Base(GetBuildTargetName(), argc, argv)
{
InitShaderManagementConsoleResources();
QApplication::setApplicationName("O3DE Shader Management Console");
// The settings registry has been created at this point, so add the CMake target
AZ::SettingsRegistryMergeUtils::MergeSettingsToRegistry_AddBuildSystemTargetSpecialization(
*AZ::SettingsRegistry::Get(), GetBuildTargetName());
ShaderManagementConsoleRequestBus::Handler::BusConnect();
AzToolsFramework::EditorWindowRequestBus::Handler::BusConnect();
AtomToolsFramework::AtomToolsMainWindowFactoryRequestBus::Handler::BusConnect();
}
ShaderManagementConsoleApplication::~ShaderManagementConsoleApplication()
{
ShaderManagementConsoleRequestBus::Handler::BusDisconnect();
AzToolsFramework::EditorWindowRequestBus::Handler::BusDisconnect();
AtomToolsFramework::AtomToolsMainWindowFactoryRequestBus::Handler::BusDisconnect();
m_window.reset();
}
@ -115,40 +117,20 @@ namespace ShaderManagementConsole
{
Base::StartCommon(systemEntity);
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Handler::RegisterDocumentType,
[]() { return aznew ShaderManagementConsoleDocument(); });
}
AZStd::string ShaderManagementConsoleApplication::GetBuildTargetName() const
{
#if !defined(LY_CMAKE_TARGET)
#error "LY_CMAKE_TARGET must be defined in order to add this source file to a CMake executable target"
#endif
//! Returns the build system target name of "ShaderManagementConsole"
return AZStd::string_view{ LY_CMAKE_TARGET };
}
AZStd::vector<AZStd::string> ShaderManagementConsoleApplication::GetCriticalAssetFilters() const
{
return AZStd::vector<AZStd::string>({ "passes/", "config/" });
}
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Handler::RegisterDocumentType,
[](const AZ::Crc32& toolId) { return aznew ShaderManagementConsoleDocument(toolId); });
QWidget* ShaderManagementConsoleApplication::GetAppMainWindow()
{
return m_window.get();
}
m_window.reset(aznew ShaderManagementConsoleWindow(m_toolId));
void ShaderManagementConsoleApplication::CreateMainWindow()
{
m_window.reset(aznew ShaderManagementConsoleWindow);
m_assetBrowserInteractions.reset(aznew AtomToolsFramework::AtomToolsAssetBrowserInteractions);
m_assetBrowserInteractions->RegisterContextMenuActions(
[](const AtomToolsFramework::AtomToolsAssetBrowserInteractions::AssetBrowserEntryVector& entries)
{
return entries.front()->GetEntryType() == AzToolsFramework::AssetBrowser::AssetBrowserEntry::AssetEntryType::Source;
},
[]([[maybe_unused]] QWidget* caller, QMenu* menu, const AtomToolsFramework::AtomToolsAssetBrowserInteractions::AssetBrowserEntryVector& entries)
[this]([[maybe_unused]] QWidget* caller, QMenu* menu, const AtomToolsFramework::AtomToolsAssetBrowserInteractions::AssetBrowserEntryVector& entries)
{
if (AzFramework::StringFunc::Path::IsExtension(
entries.front()->GetFullPath().c_str(), AZ::RPI::ShaderSourceData::Extension))
@ -166,10 +148,10 @@ namespace ShaderManagementConsole
else if (AzFramework::StringFunc::Path::IsExtension(
entries.front()->GetFullPath().c_str(), AZ::RPI::ShaderVariantListSourceData::Extension))
{
menu->addAction(QObject::tr("Open"), [entries]()
menu->addAction(QObject::tr("Open"), [entries, this]()
{
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument,
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument,
entries.front()->GetFullPath());
});
}
@ -183,9 +165,20 @@ namespace ShaderManagementConsole
});
}
void ShaderManagementConsoleApplication::DestroyMainWindow()
void ShaderManagementConsoleApplication::Destroy()
{
m_window.reset();
Base::Destroy();
}
AZStd::vector<AZStd::string> ShaderManagementConsoleApplication::GetCriticalAssetFilters() const
{
return AZStd::vector<AZStd::string>({ "passes/", "config/" });
}
QWidget* ShaderManagementConsoleApplication::GetAppMainWindow()
{
return m_window.get();
}
AZ::Data::AssetInfo ShaderManagementConsoleApplication::GetSourceAssetInfo(const AZStd::string& sourceAssetFileName)

@ -11,7 +11,6 @@
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <AtomToolsFramework/AssetBrowser/AtomToolsAssetBrowserInteractions.h>
#include <AtomToolsFramework/Document/AtomToolsDocumentApplication.h>
#include <AtomToolsFramework/Window/AtomToolsMainWindowFactoryRequestBus.h>
#include <AzToolsFramework/API/EditorWindowRequestBus.h>
#include <ShaderManagementConsoleRequestBus.h>
#include <Window/ShaderManagementConsoleWindow.h>
@ -21,7 +20,6 @@ namespace ShaderManagementConsole
class ShaderManagementConsoleApplication
: public AtomToolsFramework::AtomToolsDocumentApplication
, private ShaderManagementConsoleRequestBus::Handler
, private AtomToolsFramework::AtomToolsMainWindowFactoryRequestBus::Handler
, private AzToolsFramework::EditorWindowRequestBus::Handler
{
public:
@ -36,18 +34,14 @@ namespace ShaderManagementConsole
void Reflect(AZ::ReflectContext* context) override;
const char* GetCurrentConfigurationName() const override;
void StartCommon(AZ::Entity* systemEntity) override;
void Destroy() override;
// AtomToolsFramework::AtomToolsApplication overrides...
AZStd::string GetBuildTargetName() const override;
AZStd::vector<AZStd::string> GetCriticalAssetFilters() const override;
// AzToolsFramework::EditorWindowRequests::Bus::Handler
QWidget* GetAppMainWindow() override;
// AtomToolsMainWindowFactoryRequestBus::Handler overrides...
void CreateMainWindow() override;
void DestroyMainWindow() override;
// ShaderManagementConsoleRequestBus::Handler overrides...
AZ::Data::AssetInfo GetSourceAssetInfo(const AZStd::string& sourceAssetFileName) override;
AZStd::vector<AZ::Data::AssetId> FindMaterialAssetsUsingShader(const AZStd::string& shaderFilePath) override;

@ -26,11 +26,9 @@ AZ_POP_DISABLE_WARNING
namespace ShaderManagementConsole
{
ShaderManagementConsoleWindow::ShaderManagementConsoleWindow(QWidget* parent /* = 0 */)
: Base(parent)
ShaderManagementConsoleWindow::ShaderManagementConsoleWindow(const AZ::Crc32& toolId, QWidget* parent)
: Base(toolId, parent)
{
resize(1280, 1024);
// Among other things, we need the window wrapper to save the main window size, position, and state
auto mainWindowWrapper =
new AzQtComponents::WindowDecorationWrapper(AzQtComponents::WindowDecorationWrapper::OptionAutoTitleBarButtons);
@ -42,11 +40,11 @@ namespace ShaderManagementConsole
setObjectName("ShaderManagementConsoleWindow");
m_assetBrowser->SetFilterState("", AZ::RPI::ShaderAsset::Group, true);
m_assetBrowser->SetOpenHandler([](const AZStd::string& absolutePath) {
m_assetBrowser->SetOpenHandler([this](const AZStd::string& absolutePath) {
if (AzFramework::StringFunc::Path::IsExtension(absolutePath.c_str(), AZ::RPI::ShaderVariantListSourceData::Extension))
{
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Broadcast(
&AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, absolutePath);
AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Event(
m_toolId, &AtomToolsFramework::AtomToolsDocumentSystemRequestBus::Events::OpenDocument, absolutePath);
return;
}

@ -31,7 +31,7 @@ namespace ShaderManagementConsole
using Base = AtomToolsFramework::AtomToolsDocumentMainWindow;
ShaderManagementConsoleWindow(QWidget* parent = 0);
ShaderManagementConsoleWindow(const AZ::Crc32& toolId, QWidget* parent = 0);
~ShaderManagementConsoleWindow() = default;
protected:

Loading…
Cancel
Save