Skip to content

WIP: Support for undo/redo apply colors #1242

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 25 additions & 30 deletions avogadro/qtgui/rwmolecule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ using Core::CrystalTools;
using Core::UnitCell;
using std::swap;

RWMolecule::RWMolecule(Molecule& mol, QObject* p) : QObject(p), m_molecule(mol), m_interactive(false)
{}
RWMolecule::RWMolecule(Molecule& mol, QObject* p)
: QObject(p), m_molecule(mol), m_interactive(false)
{
}

RWMolecule::~RWMolecule() {}

Expand All @@ -33,8 +35,7 @@ RWMolecule::AtomType RWMolecule::addAtom(unsigned char num, bool usingPositions)
auto atomId = static_cast<Index>(m_molecule.atomCount());
auto atomUid = static_cast<Index>(m_molecule.m_atomUniqueIds.size());

auto* comm =
new AddAtomCommand(*this, num, usingPositions, atomId, atomUid);
auto* comm = new AddAtomCommand(*this, num, usingPositions, atomId, atomUid);
comm->setText(tr("Add Atom"));
m_undoStack.push(comm);
return AtomType(this, atomId);
Expand Down Expand Up @@ -149,8 +150,8 @@ bool RWMolecule::setAtomicNumber(Index atomId, unsigned char num)
if (atomId >= atomCount())
return false;

auto* comm = new SetAtomicNumberCommand(
*this, atomId, m_molecule.atomicNumber(atomId), num);
auto* comm = new SetAtomicNumberCommand(*this, atomId,
m_molecule.atomicNumber(atomId), num);
comm->setText(tr("Change Element"));
m_undoStack.push(comm);
return true;
Expand All @@ -162,8 +163,7 @@ bool RWMolecule::setAtomPositions3d(const Core::Array<Vector3>& pos,
if (pos.size() != m_molecule.atomCount())
return false;

auto* comm =
new SetPositions3dCommand(*this, m_molecule.m_positions3d, pos);
auto* comm = new SetPositions3dCommand(*this, m_molecule.m_positions3d, pos);
comm->setText(undoText);
comm->setCanMerge(m_interactive);
m_undoStack.push(comm);
Expand All @@ -188,21 +188,21 @@ bool RWMolecule::setAtomPosition3d(Index atomId, const Vector3& pos,
if (m_molecule.m_positions3d.size() != m_molecule.atomCount())
m_molecule.m_positions3d.resize(m_molecule.atomCount(), Vector3::Zero());

auto* comm = new SetPosition3dCommand(
*this, atomId, m_molecule.m_positions3d[atomId], pos);
auto* comm = new SetPosition3dCommand(*this, atomId,
m_molecule.m_positions3d[atomId], pos);
comm->setText(undoText);
comm->setCanMerge(m_interactive);
m_undoStack.push(comm);
return true;
}

void RWMolecule::setAtomSelected(Index atomId, bool selected, const QString& undoText)
void RWMolecule::setAtomSelected(Index atomId, bool selected,
const QString& undoText)
{
auto* comm = new ModifySelectionCommand(*this, atomId, selected);
auto* comm = new SetSelectionCommand(*this, atomId, selected);
comm->setText(undoText);
comm->setCanMerge(true);
m_undoStack.push(comm);
// m_molecule.setAtomSelected(atomId, selected);
}

bool RWMolecule::atomSelected(Index atomId) const
Expand Down Expand Up @@ -234,14 +234,15 @@ bool RWMolecule::setFormalCharge(Index atomId, signed char charge)
return true;
}

bool RWMolecule::setColor(Index atomId, Vector3ub color)
bool RWMolecule::setColor(Index atomId, Vector3ub color,
const QString& undoText)
{
if (atomId >= atomCount())
return false;

auto* comm =
new SetAtomColorCommand(*this, atomId, m_molecule.color(atomId), color);
comm->setText(tr("Change Atom Color"));
auto* comm = new SetAtomColorCommand(*this, atomId, color);
comm->setText(undoText);
comm->setCanMerge(true);
m_undoStack.push(comm);
return true;
}
Expand Down Expand Up @@ -315,8 +316,7 @@ bool RWMolecule::setBondOrders(const Core::Array<unsigned char>& orders)
if (orders.size() != m_molecule.bondCount())
return false;

