/*
QGL MouseController
Ivan Pelipenko peri4ko@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see .
*/
#include "mouse_controller.h"
#include "glmesh.h"
#include "qglview.h"
#include
#include
#include
using namespace QGLEngineShaders;
MouseController::MouseController(QGLView * view_): view(view_) {
app_scale = 1;
lastPos = QPoint(-1, -1);
cur_action = RendererService::haNoAction;
sel_button = Qt::LeftButton;
sel_mod = Qt::ControlModifier;
mouse_first = mouseSelect_ = mouseRotate_ = cameraOrbit_ = canSelect_ = true;
grabMouse_ = mouse_sec = selecting_ = customMouseMove_ = false;
}
MouseController::~MouseController() {
}
void MouseController::resize() {
mouse_first = true;
app_scale = appScale();
}
void MouseController::mouseReleaseEvent(QMouseEvent * e) {
if (cur_action != RendererService::haNoAction) {
mouseMoveEvent(e);
return;
}
bool add_ts = e->modifiers().testFlag(sel_mod);
if (selecting_) {
selecting_ = false;
canSelect_ = true;
view->renderer_.mouse_rect = QRect();
view->scene()->selectObjects(hov_objects.toList(), add_ts);
return;
}
if (canSelect_ && mouseSelect_) {
if ((lastPos - downPos).manhattanLength() < QApplication::startDragDistance()) {
if (e->button() == Qt::LeftButton) {
//qDebug() << hov_objects << hov_aims;
if (hov_objects.isEmpty() && hov_aims.isEmpty()) {
view->scene()->clearSelection();
} else {
if (!hov_objects.isEmpty())
view->scene()->selectObject(hov_objects[0], add_ts);
if (!hov_aims.isEmpty()) {
view->scene()->selectObject(hov_aims[0], add_ts);
hov_aims[0]->setAimSelected(true);
}
}
}
if (e->button() == Qt::RightButton) {
if (view->renderer_.edit_mode && !view->scene()->selectedObjects().isEmpty())
view->popupMenu(e->globalPos());
}
}
}
canSelect_ = e->buttons() == 0;
emit view->glMouseReleaseEvent(e);
}
void MouseController::mousePressEvent(QMouseEvent * e) {
downPos = e->pos();
if (cur_action != RendererService::haNoAction && e->buttons() == Qt::LeftButton) {
return;
}
if (selecting_) {
selecting_ = false;
view->renderer_.mouse_rect = QRect();
return;
}
if (!QRect(QPoint(), view->size()).contains(e->pos())) return;
lastPos = e->pos();
downPos = e->pos();
emit view->glMousePressEvent(e);
}
void MouseController::mouseMoveEvent(QMouseEvent * e) {
QPoint cpos = e->pos();
if (cur_action != RendererService::haNoAction && (e->buttons() == Qt::LeftButton)) {
RendererService & rs(view->renderer_.rend_service);
ObjectBaseList objects = view->scene()->selectedObjects(true);
QVector axis;
switch (cur_action) {
case RendererService::haMove:
if (cur_handle.testFlag(RendererService::hmMoveX)) axis << 0;
if (cur_handle.testFlag(RendererService::hmMoveY)) axis << 1;
if (cur_handle.testFlag(RendererService::hmMoveZ)) axis << 2;
break;
case RendererService::haRotate:
if (cur_handle.testFlag(RendererService::hmRotateX)) axis << 0;
if (cur_handle.testFlag(RendererService::hmRotateY)) axis << 1;
if (cur_handle.testFlag(RendererService::hmRotateZ)) axis << 2;
break;
case RendererService::haScale:
if (cur_handle.testFlag(RendererService::hmScaleX)) axis << 0;
if (cur_handle.testFlag(RendererService::hmScaleY)) axis << 1;
if (cur_handle.testFlag(RendererService::hmScaleZ)) axis << 2;
break;
default: break;
}
QVector scales;
foreach (int a, axis) {
QVector3D axe_vector; axe_vector[a] = 1.;
QMatrix4x4 axis_mat = view->camera()->fullViewMatrix() * rs.axis_mat;
QVector3D center_screen = axis_mat * rs.selection_center;
QVector3D axe_screen = ((axis_mat * (rs.selection_center + axe_vector)) - center_screen).normalized();
QVector3D mouse_vector(cpos - lastPos);
mouse_vector[1] *= -1.;
if (cur_action == RendererService::haMove) {
double len_scl = 1. / QVector3D(axe_screen.x(), axe_screen.y(), 1.E-6).length();
mouse_vector /= QVector3D(view->width(), view->height(), 1);
mouse_vector *= -center_screen.z() * len_scl;
axe_vector *= QVector3D::dotProduct(axe_screen, mouse_vector);
QMatrix4x4 pmat;
foreach (ObjectBase * o, objects) {
pmat.setToIdentity();
if (o->parent())
pmat = o->parent()->worldTransform().inverted();
QVector3D dv = pmat.mapVector(axe_vector);
if (o->isAimSelected()) {
AimedObject * ao = (AimedObject*)o;
ao->setAim(ao->aim() + dv);
} else
o->move(dv);
}
}
if (cur_action == RendererService::haRotate) {
axe_screen.setZ(0.);
axe_screen.normalize();
QVector3D norm = QVector3D(axe_screen.y(), -axe_screen.x(), 0.);
axe_vector *= QVector3D::dotProduct(mouse_vector, norm) / 2. / app_scale;
foreach (ObjectBase * o, objects)
o->setRotation(o->rotation() + axe_vector);
}
if (cur_action == RendererService::haScale) {
mouse_vector /= QVector3D(view->width(), view->height(), 1);
mouse_vector *= 3. / app_scale;
axe_vector *= QVector3D::dotProduct(axe_screen, mouse_vector);
scales << axe_vector;
}
}
if (cur_action == RendererService::haScale) {
double sc = 0., max = 0.;
foreach (const QVector3D & s, scales) {
double v = QVector3D::dotProduct(s, QVector3D(1,1,1));
sc += v;
max = qMax(max, qAbs(v));
}
sc = max * (sc > 0. ? 1. : -1);
QVector3D axe_vector;
foreach (int a, axis)
axe_vector[a] = 1.;
foreach (ObjectBase * o, objects)
o->scale(QVector3D(1,1,1) + (axe_vector * sc));
QCursor::setPos(view->mapToGlobal(downPos));
} else
lastPos = e->pos();
emit view->objectsPositionChanged();
return;
}
if (selecting_) {
view->renderer_.mouse_rect = QRect(downPos, cpos).normalized();
return;
}
if (e->buttons().testFlag(Qt::LeftButton)) {
if ((cpos - downPos).manhattanLength() >= QApplication::startDragDistance()) {
selecting_ = true;
canSelect_ = false;
}
return;
}
QRect g_rect(QPoint(), view->size());
if (mouseRotate_) {
float dx = e->x() - lastPos.x();
float dy = e->y() - lastPos.y();
if (e->buttons().testFlag(Qt::MidButton)) {
if (cameraOrbit_) {
view->camera()->orbitZ (dx / 4.f);
view->camera()->orbitXY(dy / 4.f);
} else {
view->camera()->rotateZ(-dx / 4.f);
view->camera()->rotateX(-dy / 4.f);
}
emit view->cameraPosChanged(view->camera()->pos());
} else if (e->buttons().testFlag(Qt::RightButton)) {
float ad = view->camera()->distance();
view->camera()->moveLeft(dx / 1000.f * ad);
view->camera()->moveUp (dy / 1000.f * ad);
emit view->cameraPosChanged(view->camera()->pos());
}
}
if (customMouseMove_) emit view->customMouseMoveEvent(e->pos(), lastPos, e->buttons());
lastPos = e->pos();
if (e->buttons() == 0) {
cur_handle = QFlags();
cur_action = RendererService::haNoAction;
Qt::CursorShape cs = Qt::CrossCursor;
if (view->renderer_.edit_mode) {
uint hid = view->renderer_.rend_selection.id_hover;
cur_handle = (RendererService::HandleMesh)hid;
if (hid >= RendererService::hmMoveX && hid <= RendererService::hmMaxMove ) {
cur_action = RendererService::haMove;
cs = Qt::SizeAllCursor;
}
if (hid >= RendererService::hmRotateX && hid <= RendererService::hmMaxRotate) {
cur_action = RendererService::haRotate;
cs = Qt::PointingHandCursor;
}
if (hid >= RendererService::hmScaleX && hid <= RendererService::hmMaxScale ) {
cur_action = RendererService::haScale;
cs = Qt::SplitHCursor;
}
}
if (cur_action == RendererService::haNoAction)
cur_handle = QFlags();
view->setCursor(cs);
view->renderer_.rend_service.current_handle = cur_handle;
}
if (grabMouse_) {
QCursor::setPos(view->mapToGlobal(QRect(QPoint(), view->size()).center()));
if (mouse_sec) {
mouse_sec = false;
return;
}
if (mouse_first) {
mouse_first = false;
mouse_sec = true;
return;
}
lastPos = g_rect.center();
int dx = e->x() - lastPos.x();
int dy = e->y() - lastPos.y();
emit view->glMouseMoveEvent(new QMouseEvent(QEvent::MouseMove, QPoint(dx, dy), e->button(), e->buttons(), e->modifiers()));
return;
}
emit view->glMouseMoveEvent(e);
}
void MouseController::wheelEvent(QWheelEvent * e) {
if (mouseRotate_) {
if (e->delta() > 0) view->camera()->flyCloser(0.1f);
if (e->delta() < 0) view->camera()->flyFarer(0.1f);
emit view->cameraPosChanged(view->camera()->pos());
}
emit view->glWheelEvent(e);
}
void MouseController::leaveEvent(QEvent * ) {
lastPos = QPoint(-1, -1);
//qDebug() << lastPos;
}
void MouseController::mouseDoubleClickEvent(QMouseEvent * e) {
if (e->buttons().testFlag(Qt::MidButton))
emit view->doubleClick();
}