Merge pull request #7570 from aws-lumberyard-dev/Atom/guthadam/atom_tools_document_and_window_buses_support_multiple_instances

Atom Tools: updated document and windows systems and buses to support multiple instances
monroegm-disable-blank-issue-2
Guthrie Adams 4 years ago committed by GitHub
commit 9e32c83d30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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 int updateIntervalWhenActive =
aznumeric_cast<int>(GetSettingOrDefault<AZ::u64>("/O3DE/AtomToolsFramework/Application/UpdateIntervalWhenActive", 1));
const int updateIntervalWhenNotActive =
aznumeric_cast<int>(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,14 +398,11 @@ 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");
ExitMainLoop();
});
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();
});
}
// Process command line options for running one or more python scripts on startup
@ -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()
{
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::ExitMainLoop);
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,25 +202,29 @@ namespace AtomToolsFramework
AZ_UNUSED(time);
AZ_UNUSED(deltaTime);
if (!m_pathToSelect.empty())
if (m_pathToSelect.empty())
{
// Attempt to select the new path
AzToolsFramework::AssetBrowser::AssetBrowserViewRequestBus::Broadcast(
&AzToolsFramework::AssetBrowser::AssetBrowserViewRequestBus::Events::SelectFileAtPath, m_pathToSelect);
AZ::TickBus::Handler::BusDisconnect();
m_pathToSelect.clear();
return;
}
// Iterate over the selected entries to verify if the selection was made
for (const AssetBrowserEntry* entry : m_ui->m_assetBrowserTreeViewWidget->GetSelectedAssets())
// Attempt to select the new path
AzToolsFramework::AssetBrowser::AssetBrowserViewRequestBus::Broadcast(
&AzToolsFramework::AssetBrowser::AssetBrowserViewRequestBus::Events::SelectFileAtPath, m_pathToSelect);
// Iterate over the selected entries to verify if the selection was made
for (const AssetBrowserEntry* entry : m_ui->m_assetBrowserTreeViewWidget->GetSelectedAssets())
{
if (entry)
{
if (entry)
AZStd::string sourcePath = entry->GetFullPath();
AzFramework::StringFunc::Path::Normalize(sourcePath);
if (m_pathToSelect == sourcePath)
{
AZStd::string sourcePath = entry->GetFullPath();
AzFramework::StringFunc::Path::Normalize(sourcePath);
if (m_pathToSelect == sourcePath)
{
// Once the selection is confirmed, cancel the operation and disconnect
AZ::TickBus::Handler::BusDisconnect();
m_pathToSelect.clear();
}
// Once the selection is confirmed, cancel the operation and disconnect
AZ::TickBus::Handler::BusDisconnect();
m_pathToSelect.clear();
}
}
}

@ -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

@ -22,8 +22,8 @@
namespace MaterialEditor
{
MaterialDocument::MaterialDocument()
: AtomToolsFramework::AtomToolsDocument()
MaterialDocument::MaterialDocument(const AZ::Crc32& toolId)
: AtomToolsFramework::AtomToolsDocument(toolId)
{
MaterialDocumentRequestBus::Handler::BusConnect(m_id);
}
@ -87,12 +87,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;
}
}
@ -845,8 +845,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