auto* comm =
new SetBondOrdersCommand(*this, m_molecule.bondOrders(), orders);
auto* comm = new SetBondOrdersCommand(*this, m_molecule.bondOrders(), orders);
comm->setText(tr("Set Bond Orders"));
m_undoStack.push(comm);
return true;
Expand Down Expand Up @@ -350,8 +350,7 @@ bool RWMolecule::setBondPairs(const Array<std::pair<Index, Index>>& pairs)
if (p_const[i].first > p_const[i].second)
swap(p[i].first, p[i].second);

auto* comm =
new SetBondPairsCommand(*this, m_molecule.bondPairs(), p);
auto* comm = new SetBondPairsCommand(*this, m_molecule.bondPairs(), p);
comm->setText(tr("Update Bonds"));
m_undoStack.push(comm);
return true;
Expand Down Expand Up @@ -389,8 +388,7 @@ void RWMolecule::addUnitCell()
static_cast<Real>(90.0) * DEG_TO_RAD);
m_molecule.setUnitCell(cell);

auto* comm =
new AddUnitCellCommand(*this, *m_molecule.unitCell());
auto* comm = new AddUnitCellCommand(*this, *m_molecule.unitCell());
comm->setText(tr("Add Unit Cell"));
m_undoStack.push(comm);
emitChanged(Molecule::UnitCell | Molecule::Added);
Expand All @@ -402,8 +400,7 @@ void RWMolecule::removeUnitCell()
if (!m_molecule.unitCell())
return;

auto* comm =
new RemoveUnitCellCommand(*this, *m_molecule.unitCell());
auto* comm = new RemoveUnitCellCommand(*this, *m_molecule.unitCell());
comm->setText(tr("Remove Unit Cell"));
m_undoStack.push(comm);

Expand All @@ -415,8 +412,7 @@ void RWMolecule::modifyMolecule(const Molecule& newMolecule,
Molecule::MoleculeChanges changes,
const QString& undoText)
{
auto* comm =
new ModifyMoleculeCommand(*this, m_molecule, newMolecule);
auto* comm = new ModifyMoleculeCommand(*this, m_molecule, newMolecule);

comm->setText(undoText);
m_undoStack.push(comm);
Expand Down Expand Up @@ -484,8 +480,7 @@ void RWMolecule::wrapAtomsToCell()
CrystalTools::wrapAtomsToUnitCell(m_molecule);
Core::Array<Vector3> newPos = m_molecule.atomPositions3d();

auto* comm =
new SetPositions3dCommand(*this, oldPos, newPos);
auto* comm = new SetPositions3dCommand(*this, oldPos, newPos);
comm->setText(tr("Wrap Atoms to Cell"));
m_undoStack.push(comm);

Expand Down Expand Up @@ -727,4 +722,4 @@ bool RWMolecule::setForceVector(Index atomId, const Vector3& forces,
return true;
}

} // namespace Avogadro
} // namespace Avogadro::QtGui
3 changes: 2 additions & 1 deletion avogadro/qtgui/rwmolecule.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,8 @@ class AVOGADROQTGUI_EXPORT RWMolecule : public QObject
* @param color The new color.
* @return True on success, false otherwise.
*/
bool setColor(Index atomId, Vector3ub color);
bool setColor(Index atomId, Vector3ub color,
const QString& undoText = tr("Change Atom Color"));

bool setLayer(Index atomId, size_t layer);
size_t layer(Index atomId) const;
Expand Down
87 changes: 25 additions & 62 deletions avogadro/qtgui/rwmolecule_undo.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ enum MergeIds
SetPosition3dMergeId,
SetForceVectorMergeId,
SetBondOrderMergeId,
ModifySelectionMergeId,
ModifyColorsMergeId
SetSelectionMergeId,
SetColorMergeId
};

// Base class for undo commands that can be merged together, overriding the
Expand Down Expand Up @@ -348,25 +348,6 @@ class SetAtomFormalChargeCommand : public RWMolecule::UndoCommand
} // namespace

