From 317e0dc54ce2af363e789f7e5f506be0c3010005 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Sun, 23 Jul 2023 20:38:22 -0400 Subject: [PATCH 1/3] Add extension and tool register / handle commands for scripts First example is with the spectra plugin to show / set vibrations Also, now show displacement arrows with the force visualizer Signed-off-by: Geoff Hutchison --- avogadro/qtgui/extensionplugin.cpp | 7 +++ avogadro/qtgui/extensionplugin.h | 22 +++++++ avogadro/qtgui/toolplugin.cpp | 7 +++ avogadro/qtgui/toolplugin.h | 22 +++++++ avogadro/qtplugins/spectra/spectra.cpp | 80 ++++++++++++++++++++------ avogadro/qtplugins/spectra/spectra.h | 2 + 6 files changed, 121 insertions(+), 19 deletions(-) diff --git a/avogadro/qtgui/extensionplugin.cpp b/avogadro/qtgui/extensionplugin.cpp index 5603a337f..534166d72 100644 --- a/avogadro/qtgui/extensionplugin.cpp +++ b/avogadro/qtgui/extensionplugin.cpp @@ -41,4 +41,11 @@ void ExtensionPlugin::setActiveWidget(QWidget* widget) { } +bool ExtensionPlugin::handleCommand(const QString& command, const QVariantMap& options) +{ + Q_UNUSED(command); + Q_UNUSED(options); + return false; +} + } // End Avogadro namespace diff --git a/avogadro/qtgui/extensionplugin.h b/avogadro/qtgui/extensionplugin.h index 35af93a24..6a2054109 100644 --- a/avogadro/qtgui/extensionplugin.h +++ b/avogadro/qtgui/extensionplugin.h @@ -103,6 +103,17 @@ public slots: */ virtual void setActiveWidget(QWidget* widget); + /** + * Called by the app to handle a command registered by the extension. + * (e.g., "renderMovie" or "generateSurface", etc.) + * + * The app will turn the command into a string and pass it to the extension. + * and any options will go from a JSON dictionary to a QVariantMap. + * + * @return true if the command was handled, false otherwise. + */ + virtual bool handleCommand(const QString& command, const QVariantMap& options); + signals: /** * Signal that the extension has a new molecule that is ready to be loaded. @@ -131,6 +142,17 @@ public slots: * would be most readily viewed with a specialized view. */ void requestActiveDisplayTypes(QStringList displayTypes); + + /** + * Register a new command with the application. The command will be available + * through scripting (e.g., "renderMovie" or "generateSurface", etc.) + * + * @param command The name of the command to register. + * @param description A description of the command. + * + * @sa handleCommand + */ + void registerCommand(QString command, QString description); }; /** diff --git a/avogadro/qtgui/toolplugin.cpp b/avogadro/qtgui/toolplugin.cpp index 8958bfed5..0b7f9bb51 100644 --- a/avogadro/qtgui/toolplugin.cpp +++ b/avogadro/qtgui/toolplugin.cpp @@ -54,6 +54,13 @@ void ToolPlugin::draw(Rendering::GroupNode&) { } +bool ToolPlugin::handleCommand(const QString& command, const QVariantMap& options) +{ + Q_UNUSED(command); + Q_UNUSED(options); + return false; +} + ToolPluginFactory::~ToolPluginFactory() { } diff --git a/avogadro/qtgui/toolplugin.h b/avogadro/qtgui/toolplugin.h index d5b3a543b..23bcf2f08 100644 --- a/avogadro/qtgui/toolplugin.h +++ b/avogadro/qtgui/toolplugin.h @@ -91,6 +91,17 @@ class AVOGADROQTGUI_EXPORT ToolPlugin : public QObject */ virtual void draw(Rendering::GroupNode& node); + /** + * Called by the app to handle a command registered by the plugin. + * (e.g., "renderMovie" or "drawAtom", etc.) + * + * The app will turn the command into a string and pass it to the tool. + * and any options will go from a JSON dictionary to a QVariantMap. + * + * @return true if the command was handled, false otherwise. + */ + virtual bool handleCommand(const QString& command, const QVariantMap& options); + signals: /** * Emitted when draw() needs to be called again due to updates. @@ -103,6 +114,17 @@ class AVOGADROQTGUI_EXPORT ToolPlugin : public QObject */ void updateRequested(); + /** + * Register a new command with the application. The command will be available + * through scripting (e.g., "renderMovie" or "generateSurface", etc.) + * + * @param command The name of the command to register. + * @param description A description of the command. + * + * @sa handleCommand + */ + void registerCommand(QString command, QString description); + public slots: /** * Called when the current molecule changes. diff --git a/avogadro/qtplugins/spectra/spectra.cpp b/avogadro/qtplugins/spectra/spectra.cpp index 6203518e9..b94aaeaec 100644 --- a/avogadro/qtplugins/spectra/spectra.cpp +++ b/avogadro/qtplugins/spectra/spectra.cpp @@ -9,11 +9,12 @@ #include #include #include +#include -#include #include +#include +#include #include -#include namespace Avogadro::QtPlugins { @@ -26,12 +27,20 @@ Spectra::Spectra(QObject* p) action->setText(tr("Vibrational Modes…")); connect(action, SIGNAL(triggered()), SLOT(openDialog())); m_actions.push_back(action); -} -Spectra::~Spectra() -{ + emit registerCommand("showVibrations", + tr("Show the vibrational modes dialog.")); + emit registerCommand("setVibrationalMode", tr("Set the vibrational mode.")); + emit registerCommand("setVibrationalAmplitude", + tr("Set the vibrational amplitude.")); + emit registerCommand("startVibrationAnimation", + tr("Start the vibrational animation.")); + emit registerCommand("stopVibrationAnimation", + tr("Stop the vibrational animation.")); } +Spectra::~Spectra() {} + QList Spectra::actions() const { return m_actions; @@ -54,6 +63,37 @@ void Spectra::setMolecule(QtGui::Molecule* mol) m_molecule = mol; if (m_dialog) m_dialog->setMolecule(mol); + + if (isVibrational) + openDialog(); +} + +bool Spectra::handleCommand(const QString& command, const QVariantMap& options) +{ + if (m_molecule == nullptr) + return false; // No molecule to handle the command. + + if (command == "showVibrations") { + openDialog(); + return true; + } else if (command == "setVibrationalMode") { + if (options.contains("mode")) { + setMode(options["mode"].toInt()); + return true; + } + } else if (command == "setVibrationalAmplitude") { + if (options.contains("amplitude")) { + setAmplitude(options["amplitude"].toInt()); + return true; + } + } else if (command == "startVibrationAnimation") { + startVibrationAnimation(); + return true; + } else if (command == "stopVibrationAnimation") { + stopVibrationAnimation(); + return true; + } + return false; } void Spectra::setMode(int mode) @@ -66,8 +106,10 @@ void Spectra::setMode(int mode) m_molecule->setCoordinate3d(0); Core::Array atomPositions = m_molecule->atomPositions3d(); Core::Array atomDisplacements = m_molecule->vibrationLx(mode); + // TODO: needs an option (show forces or not) + m_molecule->setForceVectors(atomDisplacements); - int frames = 5; + int frames = 5; // TODO: needs an option int frameCounter = 0; m_molecule->setCoordinate3d(atomPositions, frameCounter++); @@ -77,9 +119,9 @@ void Spectra::setMode(int mode) for (int i = 1; i <= frames; ++i) { Core::Array framePositions; for (Index atom = 0; atom < m_molecule->atomCount(); ++atom) { - framePositions.push_back(atomPositions[atom] + - atomDisplacements[atom] * factor * - (double(i) / frames)); + framePositions.push_back(atomPositions[atom] + atomDisplacements[atom] * + factor * + (double(i) / frames)); } m_molecule->setCoordinate3d(framePositions, frameCounter++); } @@ -87,9 +129,9 @@ void Spectra::setMode(int mode) for (int i = frames - 1; i >= 0; --i) { Core::Array framePositions; for (Index atom = 0; atom < m_molecule->atomCount(); ++atom) { - framePositions.push_back(atomPositions[atom] + - atomDisplacements[atom] * factor * - (double(i) / frames)); + framePositions.push_back(atomPositions[atom] + atomDisplacements[atom] * + factor * + (double(i) / frames)); } m_molecule->setCoordinate3d(framePositions, frameCounter++); } @@ -97,9 +139,9 @@ void Spectra::setMode(int mode) for (int i = 1; i <= frames; ++i) { Core::Array framePositions; for (Index atom = 0; atom < m_molecule->atomCount(); ++atom) { - framePositions.push_back(atomPositions[atom] - - atomDisplacements[atom] * factor * - (double(i) / frames)); + framePositions.push_back(atomPositions[atom] - atomDisplacements[atom] * + factor * + (double(i) / frames)); } m_molecule->setCoordinate3d(framePositions, frameCounter++); } @@ -107,9 +149,9 @@ void Spectra::setMode(int mode) for (int i = frames - 1; i >= 0; --i) { Core::Array framePositions; for (Index atom = 0; atom < m_molecule->atomCount(); ++atom) { - framePositions.push_back(atomPositions[atom] - - atomDisplacements[atom] * factor * - (double(i) / frames)); + framePositions.push_back(atomPositions[atom] - atomDisplacements[atom] * + factor * + (double(i) / frames)); } m_molecule->setCoordinate3d(framePositions, frameCounter++); } @@ -169,4 +211,4 @@ void Spectra::advanceFrame() m_molecule->setCoordinate3d(m_currentFrame); m_molecule->emitChanged(QtGui::Molecule::Atoms | QtGui::Molecule::Added); } -} +} // namespace Avogadro::QtPlugins diff --git a/avogadro/qtplugins/spectra/spectra.h b/avogadro/qtplugins/spectra/spectra.h index d8cbb8e09..5d942e682 100644 --- a/avogadro/qtplugins/spectra/spectra.h +++ b/avogadro/qtplugins/spectra/spectra.h @@ -42,6 +42,8 @@ class Spectra : public QtGui::ExtensionPlugin void setMolecule(QtGui::Molecule* mol) override; + bool handleCommand(const QString& command, const QVariantMap& options) override; + public slots: void setMode(int mode); void setAmplitude(int amplitude); From a9c62d493d57eb7c62ab9bd05ba83b9f7daa385a Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Mon, 24 Jul 2023 22:21:30 -0400 Subject: [PATCH 2/3] Increase the size of the force arrows Signed-off-by: Geoff Hutchison --- avogadro/qtplugins/spectra/spectra.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/avogadro/qtplugins/spectra/spectra.cpp b/avogadro/qtplugins/spectra/spectra.cpp index b94aaeaec..ea1cfef83 100644 --- a/avogadro/qtplugins/spectra/spectra.cpp +++ b/avogadro/qtplugins/spectra/spectra.cpp @@ -107,14 +107,19 @@ void Spectra::setMode(int mode) Core::Array atomPositions = m_molecule->atomPositions3d(); Core::Array atomDisplacements = m_molecule->vibrationLx(mode); // TODO: needs an option (show forces or not) - m_molecule->setForceVectors(atomDisplacements); + double factor = 0.01 * m_amplitude; + Index atom = 0; + for (Vector3& v : atomDisplacements) { + v *= 10.0*factor; + m_molecule->setForceVector(atom, v); + ++atom; + } + m_molecule->emitChanged(QtGui::Molecule::Atoms | QtGui::Molecule::Added); int frames = 5; // TODO: needs an option int frameCounter = 0; m_molecule->setCoordinate3d(atomPositions, frameCounter++); - double factor = 0.01 * m_amplitude; - // Current coords + displacement. for (int i = 1; i <= frames; ++i) { Core::Array framePositions; From a0211c24d4ac9eeaeae813fa9aa11a2c57a31e23 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Mon, 24 Jul 2023 22:29:04 -0400 Subject: [PATCH 3/3] Fix formatting Signed-off-by: Geoff Hutchison --- avogadro/qtgui/extensionplugin.cpp | 29 ++++++++------------------ avogadro/qtgui/extensionplugin.h | 17 ++++++++------- avogadro/qtgui/toolplugin.cpp | 21 +++++++------------ avogadro/qtgui/toolplugin.h | 19 +++++++++-------- avogadro/qtplugins/spectra/spectra.cpp | 2 +- avogadro/qtplugins/spectra/spectra.h | 7 ++++--- 6 files changed, 40 insertions(+), 55 deletions(-) diff --git a/avogadro/qtgui/extensionplugin.cpp b/avogadro/qtgui/extensionplugin.cpp index 534166d72..ea2052c69 100644 --- a/avogadro/qtgui/extensionplugin.cpp +++ b/avogadro/qtgui/extensionplugin.cpp @@ -7,45 +7,34 @@ namespace Avogadro::QtGui { -ExtensionPlugin::ExtensionPlugin(QObject* parent_) : QObject(parent_) -{ -} +ExtensionPlugin::ExtensionPlugin(QObject* parent_) : QObject(parent_) {} -ExtensionPlugin::~ExtensionPlugin() -{ -} +ExtensionPlugin::~ExtensionPlugin() {} QList ExtensionPlugin::fileFormats() const { return QList(); } -ExtensionPluginFactory::~ExtensionPluginFactory() -{ -} +ExtensionPluginFactory::~ExtensionPluginFactory() {} bool ExtensionPlugin::readMolecule(Molecule&) { return false; } -void ExtensionPlugin::setScene(Rendering::Scene*) -{ -} +void ExtensionPlugin::setScene(Rendering::Scene*) {} -void ExtensionPlugin::setCamera(Rendering::Camera* camera) -{ -} +void ExtensionPlugin::setCamera(Rendering::Camera* camera) {} -void ExtensionPlugin::setActiveWidget(QWidget* widget) -{ -} +void ExtensionPlugin::setActiveWidget(QWidget* widget) {} -bool ExtensionPlugin::handleCommand(const QString& command, const QVariantMap& options) +bool ExtensionPlugin::handleCommand(const QString& command, + const QVariantMap& options) { Q_UNUSED(command); Q_UNUSED(options); return false; } -} // End Avogadro namespace +} // namespace Avogadro::QtGui diff --git a/avogadro/qtgui/extensionplugin.h b/avogadro/qtgui/extensionplugin.h index 6a2054109..dcc85c214 100644 --- a/avogadro/qtgui/extensionplugin.h +++ b/avogadro/qtgui/extensionplugin.h @@ -23,7 +23,7 @@ class Molecule; namespace Rendering { class Camera; class Scene; -} +} // namespace Rendering namespace Io { class FileFormat; @@ -106,13 +106,14 @@ public slots: /** * Called by the app to handle a command registered by the extension. * (e.g., "renderMovie" or "generateSurface", etc.) - * + * * The app will turn the command into a string and pass it to the extension. * and any options will go from a JSON dictionary to a QVariantMap. - * + * * @return true if the command was handled, false otherwise. */ - virtual bool handleCommand(const QString& command, const QVariantMap& options); + virtual bool handleCommand(const QString& command, + const QVariantMap& options); signals: /** @@ -146,10 +147,10 @@ public slots: /** * Register a new command with the application. The command will be available * through scripting (e.g., "renderMovie" or "generateSurface", etc.) - * + * * @param command The name of the command to register. * @param description A description of the command. - * + * * @sa handleCommand */ void registerCommand(QString command, QString description); @@ -168,8 +169,8 @@ class AVOGADROQTGUI_EXPORT ExtensionPluginFactory ~ExtensionPluginFactory() override; }; -} // End QtGui namespace -} // End Avogadro namespace +} // namespace QtGui +} // namespace Avogadro Q_DECLARE_INTERFACE(Avogadro::QtGui::ExtensionPluginFactory, "org.openchemistry.avogadro.ExtensionPluginFactory") diff --git a/avogadro/qtgui/toolplugin.cpp b/avogadro/qtgui/toolplugin.cpp index 0b7f9bb51..249c2a263 100644 --- a/avogadro/qtgui/toolplugin.cpp +++ b/avogadro/qtgui/toolplugin.cpp @@ -7,13 +7,9 @@ namespace Avogadro::QtGui { -ToolPlugin::ToolPlugin(QObject* parent_) : QObject(parent_) -{ -} +ToolPlugin::ToolPlugin(QObject* parent_) : QObject(parent_) {} -ToolPlugin::~ToolPlugin() -{ -} +ToolPlugin::~ToolPlugin() {} QUndoCommand* ToolPlugin::mousePressEvent(QMouseEvent*) { @@ -50,19 +46,16 @@ QUndoCommand* ToolPlugin::keyReleaseEvent(QKeyEvent*) return nullptr; } -void ToolPlugin::draw(Rendering::GroupNode&) -{ -} +void ToolPlugin::draw(Rendering::GroupNode&) {} -bool ToolPlugin::handleCommand(const QString& command, const QVariantMap& options) +bool ToolPlugin::handleCommand(const QString& command, + const QVariantMap& options) { Q_UNUSED(command); Q_UNUSED(options); return false; } -ToolPluginFactory::~ToolPluginFactory() -{ -} +ToolPluginFactory::~ToolPluginFactory() {} -} // End Avogadro namespace +} // namespace Avogadro::QtGui diff --git a/avogadro/qtgui/toolplugin.h b/avogadro/qtgui/toolplugin.h index 23bcf2f08..b5756f3df 100644 --- a/avogadro/qtgui/toolplugin.h +++ b/avogadro/qtgui/toolplugin.h @@ -21,7 +21,7 @@ namespace Avogadro { namespace Rendering { class GroupNode; class GLRenderer; -} +} // namespace Rendering namespace QtOpenGL { class GLWidget; @@ -94,13 +94,14 @@ class AVOGADROQTGUI_EXPORT ToolPlugin : public QObject /** * Called by the app to handle a command registered by the plugin. * (e.g., "renderMovie" or "drawAtom", etc.) - * + * * The app will turn the command into a string and pass it to the tool. * and any options will go from a JSON dictionary to a QVariantMap. - * + * * @return true if the command was handled, false otherwise. */ - virtual bool handleCommand(const QString& command, const QVariantMap& options); + virtual bool handleCommand(const QString& command, + const QVariantMap& options); signals: /** @@ -117,10 +118,10 @@ class AVOGADROQTGUI_EXPORT ToolPlugin : public QObject /** * Register a new command with the application. The command will be available * through scripting (e.g., "renderMovie" or "generateSurface", etc.) - * + * * @param command The name of the command to register. * @param description A description of the command. - * + * * @sa handleCommand */ void registerCommand(QString command, QString description); @@ -159,12 +160,12 @@ class AVOGADROQTGUI_EXPORT ToolPluginFactory public: virtual ~ToolPluginFactory(); - virtual ToolPlugin* createInstance(QObject *parent = nullptr) = 0; + virtual ToolPlugin* createInstance(QObject* parent = nullptr) = 0; virtual QString identifier() const = 0; }; -} // End QtGui namespace -} // End Avogadro namespace +} // namespace QtGui +} // namespace Avogadro Q_DECLARE_INTERFACE(Avogadro::QtGui::ToolPluginFactory, "org.openchemistry.avogadro.ToolPluginFactory") diff --git a/avogadro/qtplugins/spectra/spectra.cpp b/avogadro/qtplugins/spectra/spectra.cpp index ea1cfef83..f4d5541cb 100644 --- a/avogadro/qtplugins/spectra/spectra.cpp +++ b/avogadro/qtplugins/spectra/spectra.cpp @@ -110,7 +110,7 @@ void Spectra::setMode(int mode) double factor = 0.01 * m_amplitude; Index atom = 0; for (Vector3& v : atomDisplacements) { - v *= 10.0*factor; + v *= 10.0 * factor; m_molecule->setForceVector(atom, v); ++atom; } diff --git a/avogadro/qtplugins/spectra/spectra.h b/avogadro/qtplugins/spectra/spectra.h index 5d942e682..8f1f51730 100644 --- a/avogadro/qtplugins/spectra/spectra.h +++ b/avogadro/qtplugins/spectra/spectra.h @@ -42,7 +42,8 @@ class Spectra : public QtGui::ExtensionPlugin void setMolecule(QtGui::Molecule* mol) override; - bool handleCommand(const QString& command, const QVariantMap& options) override; + bool handleCommand(const QString& command, + const QVariantMap& options) override; public slots: void setMode(int mode); @@ -68,7 +69,7 @@ private slots: int m_mode; int m_amplitude; }; -} -} +} // namespace QtPlugins +} // namespace Avogadro #endif // AVOGADRO_QTPLUGINS_Spectra_H