Merge pull request #120 from aws-lumberyard-dev/Atom/mnaumov/ATOM-14073

[ATOM-14073] Double click launches Material Editor
This commit is contained in:
AMZN-mnaumov
2021-04-21 20:18:02 -07:00
committed by GitHub
11 changed files with 481 additions and 384 deletions
@@ -1,375 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <QApplication>
#include <QClipboard>
#include <QMenu>
#include <QInputDialog>
#include <QMessageBox>
#include <QFileDialog>
#include <QDesktopServices>
#include <AzQtComponents/Utilities/DesktopUtilities.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <AzToolsFramework/Thumbnails/SourceControlThumbnail.h>
#include <AtomToolsFramework/Util/Util.h>
#include <Atom/Document/MaterialDocumentSystemRequestBus.h>
#include <Source/Window/MaterialBrowserInteractions.h>
#include <Window/CreateMaterialDialog/CreateMaterialDialog.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Edit/Material/MaterialSourceData.h>
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
namespace MaterialEditor
{
MaterialBrowserInteractions::MaterialBrowserInteractions()
{
using namespace AzToolsFramework::AssetBrowser;
AssetBrowserInteractionNotificationBus::Handler::BusConnect();
}
MaterialBrowserInteractions::~MaterialBrowserInteractions()
{
AssetBrowserInteractionNotificationBus::Handler::BusDisconnect();
}
void MaterialBrowserInteractions::AddContextMenuActions(QWidget* caller, QMenu* menu, const AZStd::vector<AzToolsFramework::AssetBrowser::AssetBrowserEntry*>& entries)
{
AssetBrowserEntry* entry = entries.empty() ? nullptr : entries.front();
if (!entry)
{
return;
}
m_caller = caller;
QObject::connect(m_caller, &QObject::destroyed, [this]()
{
m_caller = nullptr;
});
AddGenericContextMenuActions(caller, menu, entry);
if (entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Source)
{
const auto source = azalias_cast<const SourceAssetBrowserEntry*>(entry);
if (AzFramework::StringFunc::Path::IsExtension(entry->GetFullPath().c_str(), MaterialExtension))
{
AddContextMenuActionsForMaterialSource(caller, menu, source);
}
else if (AzFramework::StringFunc::Path::IsExtension(entry->GetFullPath().c_str(), MaterialTypeExtension))
{
AddContextMenuActionsForMaterialTypeSource(caller, menu, source);
}
else
{
AddContextMenuActionsForOtherSource(caller, menu, source);
}
}
else if (entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Folder)
{
const auto folder = azalias_cast<const FolderAssetBrowserEntry*>(entry);
AddContextMenuActionsForFolder(caller, menu, folder);
}
}
void MaterialBrowserInteractions::AddGenericContextMenuActions([[maybe_unused]] QWidget* caller, QMenu* menu, const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry)
{
menu->addAction(QObject::tr("Copy Name To Clipboard"), [=]()
{
QApplication::clipboard()->setText(entry->GetName().c_str());
});
menu->addAction(QObject::tr("Copy Path To Clipboard"), [=]()
{
QApplication::clipboard()->setText(entry->GetFullPath().c_str());
});
}
void MaterialBrowserInteractions::AddContextMenuActionsForMaterialTypeSource(QWidget* caller, QMenu* menu, const AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry* entry)
{
menu->addAction(AzQtComponents::fileBrowserActionName(), [entry]()
{
AzQtComponents::ShowFileOnDesktop(entry->GetFullPath().c_str());
});
menu->addSeparator();
menu->addAction("Create Material...", [entry]()
{
const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo(
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) +
AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" +
AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." +
AZ::RPI::MaterialSourceData::Extension).absoluteFilePath();
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CreateDocumentFromFile,
entry->GetFullPath(), AtomToolsFramework::GetSaveFileInfo(defaultPath).absoluteFilePath().toUtf8().constData());
});
AddPerforceMenuActions(caller, menu, entry);
}
void MaterialBrowserInteractions::AddContextMenuActionsForOtherSource(QWidget* caller, QMenu* menu, const AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry* entry)
{
menu->addAction("Open", [entry]()
{
QDesktopServices::openUrl(QUrl::fromLocalFile(entry->GetFullPath().c_str()));
});
menu->addAction("Duplicate...", [entry, caller]()
{
const QFileInfo duplicateFileInfo(AtomToolsFramework::GetDuplicationFileInfo(entry->GetFullPath().c_str()));
if (!duplicateFileInfo.absoluteFilePath().isEmpty())
{
if (QFile::copy(entry->GetFullPath().c_str(), duplicateFileInfo.absoluteFilePath()))
{
QFile::setPermissions(duplicateFileInfo.absoluteFilePath(), QFile::ReadOther | QFile::WriteOther);
// Auto add file to source control
AzToolsFramework::SourceControlCommandBus::Broadcast(&AzToolsFramework::SourceControlCommandBus::Events::RequestEdit,
duplicateFileInfo.absoluteFilePath().toUtf8().constData(), true, [](bool, const AzToolsFramework::SourceControlFileInfo&) {});
}
}
});
menu->addAction(AzQtComponents::fileBrowserActionName(), [entry]()
{
AzQtComponents::ShowFileOnDesktop(entry->GetFullPath().c_str());
});
AddPerforceMenuActions(caller, menu, entry);
}
void MaterialBrowserInteractions::AddContextMenuActionsForMaterialSource(QWidget* caller, QMenu* menu, const AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry* entry)
{
menu->addAction("Open", [entry]()
{
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::OpenDocument, entry->GetFullPath());
});
menu->addAction("Duplicate...", [entry, caller]()
{
const QFileInfo duplicateFileInfo(AtomToolsFramework::GetDuplicationFileInfo(entry->GetFullPath().c_str()));
if (!duplicateFileInfo.absoluteFilePath().isEmpty())
{
if (QFile::copy(entry->GetFullPath().c_str(), duplicateFileInfo.absoluteFilePath()))
{
QFile::setPermissions(duplicateFileInfo.absoluteFilePath(), QFile::ReadOther | QFile::WriteOther);
// Auto add file to source control
AzToolsFramework::SourceControlCommandBus::Broadcast(&AzToolsFramework::SourceControlCommandBus::Events::RequestEdit,
duplicateFileInfo.absoluteFilePath().toUtf8().constData(), true, [](bool, const AzToolsFramework::SourceControlFileInfo&) {});
}
}
});
menu->addAction(AzQtComponents::fileBrowserActionName(), [entry]()
{
AzQtComponents::ShowFileOnDesktop(entry->GetFullPath().c_str());
});
menu->addSeparator();
menu->addAction("Create Child Material...", [entry]()
{
const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo(
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) +
AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" +
AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." +
AZ::RPI::MaterialSourceData::Extension).absoluteFilePath();
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CreateDocumentFromFile,
entry->GetFullPath(), AtomToolsFramework::GetSaveFileInfo(defaultPath).absoluteFilePath().toUtf8().constData());
});
menu->addSeparator();
QAction* openParentAction = menu->addAction("Open Parent Material", [entry]()
{
AZ_UNUSED(entry);
// ToDo
});
openParentAction->setEnabled(false);
AddPerforceMenuActions(caller, menu, entry);
}
void MaterialBrowserInteractions::AddContextMenuActionsForFolder(QWidget* caller, QMenu* menu, const AzToolsFramework::AssetBrowser::FolderAssetBrowserEntry* entry)
{
menu->addAction(AzQtComponents::fileBrowserActionName(), [entry]()
{
AzQtComponents::ShowFileOnDesktop(entry->GetFullPath().c_str());
});
QAction* createFolderAction = menu->addAction(QObject::tr("Create new sub folder..."));
QObject::connect(createFolderAction, &QAction::triggered, caller, [caller, entry]()
{
bool ok;
QString newFolderName = QInputDialog::getText(caller, "Enter new folder name", "name:", QLineEdit::Normal, "NewFolder", &ok);
if (ok)
{
if (newFolderName.isEmpty())
{
QMessageBox msgBox(QMessageBox::Icon::Critical, "Error", "Folder name can't be empty", QMessageBox::Ok, caller);
msgBox.exec();
}
else
{
AZStd::string newFolderPath;
AzFramework::StringFunc::Path::Join(entry->GetFullPath().c_str(), newFolderName.toUtf8().constData(), newFolderPath);
QDir dir(newFolderPath.c_str());
if (dir.exists())
{
QMessageBox::critical(caller, "Error", "Folder with this name already exists");
return;
}
auto result = dir.mkdir(newFolderPath.c_str());
if (!result)
{
AZ_Error("MaterialBrowser", false, "Failed to make new folder");
return;
}
}
}
});
menu->addSeparator();
QAction* createMaterialAction = menu->addAction(QObject::tr("Create Material..."));
QObject::connect(createMaterialAction, &QAction::triggered, caller, [caller, entry]()
{
CreateMaterialDialog createDialog(entry->GetFullPath().c_str(), caller);
createDialog.adjustSize();
if (createDialog.exec() == QDialog::Accepted &&
!createDialog.m_materialFileInfo.absoluteFilePath().isEmpty() &&
!createDialog.m_materialTypeFileInfo.absoluteFilePath().isEmpty())
{
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CreateDocumentFromFile,
createDialog.m_materialTypeFileInfo.absoluteFilePath().toUtf8().constData(),
createDialog.m_materialFileInfo.absoluteFilePath().toUtf8().constData());
}
});
}
void MaterialBrowserInteractions::AddPerforceMenuActions([[maybe_unused]] QWidget* caller, QMenu* menu, const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry)
{
using namespace AzToolsFramework;
bool isActive = false;
SourceControlConnectionRequestBus::BroadcastResult(isActive, &SourceControlConnectionRequests::IsActive);
if (isActive)
{
menu->addSeparator();
AZStd::string path = entry->GetFullPath();
AzFramework::StringFunc::Path::Normalize(path);
QMenu* sourceControlMenu = menu->addMenu("Source Control");
// Update the enabled state of source control menu actions only if menu is shown
QMenu::connect(sourceControlMenu, &QMenu::aboutToShow, [this, path]()
{
SourceControlCommandBus::Broadcast(&SourceControlCommandBus::Events::GetFileInfo, path.c_str(),
[this](bool success, const SourceControlFileInfo& info) { UpdateSourceControlActions(success, info); });
});
// add get latest action
m_getLatestAction = sourceControlMenu->addAction("Get Latest", [path, this]()
{
SourceControlCommandBus::Broadcast(&SourceControlCommandBus::Events::RequestLatest, path.c_str(),
[](bool, const SourceControlFileInfo&) {});
});
QObject::connect(m_getLatestAction, &QObject::destroyed, [this]()
{
m_getLatestAction = nullptr;
});
m_getLatestAction->setEnabled(false);
// add add action
m_addAction = sourceControlMenu->addAction("Add", [path]()
{
SourceControlCommandBus::Broadcast(&SourceControlCommandBus::Events::RequestEdit, path.c_str(), true,
[path](bool, const SourceControlFileInfo&)
{
SourceControlThumbnailRequestBus::Broadcast(&SourceControlThumbnailRequests::FileStatusChanged, path.c_str());
});
});
QObject::connect(m_addAction, &QObject::destroyed, [this]()
{
m_addAction = nullptr;
});
m_addAction->setEnabled(false);
// add checkout action
m_checkOutAction = sourceControlMenu->addAction("Check Out", [path]()
{
SourceControlCommandBus::Broadcast(&SourceControlCommandBus::Events::RequestEdit, path.c_str(), true,
[path](bool, const SourceControlFileInfo&)
{
SourceControlThumbnailRequestBus::Broadcast(&SourceControlThumbnailRequests::FileStatusChanged, path.c_str());
});
});
QObject::connect(m_checkOutAction, &QObject::destroyed, [this]()
{
m_checkOutAction = nullptr;
});
m_checkOutAction->setEnabled(false);
// add undo checkout action
m_undoCheckOutAction = sourceControlMenu->addAction("Undo Check Out", [path]()
{
SourceControlCommandBus::Broadcast(&SourceControlCommandBus::Events::RequestRevert, path.c_str(),
[path](bool, const SourceControlFileInfo&)
{
SourceControlThumbnailRequestBus::Broadcast(&SourceControlThumbnailRequests::FileStatusChanged, path.c_str());
});
});
QObject::connect(m_undoCheckOutAction, &QObject::destroyed, [this]()
{
m_undoCheckOutAction = nullptr;
});
m_undoCheckOutAction->setEnabled(false);
}
}
void MaterialBrowserInteractions::UpdateSourceControlActions(bool success, AzToolsFramework::SourceControlFileInfo info)
{
if (!success && m_caller)
{
QMessageBox::critical(m_caller, "Error", "Source control operation failed.");
}
if (m_getLatestAction)
{
m_getLatestAction->setEnabled(info.IsManaged() && info.HasFlag(AzToolsFramework::SCF_OutOfDate));
}
if (m_addAction)
{
m_addAction->setEnabled(!info.IsManaged());
}
if (m_checkOutAction)
{
m_checkOutAction->setEnabled(info.IsManaged() && info.IsReadOnly() && !info.IsLockedByOther());
}
if (m_undoCheckOutAction)
{
m_undoCheckOutAction->setEnabled(info.IsManaged() && !info.IsReadOnly());
}
}
} // namespace MaterialEditor
@@ -0,0 +1,358 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <QApplication>
#include <QClipboard>
#include <QMenu>
#include <QInputDialog>
#include <QMessageBox>
#include <QFileDialog>
#include <QDesktopServices>
#include <AzCore/std/string/wildcard.h>
#include <AzQtComponents/Utilities/DesktopUtilities.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <AzToolsFramework/Thumbnails/SourceControlThumbnail.h>
#include <AtomToolsFramework/Util/Util.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/Document/MaterialDocumentSystemRequestBus.h>
#include <WIndow/MaterialEditorBrowserInteractions.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Edit/Material/MaterialSourceData.h>
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
namespace MaterialEditor
{
MaterialEditorBrowserInteractions::MaterialEditorBrowserInteractions()
{
using namespace AzToolsFramework::AssetBrowser;
AssetBrowserInteractionNotificationBus::Handler::BusConnect();
}
MaterialEditorBrowserInteractions::~MaterialEditorBrowserInteractions()
{
AssetBrowserInteractionNotificationBus::Handler::BusDisconnect();
}
void MaterialEditorBrowserInteractions::AddContextMenuActions(QWidget* caller, QMenu* menu, const AZStd::vector<AzToolsFramework::AssetBrowser::AssetBrowserEntry*>& entries)
{
AssetBrowserEntry* entry = entries.empty() ? nullptr : entries.front();
if (!entry)
{
return;
}
m_caller = caller;
QObject::connect(m_caller, &QObject::destroyed, [this]()
{
m_caller = nullptr;
});
AddGenericContextMenuActions(caller, menu, entry);
if (entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Source)
{
const auto source = azalias_cast<const SourceAssetBrowserEntry*>(entry);
if (AzFramework::StringFunc::Path::IsExtension(entry->GetFullPath().c_str(), MaterialExtension))
{
AddContextMenuActionsForMaterialSource(caller, menu, source);
}
else if (AzFramework::StringFunc::Path::IsExtension(entry->GetFullPath().c_str(), MaterialTypeExtension))
{
AddContextMenuActionsForMaterialTypeSource(caller, menu, source);
}
else
{
AddContextMenuActionsForOtherSource(caller, menu, source);
}
}
else if (entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Folder)
{
const auto folder = azalias_cast<const FolderAssetBrowserEntry*>(entry);
AddContextMenuActionsForFolder(caller, menu, folder);
}
}
void MaterialEditorBrowserInteractions::AddGenericContextMenuActions([[maybe_unused]] QWidget* caller, QMenu* menu, const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry)
{
menu->addAction(QObject::tr("Copy Name To Clipboard"), [=]()
{
QApplication::clipboard()->setText(entry->GetName().c_str());
});
menu->addAction(QObject::tr("Copy Path To Clipboard"), [=]()
{
QApplication::clipboard()->setText(entry->GetFullPath().c_str());
});
}
void MaterialEditorBrowserInteractions::AddContextMenuActionsForMaterialTypeSource(QWidget* caller, QMenu* menu, const AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry* entry)
{
menu->addAction(AzQtComponents::fileBrowserActionName(), [entry]()
{
AzQtComponents::ShowFileOnDesktop(entry->GetFullPath().c_str());
});
menu->addSeparator();
menu->addAction("Create Material...", [entry]()
{
const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo(
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) +
AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" +
AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." +
AZ::RPI::MaterialSourceData::Extension).absoluteFilePath();
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CreateDocumentFromFile,
entry->GetFullPath(), AtomToolsFramework::GetSaveFileInfo(defaultPath).absoluteFilePath().toUtf8().constData());
});
AddPerforceMenuActions(caller, menu, entry);
}
void MaterialEditorBrowserInteractions::AddContextMenuActionsForOtherSource(QWidget* caller, QMenu* menu, const AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry* entry)
{
menu->addAction("Open", [entry]()
{
QDesktopServices::openUrl(QUrl::fromLocalFile(entry->GetFullPath().c_str()));
});
menu->addAction("Duplicate...", [entry, caller]()
{
const QFileInfo duplicateFileInfo(AtomToolsFramework::GetDuplicationFileInfo(entry->GetFullPath().c_str()));
if (!duplicateFileInfo.absoluteFilePath().isEmpty())
{
if (QFile::copy(entry->GetFullPath().c_str(), duplicateFileInfo.absoluteFilePath()))
{
QFile::setPermissions(duplicateFileInfo.absoluteFilePath(), QFile::ReadOther | QFile::WriteOther);
// Auto add file to source control
AzToolsFramework::SourceControlCommandBus::Broadcast(&AzToolsFramework::SourceControlCommandBus::Events::RequestEdit,
duplicateFileInfo.absoluteFilePath().toUtf8().constData(), true, [](bool, const AzToolsFramework::SourceControlFileInfo&) {});
}
}
});
menu->addAction(AzQtComponents::fileBrowserActionName(), [entry]()
{
AzQtComponents::ShowFileOnDesktop(entry->GetFullPath().c_str());
});
AddPerforceMenuActions(caller, menu, entry);
}
void MaterialEditorBrowserInteractions::AddContextMenuActionsForMaterialSource(QWidget* caller, QMenu* menu, const AzToolsFramework::AssetBrowser::SourceAssetBrowserEntry* entry)
{
menu->addAction("Open", [entry]()
{
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::OpenDocument, entry->GetFullPath());
});
menu->addAction("Duplicate...", [entry, caller]()
{
const QFileInfo duplicateFileInfo(AtomToolsFramework::GetDuplicationFileInfo(entry->GetFullPath().c_str()));
if (!duplicateFileInfo.absoluteFilePath().isEmpty())
{
if (QFile::copy(entry->GetFullPath().c_str(), duplicateFileInfo.absoluteFilePath()))
{
QFile::setPermissions(duplicateFileInfo.absoluteFilePath(), QFile::ReadOther | QFile::WriteOther);
// Auto add file to source control
AzToolsFramework::SourceControlCommandBus::Broadcast(&AzToolsFramework::SourceControlCommandBus::Events::RequestEdit,
duplicateFileInfo.absoluteFilePath().toUtf8().constData(), true, [](bool, const AzToolsFramework::SourceControlFileInfo&) {});
}
}
});
menu->addAction(AzQtComponents::fileBrowserActionName(), [entry]()
{
AzQtComponents::ShowFileOnDesktop(entry->GetFullPath().c_str());
});
menu->addSeparator();
menu->addAction("Create Child Material...", [entry]()
{
const QString defaultPath = AtomToolsFramework::GetUniqueFileInfo(
QString(AZ::IO::FileIOBase::GetInstance()->GetAlias("@devassets@")) +
AZ_CORRECT_FILESYSTEM_SEPARATOR + "Materials" +
AZ_CORRECT_FILESYSTEM_SEPARATOR + "untitled." +
AZ::RPI::MaterialSourceData::Extension).absoluteFilePath();
MaterialDocumentSystemRequestBus::Broadcast(&MaterialDocumentSystemRequestBus::Events::CreateDocumentFromFile,
entry->GetFullPath(), AtomToolsFramework::GetSaveFileInfo(defaultPath).absoluteFilePath().toUtf8().constData());
});
menu->addSeparator();
QAction* openParentAction = menu->addAction("Open Parent Material", [entry]()
{
AZ_UNUSED(entry);
// ToDo
});
openParentAction->setEnabled(false);
AddPerforceMenuActions(caller, menu, entry);
}
void MaterialEditorBrowserInteractions::AddContextMenuActionsForFolder(QWidget* caller, QMenu* menu, const AzToolsFramework::AssetBrowser::FolderAssetBrowserEntry* entry)
{
menu->addAction(AzQtComponents::fileBrowserActionName(), [entry]()
{
AzQtComponents::ShowFileOnDesktop(entry->GetFullPath().c_str());
});
QAction* createFolderAction = menu->addAction(QObject::tr("Create new sub folder..."));
QObject::connect(createFolderAction, &QAction::triggered, caller, [caller, entry]()
{
bool ok;
QString newFolderName = QInputDialog::getText(caller, "Enter new folder name", "name:", QLineEdit::Normal, "NewFolder", &ok);
if (ok)
{
if (newFolderName.isEmpty())
{
QMessageBox msgBox(QMessageBox::Icon::Critical, "Error", "Folder name can't be empty", QMessageBox::Ok, caller);
msgBox.exec();
}
else
{
AZStd::string newFolderPath;
AzFramework::StringFunc::Path::Join(entry->GetFullPath().c_str(), newFolderName.toUtf8().constData(), newFolderPath);
QDir dir(newFolderPath.c_str());
if (dir.exists())
{
QMessageBox::critical(caller, "Error", "Folder with this name already exists");
return;
}
auto result = dir.mkdir(newFolderPath.c_str());
if (!result)
{
AZ_Error("MaterialBrowser", false, "Failed to make new folder");
return;
}
}
}
});
}
void MaterialEditorBrowserInteractions::AddPerforceMenuActions([[maybe_unused]] QWidget* caller, QMenu* menu, const AzToolsFramework::AssetBrowser::AssetBrowserEntry* entry)
{
using namespace AzToolsFramework;
bool isActive = false;
SourceControlConnectionRequestBus::BroadcastResult(isActive, &SourceControlConnectionRequests::IsActive);
if (isActive)
{
menu->addSeparator();
AZStd::string path = entry->GetFullPath();
AzFramework::StringFunc::Path::Normalize(path);
QMenu* sourceControlMenu = menu->addMenu("Source Control");
// Update the enabled state of source control menu actions only if menu is shown
QMenu::connect(sourceControlMenu, &QMenu::aboutToShow, [this, path]()
{
SourceControlCommandBus::Broadcast(&SourceControlCommandBus::Events::GetFileInfo, path.c_str(),
[this](bool success, const SourceControlFileInfo& info) { UpdateSourceControlActions(success, info); });
});
// add get latest action
m_getLatestAction = sourceControlMenu->addAction("Get Latest", [path, this]()
{
SourceControlCommandBus::Broadcast(&SourceControlCommandBus::Events::RequestLatest, path.c_str(),
[](bool, const SourceControlFileInfo&) {});
});
QObject::connect(m_getLatestAction, &QObject::destroyed, [this]()
{
m_getLatestAction = nullptr;
});
m_getLatestAction->setEnabled(false);
// add add action
m_addAction = sourceControlMenu->addAction("Add", [path]()
{
SourceControlCommandBus::Broadcast(&SourceControlCommandBus::Events::RequestEdit, path.c_str(), true,
[path](bool, const SourceControlFileInfo&)
{
SourceControlThumbnailRequestBus::Broadcast(&SourceControlThumbnailRequests::FileStatusChanged, path.c_str());
});
});
QObject::connect(m_addAction, &QObject::destroyed, [this]()
{
m_addAction = nullptr;
});
m_addAction->setEnabled(false);
// add checkout action
m_checkOutAction = sourceControlMenu->addAction("Check Out", [path]()
{
SourceControlCommandBus::Broadcast(&SourceControlCommandBus::Events::RequestEdit, path.c_str(), true,
[path](bool, const SourceControlFileInfo&)
{
SourceControlThumbnailRequestBus::Broadcast(&SourceControlThumbnailRequests::FileStatusChanged, path.c_str());
});
});
QObject::connect(m_checkOutAction, &QObject::destroyed, [this]()
{
m_checkOutAction = nullptr;
});
m_checkOutAction->setEnabled(false);
// add undo checkout action
m_undoCheckOutAction = sourceControlMenu->addAction("Undo Check Out", [path]()
{
SourceControlCommandBus::Broadcast(&SourceControlCommandBus::Events::RequestRevert, path.c_str(),
[path](bool, const SourceControlFileInfo&)
{
SourceControlThumbnailRequestBus::Broadcast(&SourceControlThumbnailRequests::FileStatusChanged, path.c_str());
});
});
QObject::connect(m_undoCheckOutAction, &QObject::destroyed, [this]()
{
m_undoCheckOutAction = nullptr;
});
m_undoCheckOutAction->setEnabled(false);
}
}
void MaterialEditorBrowserInteractions::UpdateSourceControlActions(bool success, AzToolsFramework::SourceControlFileInfo info)
{
if (!success && m_caller)
{
QMessageBox::critical(m_caller, "Error", "Source control operation failed.");
}
if (m_getLatestAction)
{
m_getLatestAction->setEnabled(info.IsManaged() && info.HasFlag(AzToolsFramework::SCF_OutOfDate));
}
if (m_addAction)
{
m_addAction->setEnabled(!info.IsManaged());
}
if (m_checkOutAction)
{
m_checkOutAction->setEnabled(info.IsManaged() && info.IsReadOnly() && !info.IsLockedByOther());
}
if (m_undoCheckOutAction)
{
m_undoCheckOutAction->setEnabled(info.IsManaged() && !info.IsReadOnly());
}
}
} // namespace MaterialEditor
@@ -31,14 +31,14 @@ namespace AzToolsFramework
namespace MaterialEditor
{
class MaterialBrowserInteractions
class MaterialEditorBrowserInteractions
: public AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler
{
public:
AZ_CLASS_ALLOCATOR(MaterialBrowserInteractions, AZ::SystemAllocator, 0);
AZ_CLASS_ALLOCATOR(MaterialEditorBrowserInteractions, AZ::SystemAllocator, 0);
MaterialBrowserInteractions();
~MaterialBrowserInteractions();
MaterialEditorBrowserInteractions();
~MaterialEditorBrowserInteractions();
private:
//! AssetBrowserInteractionNotificationBus::Handler overrides...
@@ -98,7 +98,7 @@ namespace MaterialEditor
void MaterialEditorWindowComponent::CreateMaterialEditorWindow()
{
m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions);
m_materialEditorBrowserInteractions.reset(aznew MaterialEditorBrowserInteractions);
m_window.reset(aznew MaterialEditorWindow);
m_window->show();
@@ -16,7 +16,7 @@
#include <AzToolsFramework/API/EditorWindowRequestBus.h>
#include <Atom/Window/MaterialEditorWindowFactoryRequestBus.h>
#include <Source/Window/MaterialBrowserInteractions.h>
#include <Source/Window/MaterialEditorBrowserInteractions.h>
#include <Source/Window/MaterialEditorWindow.h>
namespace MaterialEditor
@@ -57,6 +57,6 @@ namespace MaterialEditor
////////////////////////////////////////////////////////////////////////
AZStd::unique_ptr<MaterialEditorWindow> m_window;
AZStd::unique_ptr<MaterialBrowserInteractions> m_materialBrowserInteractions;
AZStd::unique_ptr<MaterialEditorBrowserInteractions> m_materialEditorBrowserInteractions;
};
}
@@ -14,8 +14,8 @@ set(FILES
Include/Atom/Window/MaterialEditorWindowNotificationBus.h
Include/Atom/Window/MaterialEditorWindowRequestBus.h
Include/Atom/Window/MaterialEditorWindowFactoryRequestBus.h
Source/Window/MaterialBrowserInteractions.h
Source/Window/MaterialBrowserInteractions.cpp
Source/Window/MaterialEditorBrowserInteractions.h
Source/Window/MaterialEditorBrowserInteractions.cpp
Source/Window/MaterialEditorWindow.h
Source/Window/MaterialEditorWindow.cpp
Source/Window/MaterialEditorWindowModule.cpp
@@ -100,6 +100,7 @@ namespace AZ
AzToolsFramework::EditorMenuNotificationBus::Handler::BusConnect();
SetupThumbnails();
m_materialBrowserInteractions.reset(aznew MaterialBrowserInteractions);
}
void EditorMaterialSystemComponent::Deactivate()
@@ -111,6 +112,7 @@ namespace AZ
AzToolsFramework::EditorMenuNotificationBus::Handler::BusDisconnect();
TeardownThumbnails();
m_materialBrowserInteractions.reset();
if (m_openMaterialEditorAction)
{
@@ -22,6 +22,8 @@
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
#include <Material/MaterialBrowserInteractions.h>
namespace AZ
{
namespace Render
@@ -76,6 +78,8 @@ namespace AZ
AzFramework::TargetInfo m_materialEditorTarget;
QAction* m_openMaterialEditorAction = nullptr;
AZStd::unique_ptr<MaterialBrowserInteractions> m_materialBrowserInteractions;
};
} // namespace Render
} // namespace AZ
@@ -0,0 +1,54 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AzCore/std/string/wildcard.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <AtomLyIntegration/CommonFeatures/Material/EditorMaterialSystemComponentRequestBus.h>
#include <Material/MaterialBrowserInteractions.h>
namespace AZ
{
namespace Render
{
MaterialBrowserInteractions::MaterialBrowserInteractions()
{
AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusConnect();
}
MaterialBrowserInteractions::~MaterialBrowserInteractions()
{
AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler::BusDisconnect();
}
void MaterialBrowserInteractions::AddSourceFileOpeners(const char* fullSourceFileName, [[maybe_unused]] const AZ::Uuid& sourceUUID, AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers)
{
if (HandlesSource(fullSourceFileName))
{
openers.push_back(
{
"Material_Editor",
"Open in Material Editor...",
QIcon(),
[&](const char* fullSourceFileNameInCallback, [[maybe_unused]] const AZ::Uuid& sourceUUID)
{
EditorMaterialSystemComponentRequestBus::Broadcast(&EditorMaterialSystemComponentRequestBus::Events::OpenInMaterialEditor, fullSourceFileNameInCallback);
}
});
}
}
bool MaterialBrowserInteractions::HandlesSource(AZStd::string_view fileName) const
{
return AZStd::wildcard_match("*.material", fileName.data());
}
} // namespace Render
} // namespace AZ
@@ -0,0 +1,52 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
#include <AzToolsFramework/SourceControl/SourceControlAPI.h>
class QWidget;
class QMenu;
class QAction;
namespace AzToolsFramework
{
namespace AssetBrowser
{
class AssetBrowserEntry;
class SourceAssetBrowserEntry;
class FolderAssetBrowserEntry;
}
}
namespace AZ
{
namespace Render
{
class MaterialBrowserInteractions
: public AzToolsFramework::AssetBrowser::AssetBrowserInteractionNotificationBus::Handler
{
public:
AZ_CLASS_ALLOCATOR(MaterialBrowserInteractions, AZ::SystemAllocator, 0);
MaterialBrowserInteractions();
~MaterialBrowserInteractions();
private:
//! AssetBrowserInteractionNotificationBus::Handler overrides...
void AddSourceFileOpeners(const char* fullSourceFileName, const AZ::Uuid& sourceUUID, AzToolsFramework::AssetBrowser::SourceFileOpenerList& openers) override;
bool HandlesSource(AZStd::string_view fileName) const;
};
} // namespace Render
} // namespace AZ
@@ -41,6 +41,8 @@ set(FILES
Source/Material/EditorMaterialModelUvNameMapInspector.h
Source/Material/EditorMaterialSystemComponent.cpp
Source/Material/EditorMaterialSystemComponent.h
Source/Material/MaterialBrowserInteractions.h
Source/Material/MaterialBrowserInteractions.cpp
Source/Material/MaterialThumbnail.cpp
Source/Material/MaterialThumbnail.h
Source/Mesh/EditorMeshComponent.h