namespace {
class SetAtomColorCommand : public RWMolecule::UndoCommand
{
Index m_atomId;
Vector3ub m_oldColor;
Vector3ub m_newColor;

public:
SetAtomColorCommand(RWMolecule& m, Index atomId, Vector3ub oldColor,
Vector3ub newColor)
: UndoCommand(m), m_atomId(atomId), m_oldColor(oldColor),
m_newColor(newColor)
{
}

void redo() override { m_molecule.setColor(m_atomId, m_newColor); }

void undo() override { m_molecule.setColor(m_atomId, m_oldColor); }
};

class SetLayerCommand : public RWMolecule::UndoCommand
{
Index m_atomId;
Expand Down Expand Up @@ -687,14 +668,14 @@ class ModifyLabelCommand : public RWMolecule::UndoCommand
} // namespace

namespace {
class ModifySelectionCommand : public MergeUndoCommand<ModifySelectionMergeId>
class SetSelectionCommand : public MergeUndoCommand<SetSelectionMergeId>
{
std::vector<bool> m_newSelectedAtoms;
std::vector<bool> m_oldSelectedAtoms;

public:
ModifySelectionCommand(RWMolecule& m, Index atomId, bool selected)
: MergeUndoCommand<ModifySelectionMergeId>(m)
SetSelectionCommand(RWMolecule& m, Index atomId, bool selected)
: MergeUndoCommand<SetSelectionMergeId>(m)
{
Index atomCount = m_mol.molecule().atomCount();
m_oldSelectedAtoms.resize(atomCount);
Expand Down Expand Up @@ -724,8 +705,8 @@ class ModifySelectionCommand : public MergeUndoCommand<ModifySelectionMergeId>

bool mergeWith(const QUndoCommand* other) override
{
const ModifySelectionCommand* o =
dynamic_cast<const ModifySelectionCommand*>(other);
const SetSelectionCommand* o =
dynamic_cast<const SetSelectionCommand*>(other);
if (!o)
return false;

Expand All @@ -743,66 +724,48 @@ class ModifySelectionCommand : public MergeUndoCommand<ModifySelectionMergeId>
};
} // namespace

/*
namespace {
class ModifyColorCommand : public MergeUndoCommand<ModifyColorMergeId>
class SetAtomColorCommand : public MergeUndoCommand<SetColorMergeId>
{
Array<Vector3ub> m_newSelectedAtoms;
Array<Vector3ub> m_oldSelectedAtoms;
Array<Vector3ub> m_oldColors;
Array<Vector3ub> m_newColors;

public:
ModifySelectionCommand(RWMolecule& m, Index atomId, bool selected)
: MergeUndoCommand<ModifySelectionMergeId>(m)
SetAtomColorCommand(RWMolecule& m, Index atomId, Vector3ub newColor)
: MergeUndoCommand<SetColorMergeId>(m)
{
Index atomCount = m_mol.molecule().atomCount();
m_oldSelectedAtoms.reserve(atomCount);
m_newSelectedAtoms.reserve(atomCount);
m_oldColors.resize(m_molecule.atomCount());
m_newColors.resize(m_molecule.atomCount());

for (Index i = 0; i < atomCount; ++i) {
m_oldSelectedAtoms[i] = m_molecule.atomSelected(i);
m_newSelectedAtoms[i] = m_molecule.atomSelected(i);
}
m_oldColors = m_mol.molecule().colors();

m_newSelectedAtoms[atomId] = selected;
m_newColors = m_mol.molecule().colors();
m_newColors[atomId] = newColor;
}

void redo() override
{
Index atomCount = m_mol.molecule().atomCount();
for (Index i = 0; i < atomCount; ++i)
m_mol.molecule().setAtomSelected(i, m_newSelectedAtoms[i]);
}
void redo() override { m_mol.molecule().setColors(m_newColors); }

void undo() override
{
Index atomCount = m_mol.molecule().atomCount();
for (Index i = 0; i < atomCount; ++i)
m_mol.molecule().setAtomSelected(i, m_oldSelectedAtoms[i]);
}
void undo() override { m_mol.molecule().setColors(m_oldColors); }

bool mergeWith(const QUndoCommand* other) override
{
const ModifySelectionCommand* o =
dynamic_cast<const ModifySelectionCommand*>(other);
const SetAtomColorCommand* o =
dynamic_cast<const SetAtomColorCommand*>(other);
if (o) {
// check if the atom count matches
Index numAtoms = m_oldSelectedAtoms.size();
if (numAtoms != o->m_oldSelectedAtoms.size() ||
numAtoms != o->m_newSelectedAtoms.size()) {
Index numAtoms = m_oldColors.size();
if (numAtoms != o->m_oldColors.size() ||
numAtoms != o->m_newColors.size()) {
return false;
}

// merge these, by grabbing the new selected atoms
for (Index i = 0; i < numAtoms; ++i)
m_newSelectedAtoms[i] = o->m_newSelectedAtoms[i];

m_newColors = o->m_newColors;
return true;
}
return false;
}
};
} // namespace
*/

} // namespace QtGui
} // namespace Avogadro
Expand Down
20 changes: 12 additions & 8 deletions avogadro/qtplugins/applycolors/applycolors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <avogadro/core/residue.h>
#include <avogadro/core/residuecolors.h>
#include <avogadro/qtgui/molecule.h>
#include <avogadro/qtgui/rwmolecule.h>

#include <QtCore/QDebug>
#include <QtCore/QStringList>
Expand Down Expand Up @@ -229,7 +230,8 @@ void ApplyColors::applyIndexColors()

float indexFraction = float(i) / float(numAtoms);

m_molecule->atom(i).setColor(rainbowGradient(indexFraction, type));
m_molecule->undoMolecule()->setColor(
i, rainbowGradient(indexFraction, type), tr("Index Color"));
}

