/* 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( #if QT_VERSION_MAJOR <= 5 ((QMouseEvent *)e)->globalPos() #else ((QMouseEvent *)e)->globalPosition().toPoint() #endif ); } } } canSelect_ = e->buttons() == 0; emit view->glMouseReleaseEvent(e); } void MouseController::mousePressEvent(QMouseEvent * e) { QPoint cpos = e->pos() * view->devicePixelRatio(); downPos = cpos; if (cur_action != RendererService::haNoAction && e->buttons() == Qt::LeftButton) { return; } if (selecting_) { selecting_ = false; view->renderer_.mouse_rect = QRect(); return; } if (!view->pixelRect().contains(cpos)) return; lastPos = cpos; downPos = cpos; emit view->glMousePressEvent(e); } void MouseController::mouseMoveEvent(QMouseEvent * e) { QPoint cpos = e->pos() * view->devicePixelRatio(); 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.map(rs.selection_center); QVector3D axe_screen = (axis_mat.map(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->pixelWidth(), view->pixelHeight(), 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->pixelWidth(), view->pixelHeight(), 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 / view->devicePixelRatio())); } else { lastPos = cpos; } 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 = view->pixelRect(); if (mouseRotate_) { float dx = cpos.x() - lastPos.x(); float dy = cpos.y() - lastPos.y(); if (e->buttons().testFlag(QT_MID_BUTTON)) { 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(cpos, lastPos, e->buttons()); lastPos = cpos; 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 = cpos.x() - lastPos.x(); int dy = cpos.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_) { double ang = #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) e->delta(); #else e->angleDelta().y(); #endif if (ang > 0) view->camera()->flyCloser(0.1f); if (ang < 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_MID_BUTTON)) emit view->doubleClick(); }