/**********************************************************************
AutoRotateTool - Auto Rotation Tool for Avogadro
Copyright (C) 2007,2008 by Marcus D. Hanwell
This file is part of the Avogadro molecular editor project.
For more information, see
Avogadro is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Avogadro is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
**********************************************************************/
#include "autorotatetool.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace Eigen;
namespace Avogadro {
AutoRotateTool::AutoRotateTool(QObject *parent) : Tool(parent), m_glwidget(0), m_leftButtonPressed(false),
m_midButtonPressed(false), m_timerId(0), m_xRotation(0), m_yRotation(0), m_zRotation(0), m_maxRotation(40),
m_settingsWidget(0), m_buttonStartStop(0), m_sliderX(0), m_sliderY(0), m_sliderZ(0)
{
QAction *action = activateAction();
action->setIcon(QIcon(QString::fromUtf8(":/autorotate/autorotate.png")));
action->setToolTip(tr("Auto Rotation Tool"));
}
AutoRotateTool::~AutoRotateTool()
{
}
int AutoRotateTool::usefulness() const
{
return 20000;
}
void AutoRotateTool::rotate() const
{
if (!m_glwidget->molecule()) {
return; // done!
}
// Get back transformed axes that we can rotate around
Vector3d xAxis = m_glwidget->camera()->backTransformedXAxis();
Vector3d yAxis = m_glwidget->camera()->backTransformedYAxis();
Vector3d zAxis = m_glwidget->camera()->backTransformedZAxis();
// Perform the rotations
m_glwidget->camera()->translate( m_glwidget->center() );
m_glwidget->camera()->rotate( m_xRotation * ROTATION_SPEED, yAxis );
m_glwidget->camera()->rotate( m_yRotation * ROTATION_SPEED, xAxis );
m_glwidget->camera()->rotate( m_zRotation * ROTATION_SPEED, zAxis );
m_glwidget->camera()->translate( -m_glwidget->center() );
}
QUndoCommand* AutoRotateTool::mousePressEvent(GLWidget *widget, QMouseEvent *event)
{
// Record the starting postion and which mouse button was pressed
m_glwidget = widget;
m_startDraggingPosition = event->pos();
m_currentDraggingPosition = m_startDraggingPosition;
m_leftButtonPressed = ( event->buttons() & Qt::LeftButton );
m_midButtonPressed = ( event->buttons() & Qt::MidButton );
if (m_leftButtonPressed || m_midButtonPressed)
event->accept();
m_glwidget->update();
return 0;
}
QUndoCommand* AutoRotateTool::mouseReleaseEvent(GLWidget *widget, QMouseEvent *event)
{
m_glwidget = widget;
// Calculate some multipliers for the delta
double xMultiplier = m_maxRotation / static_cast(m_glwidget->width());
double yMultiplier = m_maxRotation / static_cast(m_glwidget->height());
QPoint deltaDragging = event->pos() - m_startDraggingPosition;
if(m_leftButtonPressed) {
event->accept();
// Rotation about the x and y axes
m_xRotation = static_cast(deltaDragging.x() * xMultiplier);
m_sliderX->setValue(m_xRotation);
m_yRotation = static_cast(deltaDragging.y() * yMultiplier);
m_sliderY->setValue(m_yRotation);
m_zRotation = 0;
m_sliderZ->setValue(m_zRotation);
enableTimer();
}
else if (m_midButtonPressed) {
event->accept();
// Rotation about the z axis
m_xRotation = 0;
m_sliderX->setValue(m_xRotation);
m_yRotation = 0;
m_sliderY->setValue(m_yRotation);
m_zRotation = static_cast(deltaDragging.x() * xMultiplier);
m_sliderZ->setValue(m_zRotation);
enableTimer();
}
m_leftButtonPressed = false;
m_midButtonPressed = false;
m_glwidget->update();
return 0;
}
QUndoCommand* AutoRotateTool::mouseMoveEvent(GLWidget *widget, QMouseEvent *event)
{
m_glwidget = widget;
// Keep track of the current position to draw the movement line
m_currentDraggingPosition = event->pos();
if (m_leftButtonPressed || m_midButtonPressed)
event->accept();
m_glwidget->update();
return 0;
}
bool AutoRotateTool::paint(GLWidget *widget)
{
m_glwidget = widget;
if(m_leftButtonPressed || m_midButtonPressed)
{
// Draw a line from the start position to the current mouse position
if (m_leftButtonPressed) {
glColor4f(1., 0., 0., 1.);
} else if (m_midButtonPressed) {
glColor4f(0., 1., 0., 1.);
}
Vector3d start = m_glwidget->camera()->unProject(m_startDraggingPosition);
Vector3d end = m_glwidget->camera()->unProject(m_currentDraggingPosition);
glDisable(GL_LIGHTING);
glBegin(GL_LINES);
glVertex3d(start.x(), start.y(), start.z());
glVertex3d(end.x(), end.y(), end.z());
glEnd();
glEnable(GL_LIGHTING);
}
return true;
}
void AutoRotateTool::timerEvent(QTimerEvent*)
{
// If there is a glwidget and at least one axis is set for rotation
// then perform rotation and trigger a window update
if (m_glwidget && (m_xRotation || m_yRotation || m_zRotation))
{
rotate();
m_glwidget->update();
}
}
void AutoRotateTool::setXRotation(int i)
{
m_xRotation = i;
}
void AutoRotateTool::setYRotation(int i)
{
m_yRotation = i;
}
void AutoRotateTool::setZRotation(int i)
{
m_zRotation = i;
}
void AutoRotateTool::toggleTimer()
{
// Toggle the timer on and off
if (m_timerId) {
disableTimer();
} else {
enableTimer();
}
}
void AutoRotateTool::enableTimer()
{
if(!m_timerId)
{
m_timerId = startTimer(40);
m_buttonStartStop->setText(tr("Stop"));
}
}
void AutoRotateTool::disableTimer()
{
if(m_timerId)
{
killTimer(m_timerId);
m_timerId = 0;
m_buttonStartStop->setText(tr("Start"));
}
}
void AutoRotateTool::resetRotations()
{
// Emit the reset signal with a value of 0
emit resetRotation(0);
}
QWidget* AutoRotateTool::settingsWidget() {
if(!m_settingsWidget) {
m_settingsWidget = new QWidget;
// Label and slider to set x axis rotation
QLabel* labelX = new QLabel(tr("x rotation:"));
labelX->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
labelX->setMaximumHeight(15);
m_sliderX = new QSlider(m_settingsWidget);
m_sliderX->setOrientation(Qt::Horizontal);
m_sliderX->setTickPosition(QSlider::TicksAbove);
m_sliderX->setToolTip(tr("x rotation"));
m_sliderX->setTickInterval(10);
m_sliderX->setPageStep(5);
m_sliderX->setRange(-m_maxRotation, m_maxRotation);
m_sliderX->setValue(0);
QHBoxLayout* xLayout = new QHBoxLayout;
xLayout->addWidget(labelX);
xLayout->addWidget(m_sliderX);
// Label and slider to set y axis rotation
QLabel* labelY = new QLabel(tr("y rotation:"));
labelY->setMaximumHeight(15);
m_sliderY = new QSlider(m_settingsWidget);
m_sliderY->setOrientation(Qt::Horizontal);
m_sliderY->setTickPosition(QSlider::TicksAbove);
m_sliderY->setToolTip(tr("y rotation"));
m_sliderY->setTickInterval(10);
m_sliderY->setPageStep(5);
m_sliderY->setRange(-m_maxRotation, m_maxRotation);
m_sliderY->setValue(0);
QHBoxLayout* yLayout = new QHBoxLayout;
yLayout->addWidget(labelY);
yLayout->addWidget(m_sliderY);
// Label and slider to set z axis rotation
QLabel* labelZ = new QLabel(tr("z rotation:"));
labelZ->setMaximumHeight(15);
m_sliderZ = new QSlider(m_settingsWidget);
m_sliderZ->setOrientation(Qt::Horizontal);
m_sliderZ->setTickPosition(QSlider::TicksAbove);
m_sliderZ->setToolTip(tr("z rotation"));
m_sliderZ->setTickInterval(10);
m_sliderZ->setPageStep(5);
m_sliderZ->setRange(-m_maxRotation, m_maxRotation);
m_sliderZ->setValue(0);
QHBoxLayout* zLayout = new QHBoxLayout;
zLayout->addWidget(labelZ);
zLayout->addWidget(m_sliderZ);
// Push buttons to start/stop and to reset
m_buttonStartStop = new QPushButton(tr("Start"), m_settingsWidget);
QPushButton* buttonReset = new QPushButton(tr("Reset"), m_settingsWidget);
QHBoxLayout* buttonLayout = new QHBoxLayout();
buttonLayout->addWidget(m_buttonStartStop);
buttonLayout->addWidget(buttonReset);
QVBoxLayout* layout = new QVBoxLayout();
layout->addLayout(xLayout);
layout->addLayout(yLayout);
layout->addLayout(zLayout);
layout->addLayout(buttonLayout);
layout->addStretch(1);
m_settingsWidget->setLayout(layout);
// Connect the sliders with the slots
connect(m_sliderX, SIGNAL(valueChanged(int)),
this, SLOT(setXRotation(int)));
connect(m_sliderY, SIGNAL(valueChanged(int)),
this, SLOT(setYRotation(int)));
connect(m_sliderZ, SIGNAL(valueChanged(int)),
this, SLOT(setZRotation(int)));
// Connect the start/stop button
connect(m_buttonStartStop, SIGNAL(clicked()),
this, SLOT(toggleTimer()));
// Connect the reset button to the reset slot
connect(buttonReset, SIGNAL(clicked()),
this, SLOT(resetRotations()));
// Connect the reset signal to the sliders
connect(this, SIGNAL(resetRotation(int)),
m_sliderX, SLOT(setValue(int)));
connect(this, SIGNAL(resetRotation(int)),
m_sliderY, SLOT(setValue(int)));
connect(this, SIGNAL(resetRotation(int)),
m_sliderZ, SLOT(setValue(int)));
connect(m_settingsWidget, SIGNAL(destroyed()),
this, SLOT(settingsWidgetDestroyed()));
}
return m_settingsWidget;
}
void AutoRotateTool::settingsWidgetDestroyed()
{
m_settingsWidget = 0;
m_buttonStartStop = 0;
}
}
#include "autorotatetool.moc"
Q_EXPORT_PLUGIN2(autorotatetool, Avogadro::AutoRotateToolFactory)