m_molecule->emitChanged(QtGui::Molecule::Atoms);
Expand All @@ -250,14 +252,14 @@ void ApplyColors::applyChargeColors()

// populate the dialog to choose the model and colormap
ChargeColorDialog dialog;
for (const auto &model : identifiers) {
for (const auto& model : identifiers) {
auto name = Calc::ChargeManager::instance().nameForModel(model);
dialog.modelCombo->addItem(name.c_str(), model.c_str());
}
dialog.exec();
if (dialog.result() != QDialog::Accepted)
return;

// get the model and colormap
const auto model = dialog.modelCombo->currentData().toString().toStdString();
const auto colormapName = dialog.colorMapCombo->currentText();
Expand All @@ -282,7 +284,8 @@ void ApplyColors::applyChargeColors()
if (isSelection && !m_molecule->atomSelected(i))
continue;

m_molecule->atom(i).setColor(chargeGradient(charges(i, 0), clamp, type));
m_molecule->undoMolecule()->setColor(
i, chargeGradient(charges(i, 0), clamp, type), tr("Charge Color"));
}

m_molecule->emitChanged(QtGui::Molecule::Atoms);
Expand Down Expand Up @@ -325,7 +328,8 @@ void ApplyColors::applyDistanceColors()
Real distance = diff.norm();
Real distanceFraction = distance / size;

m_molecule->atom(i).setColor(rainbowGradient(distanceFraction, type));
m_molecule->undoMolecule()->setColor(
i, rainbowGradient(distanceFraction, type), tr("Distance Color"));
}

m_molecule->emitChanged(QtGui::Molecule::Atoms);
Expand All @@ -344,7 +348,7 @@ void ApplyColors::resetColors()
continue;

Vector3ub color(Core::Elements::color(m_molecule->atomicNumber(i)));
m_molecule->atom(i).setColor(color);
m_molecule->undoMolecule()->setColor(i, color, tr("Reset Color"));
}

m_molecule->emitChanged(QtGui::Molecule::Atoms);
Expand All @@ -367,7 +371,7 @@ void ApplyColors::applyCustomColor(const QColor& new_color)
if (isSelection && !m_molecule->atomSelected(i))
continue;

m_molecule->atom(i).setColor(color);
m_molecule->undoMolecule()->setColor(i, color, tr("Custom Color"));
}

m_molecule->emitChanged(QtGui::Molecule::Atoms);
Expand Down Expand Up @@ -570,4 +574,4 @@ void ApplyColors::applyShapelyColors()
m_molecule->emitChanged(QtGui::Molecule::Atoms);
}

} // namespace Avogadro
} // namespace Avogadro::QtPlugins