d6b268e84e
* Sever dependency on legacy resource selector host Audio resource selectors (browse dialogs) no longer need to be registered with the legacy IResourceSelectorHost system. Set up a new EBus specifically to handle browse button presses and directly invokes the dialog. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Hook up legacy audio control selector to new EBus Remaining use of legacy audio selectors (trackview) need to be able to bypass ResourceSelectorHost now. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Removes ResourceSelectorHost and legacy selectors This removes various Variable types that were tied to resource selectors, such as GeomCache, Model, Animation, File. Removes the ResourceSelectorHost completely. The two things that still appeared to have selectors in TrackView are Audio Controls and Texture. Fixed the audio control selector to work via EBus and the Texture selector didn't seem to work at all, but left it in as it was. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Make the default audio selector return old value Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Fix some signed/unsigned comparison warnings Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Remove deleted function from Editor Mock Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com> * Change audio selector api to use string_view Per feedback. Signed-off-by: amzn-phist <52085794+amzn-phist@users.noreply.github.com>
550 lines
18 KiB
C++
550 lines
18 KiB
C++
/*
|
|
* 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
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
#include "EditorDefs.h"
|
|
|
|
#include "EditorPanelUtils.h"
|
|
|
|
#include <AzCore/Utils/Utils.h>
|
|
|
|
// Qt
|
|
#include <QInputDialog>
|
|
#include <QFileDialog>
|
|
#include <QXmlStreamReader>
|
|
|
|
// Editor
|
|
#include "IEditorPanelUtils.h"
|
|
#include "Objects/EntityObject.h"
|
|
#include "CryEditDoc.h"
|
|
#include "ViewManager.h"
|
|
#include "Controls/QToolTipWidget.h"
|
|
#include "Objects/SelectionGroup.h"
|
|
|
|
|
|
|
|
#ifndef PI
|
|
#define PI 3.14159265358979323f
|
|
#endif
|
|
|
|
|
|
struct ToolTip
|
|
{
|
|
bool isValid;
|
|
QString title;
|
|
QString content;
|
|
QString specialContent;
|
|
QString disabledContent;
|
|
};
|
|
|
|
// internal implementation for better compile times - should also never be used externally, use IParticleEditorUtils interface for that.
|
|
class CEditorPanelUtils_Impl
|
|
: public IEditorPanelUtils
|
|
{
|
|
#pragma region Drag & Drop
|
|
public:
|
|
void SetViewportDragOperation(void(* dropCallback)(CViewport* viewport, int dragPointX, int dragPointY, void* custom), void* custom) override
|
|
{
|
|
for (int i = 0; i < GetIEditor()->GetViewManager()->GetViewCount(); i++)
|
|
{
|
|
GetIEditor()->GetViewManager()->GetView(i)->SetGlobalDropCallback(dropCallback, custom);
|
|
}
|
|
}
|
|
#pragma endregion
|
|
#pragma region Preview Window
|
|
public:
|
|
|
|
int PreviewWindow_GetDisplaySettingsDebugFlags(CDisplaySettings* settings) override
|
|
{
|
|
CRY_ASSERT(settings);
|
|
return settings->GetDebugFlags();
|
|
}
|
|
|
|
void PreviewWindow_SetDisplaySettingsDebugFlags(CDisplaySettings* settings, int flags) override
|
|
{
|
|
CRY_ASSERT(settings);
|
|
settings->SetDebugFlags(flags);
|
|
}
|
|
|
|
#pragma endregion
|
|
#pragma region Shortcuts
|
|
protected:
|
|
QVector<HotKey> hotkeys;
|
|
bool m_hotkeysAreEnabled;
|
|
public:
|
|
|
|
bool HotKey_Import() override
|
|
{
|
|
QVector<QPair<QString, QString> > keys;
|
|
QString filepath = QFileDialog::getOpenFileName(nullptr, "Select shortcut configuration to load",
|
|
QString(), "HotKey Config Files (*.hkxml)");
|
|
QFile file(filepath);
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
{
|
|
return false;
|
|
}
|
|
QXmlStreamReader stream(&file);
|
|
bool result = true;
|
|
|
|
while (!stream.isEndDocument())
|
|
{
|
|
if (stream.isStartElement())
|
|
{
|
|
if (stream.name() == "HotKey")
|
|
{
|
|
QPair<QString, QString> key;
|
|
QXmlStreamAttributes att = stream.attributes();
|
|
for (QXmlStreamAttribute attr : att)
|
|
{
|
|
if (attr.name().compare(QLatin1String("path"), Qt::CaseInsensitive) == 0)
|
|
{
|
|
key.first = attr.value().toString();
|
|
}
|
|
if (attr.name().compare(QLatin1String("sequence"), Qt::CaseInsensitive) == 0)
|
|
{
|
|
key.second = attr.value().toString();
|
|
}
|
|
}
|
|
if (!key.first.isEmpty())
|
|
{
|
|
keys.push_back(key); // we allow blank key sequences for unassigned shortcuts
|
|
}
|
|
else
|
|
{
|
|
result = false; //but not blank paths!
|
|
}
|
|
}
|
|
}
|
|
stream.readNext();
|
|
}
|
|
file.close();
|
|
|
|
if (result)
|
|
{
|
|
HotKey_BuildDefaults();
|
|
for (QPair<QString, QString> key : keys)
|
|
{
|
|
for (int j = 0; j < hotkeys.count(); j++)
|
|
{
|
|
if (hotkeys[j].path.compare(key.first, Qt::CaseInsensitive) == 0)
|
|
{
|
|
hotkeys[j].SetPath(key.first.toStdString().c_str());
|
|
hotkeys[j].SetSequenceFromString(key.second.toStdString().c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void HotKey_Export() override
|
|
{
|
|
auto settingDir = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / "Editor" / "Plugins" / "ParticleEditorPlugin" / "settings";
|
|
QString filepath = QFileDialog::getSaveFileName(nullptr, "Select shortcut configuration to load", settingDir.c_str(), "HotKey Config Files (*.hkxml)");
|
|
QFile file(filepath);
|
|
if (!file.open(QIODevice::WriteOnly))
|
|
{
|
|
return;
|
|
}
|
|
|
|
QXmlStreamWriter stream(&file);
|
|
stream.setAutoFormatting(true);
|
|
stream.writeStartDocument();
|
|
stream.writeStartElement("HotKeys");
|
|
|
|
for (HotKey key : hotkeys)
|
|
{
|
|
stream.writeStartElement("HotKey");
|
|
stream.writeAttribute("path", key.path);
|
|
stream.writeAttribute("sequence", key.sequence.toString());
|
|
stream.writeEndElement();
|
|
}
|
|
stream.writeEndElement();
|
|
stream.writeEndDocument();
|
|
file.close();
|
|
}
|
|
|
|
QKeySequence HotKey_GetShortcut(const char* path) override
|
|
{
|
|
for (HotKey combo : hotkeys)
|
|
{
|
|
if (combo.IsMatch(path))
|
|
{
|
|
return combo.sequence;
|
|
}
|
|
}
|
|
return QKeySequence();
|
|
}
|
|
|
|
bool HotKey_IsPressed(const QKeyEvent* event, const char* path) override
|
|
{
|
|
if (!m_hotkeysAreEnabled)
|
|
{
|
|
return false;
|
|
}
|
|
unsigned int keyInt = 0;
|
|
//Capture any modifiers
|
|
Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
|
|
if (modifiers & Qt::ShiftModifier)
|
|
{
|
|
keyInt += Qt::SHIFT;
|
|
}
|
|
if (modifiers & Qt::ControlModifier)
|
|
{
|
|
keyInt += Qt::CTRL;
|
|
}
|
|
if (modifiers & Qt::AltModifier)
|
|
{
|
|
keyInt += Qt::ALT;
|
|
}
|
|
if (modifiers & Qt::MetaModifier)
|
|
{
|
|
keyInt += Qt::META;
|
|
}
|
|
//Capture any key
|
|
keyInt += event->key();
|
|
|
|
QString t0 = QKeySequence(keyInt).toString();
|
|
QString t1 = HotKey_GetShortcut(path).toString();
|
|
|
|
//if strings match then shortcut is pressed
|
|
if (t1.compare(t0, Qt::CaseInsensitive) == 0)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool HotKey_IsPressed(const QShortcutEvent* event, const char* path) override
|
|
{
|
|
if (!m_hotkeysAreEnabled)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
QString t0 = event->key().toString();
|
|
QString t1 = HotKey_GetShortcut(path).toString();
|
|
|
|
//if strings match then shortcut is pressed
|
|
if (t1.compare(t0, Qt::CaseInsensitive) == 0)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool HotKey_LoadExisting() override
|
|
{
|
|
QSettings settings("O3DE", "O3DE");
|
|
QString group = "Hotkeys/";
|
|
|
|
HotKey_BuildDefaults();
|
|
|
|
int size = settings.beginReadArray(group);
|
|
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
settings.setArrayIndex(i);
|
|
QPair<QString, QString> hotkey;
|
|
hotkey.first = settings.value("name").toString();
|
|
hotkey.second = settings.value("keySequence").toString();
|
|
if (!hotkey.first.isEmpty())
|
|
{
|
|
for (int j = 0; j < hotkeys.count(); j++)
|
|
{
|
|
if (hotkeys[j].path.compare(hotkey.first, Qt::CaseInsensitive) == 0)
|
|
{
|
|
hotkeys[j].SetPath(hotkey.first.toStdString().c_str());
|
|
hotkeys[j].SetSequenceFromString(hotkey.second.toStdString().c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
settings.endArray();
|
|
if (hotkeys.isEmpty())
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void HotKey_SaveCurrent() override
|
|
{
|
|
QSettings settings("O3DE", "O3DE");
|
|
QString group = "Hotkeys/";
|
|
settings.remove("Hotkeys/");
|
|
settings.sync();
|
|
settings.beginWriteArray(group);
|
|
int saveIndex = 0;
|
|
for (HotKey key : hotkeys)
|
|
{
|
|
if (!key.path.isEmpty())
|
|
{
|
|
settings.setArrayIndex(saveIndex++);
|
|
settings.setValue("name", key.path);
|
|
settings.setValue("keySequence", key.sequence.toString());
|
|
}
|
|
}
|
|
settings.endArray();
|
|
settings.sync();
|
|
}
|
|
|
|
void HotKey_BuildDefaults() override
|
|
{
|
|
m_hotkeysAreEnabled = true;
|
|
QVector<QPair<QString, QString> > keys;
|
|
while (hotkeys.count() > 0)
|
|
{
|
|
hotkeys.takeAt(0);
|
|
}
|
|
|
|
//MENU SELECTION SHORTCUTS////////////////////////////////////////////////
|
|
keys.push_back(QPair<QString, QString>("Menus.File Menu", "Alt+F"));
|
|
keys.push_back(QPair<QString, QString>("Menus.Edit Menu", "Alt+E"));
|
|
keys.push_back(QPair<QString, QString>("Menus.View Menu", "Alt+V"));
|
|
//FILE MENU SHORTCUTS/////////////////////////////////////////////////////
|
|
keys.push_back(QPair<QString, QString>("File Menu.Create new emitter", "Ctrl+N"));
|
|
keys.push_back(QPair<QString, QString>("File Menu.Create new library", "Ctrl+Shift+N"));
|
|
keys.push_back(QPair<QString, QString>("File Menu.Create new folder", ""));
|
|
keys.push_back(QPair<QString, QString>("File Menu.Import", "Ctrl+I"));
|
|
keys.push_back(QPair<QString, QString>("File Menu.Import level library", "Ctrl+Shift+I"));
|
|
keys.push_back(QPair<QString, QString>("File Menu.Save", "Ctrl+S"));
|
|
keys.push_back(QPair<QString, QString>("File Menu.Close", "Ctrl+Q"));
|
|
//EDIT MENU SHORTCUTS/////////////////////////////////////////////////////
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Copy", "Ctrl+C"));
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Paste", "Ctrl+V"));
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Duplicate", "Ctrl+D"));
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Undo", "Ctrl+Z"));
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Redo", "Ctrl+Shift+Z"));
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Group", "Ctrl+G"));
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Ungroup", "Ctrl+Shift+G"));
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Rename", "Ctrl+R"));
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Reset", ""));
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Edit Hotkeys", ""));
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Assign to selected", "Ctrl+Space"));
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Insert Comment", "Ctrl+Alt+M"));
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Enable/Disable Emitter", "Ctrl+E"));
|
|
keys.push_back(QPair<QString, QString>("File Menu.Enable All", ""));
|
|
keys.push_back(QPair<QString, QString>("File Menu.Disable All", ""));
|
|
keys.push_back(QPair<QString, QString>("Edit Menu.Delete", "Del"));
|
|
//VIEW MENU SHORTCUTS/////////////////////////////////////////////////////
|
|
keys.push_back(QPair<QString, QString>("View Menu.Reset Layout", ""));
|
|
//PLAYBACK CONTROL////////////////////////////////////////////////////////
|
|
keys.push_back(QPair<QString, QString>("Previewer.Play/Pause Toggle", "Space"));
|
|
keys.push_back(QPair<QString, QString>("Previewer.Step forward through time", "c"));
|
|
keys.push_back(QPair<QString, QString>("Previewer.Loop Toggle", "z"));
|
|
keys.push_back(QPair<QString, QString>("Previewer.Reset Playback", "x"));
|
|
keys.push_back(QPair<QString, QString>("Previewer.Focus", "Ctrl+F"));
|
|
keys.push_back(QPair<QString, QString>("Previewer.Zoom In", "w"));
|
|
keys.push_back(QPair<QString, QString>("Previewer.Zoom Out", "s"));
|
|
keys.push_back(QPair<QString, QString>("Previewer.Pan Left", "a"));
|
|
keys.push_back(QPair<QString, QString>("Previewer.Pan Right", "d"));
|
|
|
|
for (QPair<QString, QString> key : keys)
|
|
{
|
|
unsigned int index = hotkeys.count();
|
|
hotkeys.push_back(HotKey());
|
|
hotkeys[index].SetPath(key.first.toStdString().c_str());
|
|
hotkeys[index].SetSequenceFromString(key.second.toStdString().c_str());
|
|
}
|
|
}
|
|
|
|
void HotKey_SetKeys(QVector<HotKey> keys) override
|
|
{
|
|
hotkeys = keys;
|
|
}
|
|
|
|
QVector<HotKey> HotKey_GetKeys() override
|
|
{
|
|
return hotkeys;
|
|
}
|
|
|
|
QString HotKey_GetPressedHotkey(const QKeyEvent* event) override
|
|
{
|
|
if (!m_hotkeysAreEnabled)
|
|
{
|
|
return "";
|
|
}
|
|
for (HotKey key : hotkeys)
|
|
{
|
|
if (HotKey_IsPressed(event, key.path.toUtf8()))
|
|
{
|
|
return key.path;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
QString HotKey_GetPressedHotkey(const QShortcutEvent* event) override
|
|
{
|
|
if (!m_hotkeysAreEnabled)
|
|
{
|
|
return "";
|
|
}
|
|
for (HotKey key : hotkeys)
|
|
{
|
|
if (HotKey_IsPressed(event, key.path.toUtf8()))
|
|
{
|
|
return key.path;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
//building the default hotkey list re-enables hotkeys
|
|
//do not use this when rebuilding the default list is a possibility.
|
|
void HotKey_SetEnabled(bool val) override
|
|
{
|
|
m_hotkeysAreEnabled = val;
|
|
}
|
|
|
|
bool HotKey_IsEnabled() const override
|
|
{
|
|
return m_hotkeysAreEnabled;
|
|
}
|
|
|
|
#pragma endregion
|
|
#pragma region ToolTip
|
|
protected:
|
|
QMap<QString, ToolTip> m_tooltips;
|
|
|
|
void ToolTip_ParseNode(XmlNodeRef node)
|
|
{
|
|
if (QString(node->getTag()).compare("tooltip", Qt::CaseInsensitive) != 0)
|
|
{
|
|
unsigned int childCount = node->getChildCount();
|
|
|
|
for (unsigned int i = 0; i < childCount; i++)
|
|
{
|
|
ToolTip_ParseNode(node->getChild(i));
|
|
}
|
|
}
|
|
|
|
QString title = node->getAttr("title");
|
|
QString content = node->getAttr("content");
|
|
QString specialContent = node->getAttr("special_content");
|
|
QString disabledContent = node->getAttr("disabled_content");
|
|
|
|
QMap<QString, ToolTip>::iterator itr = m_tooltips.insert(node->getAttr("path"), ToolTip());
|
|
itr->isValid = true;
|
|
itr->title = title;
|
|
itr->content = content;
|
|
itr->specialContent = specialContent;
|
|
itr->disabledContent = disabledContent;
|
|
|
|
unsigned int childCount = node->getChildCount();
|
|
|
|
for (unsigned int i = 0; i < childCount; i++)
|
|
{
|
|
ToolTip_ParseNode(node->getChild(i));
|
|
}
|
|
}
|
|
|
|
ToolTip GetToolTip(QString path)
|
|
{
|
|
if (m_tooltips.contains(path))
|
|
{
|
|
return m_tooltips[path];
|
|
}
|
|
ToolTip temp;
|
|
temp.isValid = false;
|
|
return temp;
|
|
}
|
|
|
|
public:
|
|
void ToolTip_LoadConfigXML(QString filepath) override
|
|
{
|
|
XmlNodeRef node = GetIEditor()->GetSystem()->LoadXmlFromFile(filepath.toStdString().c_str());
|
|
ToolTip_ParseNode(node);
|
|
}
|
|
|
|
void ToolTip_BuildFromConfig(IQToolTip* tooltip, QString path, QString option, QString optionalData = "", bool isEnabled = true) override
|
|
{
|
|
AZ_Assert(tooltip, "tooltip cannot be null");
|
|
|
|
QString title = ToolTip_GetTitle(path, option);
|
|
QString content = ToolTip_GetContent(path, option);
|
|
QString specialContent = ToolTip_GetSpecialContentType(path, option);
|
|
QString disabledContent = ToolTip_GetDisabledContent(path, option);
|
|
|
|
// Even if these items are empty, we set them anyway to clear out any data that was left over from when the tooltip was used for a different object.
|
|
tooltip->SetTitle(title);
|
|
tooltip->SetContent(content);
|
|
|
|
//this only handles simple creation...if you need complex call this then add specials separate
|
|
if (!specialContent.contains("::"))
|
|
{
|
|
tooltip->AddSpecialContent(specialContent, optionalData);
|
|
}
|
|
|
|
if (!isEnabled) // If disabled, add disabled value
|
|
{
|
|
tooltip->AppendContent(disabledContent);
|
|
}
|
|
}
|
|
|
|
QString ToolTip_GetTitle(QString path, QString option) override
|
|
{
|
|
if (!option.isEmpty() && GetToolTip(path + "." + option).isValid)
|
|
{
|
|
return GetToolTip(path + "." + option).title;
|
|
}
|
|
if (!option.isEmpty() && GetToolTip("Options." + option).isValid)
|
|
{
|
|
return GetToolTip("Options." + option).title;
|
|
}
|
|
return GetToolTip(path).title;
|
|
}
|
|
|
|
QString ToolTip_GetContent(QString path, QString option) override
|
|
{
|
|
if (!option.isEmpty() && GetToolTip(path + "." + option).isValid)
|
|
{
|
|
return GetToolTip(path + "." + option).content;
|
|
}
|
|
if (!option.isEmpty() && GetToolTip("Options." + option).isValid)
|
|
{
|
|
return GetToolTip("Options." + option).content;
|
|
}
|
|
return GetToolTip(path).content;
|
|
}
|
|
|
|
QString ToolTip_GetSpecialContentType(QString path, QString option) override
|
|
{
|
|
if (!option.isEmpty() && GetToolTip(path + "." + option).isValid)
|
|
{
|
|
return GetToolTip(path + "." + option).specialContent;
|
|
}
|
|
if (!option.isEmpty() && GetToolTip("Options." + option).isValid)
|
|
{
|
|
return GetToolTip("Options." + option).specialContent;
|
|
}
|
|
return GetToolTip(path).specialContent;
|
|
}
|
|
|
|
QString ToolTip_GetDisabledContent(QString path, QString option) override
|
|
{
|
|
if (!option.isEmpty() && GetToolTip(path + "." + option).isValid)
|
|
{
|
|
return GetToolTip(path + "." + option).disabledContent;
|
|
}
|
|
if (!option.isEmpty() && GetToolTip("Options." + option).isValid)
|
|
{
|
|
return GetToolTip("Options." + option).disabledContent;
|
|
}
|
|
return GetToolTip(path).disabledContent;
|
|
}
|
|
#pragma endregion ToolTip
|
|
};
|
|
|
|
IEditorPanelUtils* CreateEditorPanelUtils()
|
|
{
|
|
return new CEditorPanelUtils_Impl();
|
|
}
|
|
|