You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Editor/EditorPanelUtils.cpp

543 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
{
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);
}
}
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);
}
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;
}
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;
}
};
IEditorPanelUtils* CreateEditorPanelUtils()
{
return new CEditorPanelUtils_Impl();
}