// Copyright (c) 2008 GeometryFactory Sarl (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org). // 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 3 of the License, or (at your option) any later version. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // SPDX-License-Identifier: GPL-3.0+ // // // Author(s) : Andreas Fabri // Laurent Rineau #ifdef CGAL_HEADER_ONLY #define CGAL_INLINE_FUNCTION inline #include #else #define CGAL_INLINE_FUNCTION #endif #include #include // for mapToScene(QGraphicsView*, QRect) #include #include #include #include #include #include #include #include #include #include #include namespace CGAL { namespace Qt { CGAL_INLINE_FUNCTION GraphicsViewNavigation::GraphicsViewNavigation() : rectItem(new QGraphicsRectItem), dragging(false) { QColor rect_color(250, 221, 0); rect_color.setAlpha(50); rectItem->setBrush(rect_color); rect_color.setAlpha(255); rectItem->setPen(QPen(rect_color, 0, ::Qt::DashLine)); rectItem->hide(); rectItem->setZValue(10000); } CGAL_INLINE_FUNCTION GraphicsViewNavigation::~GraphicsViewNavigation() { delete rectItem; } CGAL_INLINE_FUNCTION bool GraphicsViewNavigation::eventFilter(QObject *obj, QEvent *event) { QGraphicsView* v = qobject_cast(obj); if(v == NULL) { QWidget* viewport = qobject_cast(obj); if(viewport == NULL) { return false; } v = qobject_cast(viewport->parent()); if(v == NULL) { return false; } } switch(event->type()) { case QEvent::KeyPress: { QKeyEvent *keyEvent = static_cast(event); int offset = 10; if( (keyEvent->modifiers() & ::Qt::ShiftModifier) || (keyEvent->modifiers() & ::Qt::ControlModifier) ) { offset = 20; } switch (keyEvent->key()) { case ::Qt::Key_Up: translateView(v, 0, -offset); break; case ::Qt::Key_Down: translateView(v, 0, offset); break; case ::Qt::Key_Left: translateView(v, -offset, 0); break; case ::Qt::Key_Right: translateView(v, offset, 0); break; case ::Qt::Key_PageUp: v->rotate(-6); break; case ::Qt::Key_PageDown: v->rotate(6); break; case ::Qt::Key_Plus: scaleView(v, 1.2); break; case ::Qt::Key_Minus: scaleView(v, 1 / 1.2); break; case ::Qt::Key_Control: cursor_backup = v->cursor(); v->setCursor(::Qt::CrossCursor); CGAL_FALLTHROUGH; default: return false; } // display_parameters(); return true; break; } // end case KeyPress case QEvent::KeyRelease: { QKeyEvent *keyEvent = static_cast(event); if(keyEvent->key() == ::Qt::Key_Control) { if(rectItem->isVisible() ) { dragging = false; v->scene()->removeItem(rectItem); rectItem->hide(); } v->setCursor(cursor_backup); return true; } return false; break; } // end case KeyRelease case QEvent::Wheel: { QWheelEvent *wheelEvent = static_cast(event); if(wheelEvent->orientation() != ::Qt::Vertical) { return false; } double zoom_ratio = 240.0; if( (wheelEvent->modifiers() & ::Qt::ShiftModifier) || (wheelEvent->modifiers() & ::Qt::ControlModifier) ) { zoom_ratio = 120.0; } scaleView(v, pow((double)2, -wheelEvent->delta() / zoom_ratio)); // display_parameters(); return true; break; } // end case Wheel case QEvent::MouseButtonPress: { QMouseEvent* mouseEvent = static_cast(event); if( (mouseEvent->modifiers() == (::Qt::ControlModifier | ::Qt::ShiftModifier)) && mouseEvent->button() == ::Qt::RightButton ) { QPoint offset = mouseEvent->pos() - v->viewport()->rect().center(); translateView(v, offset.x(), offset.y()); return true; } else if( mouseEvent->modifiers() == ::Qt::ControlModifier ) { if(mouseEvent->button() == ::Qt::LeftButton) { rect_first_point = v->mapToScene(mouseEvent->pos()); rectItem->setRect(QRectF(rect_first_point, QSizeF(0.,0.))); rectItem->show(); v->scene()->addItem(rectItem); return true; } else if( mouseEvent->button() == ::Qt::RightButton) { dragging = true; dragging_start = v->mapToScene(mouseEvent->pos()); v->setCursor(::Qt::ClosedHandCursor); return true; } } return false; break; } // end case MouseRelease case QEvent::MouseMove: { QMouseEvent* mouseEvent = static_cast(event); QPointF pos = v->mapToScene(mouseEvent->pos()); QString xy = QString(" ") + QString::number(pos.x(),'g', 6) + " , " + QString::number(pos.y(),'g', 6) + " "; Q_EMIT mouseCoordinates(xy); if(rectItem->isVisible()) { QPointF size = v->mapToScene(mouseEvent->pos()); size = size - rect_first_point; rectItem->setRect(rect_first_point.x(), rect_first_point.y(), size.x(), size.y()); } if( dragging ) { // std::cerr << boost::format("mouseMove: globalpos=(%1%, %2%)\n" // " pos=(%3%, %4%)\n" // " sender=%5% (class %6%), parent class %7%\n") // % mouseEvent->globalPos().x() // % mouseEvent->globalPos().y() // % mouseEvent->pos().x() // % mouseEvent->pos().y() // % (&*obj) // % obj->metaObject()->className() // % obj->parent()->metaObject()->className(); // drag_to(mouseEvent->pos()); } break; } // end MouseMove case QEvent::MouseButtonRelease: { QMouseEvent* mouseEvent = static_cast(event); if(rectItem->isVisible() && mouseEvent->button() == ::Qt::LeftButton){ v->setSceneRect(v->sceneRect() | rectItem->rect()); v->fitInView(rectItem->rect(), ::Qt::KeepAspectRatio); v->scene()->removeItem(rectItem); rectItem->hide(); return true; } else if( mouseEvent->button() == ::Qt::RightButton ) { if(dragging) { dragging = false; drag_to(v, mouseEvent->pos()); v->setCursor(cursor_backup); return true; } } return false; break; } // end MouseRelease default: return false; } // end switch return false; } CGAL_INLINE_FUNCTION void GraphicsViewNavigation::scaleView(QGraphicsView* v, qreal scaleFactor) { QPointF center = v->mapToScene(v->viewport()->rect().center()); // qreal factor = v->matrix().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width(); //if (factor < 0.001 || factor > 2000) // return; v->scale(scaleFactor, scaleFactor); QPoint offset = v->mapFromScene(center) - v->viewport()->rect().center(); translateView(v, offset.x(), offset.y()); } CGAL_INLINE_FUNCTION void GraphicsViewNavigation::drag_to(QGraphicsView* v, QPoint new_pos) { QPoint dragging_start_in_view = v->mapFromScene(dragging_start); QPoint offset = new_pos - dragging_start_in_view; // std::cerr << boost::format("drag_to: origin=(%1%, %2%)\n" // " offset=(%3%, %4%)\n") // % dragging_start_in_view.x() % dragging_start_in_view.y() // % offset.x() % offset.y(); translateView(v, -offset.x(), -offset.y()); dragging_start_in_view = v->mapFromScene(dragging_start); // std::cerr << boost::format(" after=(%1%, %2%)\n") // % dragging_start_in_view.x() % dragging_start_in_view.y(); } CGAL_INLINE_FUNCTION void GraphicsViewNavigation::translateView(QGraphicsView* v, int dx, int dy) { if( dx == 0 && dy == 0 ) { return; } int horizontalScrollBarValue = v->horizontalScrollBar()->value(); int verticalScrollBarValue = v->verticalScrollBar()->value(); if( (horizontalScrollBarValue + dx <= v->horizontalScrollBar()->maximum()) && (horizontalScrollBarValue + dx >= v->horizontalScrollBar()->minimum()) && (verticalScrollBarValue + dy <= v->verticalScrollBar()->maximum()) && (verticalScrollBarValue + dy >= v->verticalScrollBar()->minimum()) ) { v->horizontalScrollBar()->setValue(horizontalScrollBarValue + dx); v->verticalScrollBar()->setValue(verticalScrollBarValue + dy); } else { QRect vp_rect = v->viewport()->rect(); QPointF new_center = v->mapToScene(vp_rect.center() + QPoint(dx, dy)); vp_rect |= vp_rect.translated(dx, dy); QRectF rect = mapToScene(v, vp_rect); v->setSceneRect(v->sceneRect() | rect); v->centerOn(new_center); // QGraphicsView::centerOn makes rounding errors. // The following two "if" make them unnoticable when dx==0 or dy==0. if(dx == 0) { v->horizontalScrollBar()->setValue(horizontalScrollBarValue); } if(dy == 0) { v->verticalScrollBar()->setValue(verticalScrollBarValue); } } // display_parameters(); } CGAL_INLINE_FUNCTION void GraphicsViewNavigation::display_parameters(QGraphicsView* v) { std::cerr << boost::format("matrix translation=(%1%, %2%)\n" " rotation=(%3% - %4% )\n" " (%5% - %6% )\n") % v->matrix().dx() % v->matrix().dy() % v->matrix().m11() % v->matrix().m12() % v->matrix().m21() % v->matrix().m22(); QRect vp_rect = v->viewport()->rect(); QPoint vp_top_left = vp_rect.topLeft(); QPoint vp_bottom_right = vp_rect.bottomRight(); QPointF top_left = v->mapToScene(vp_top_left); QPointF bottom_right = v->mapToScene(vp_bottom_right); std::cerr << boost::format("view=(%1% - %2%) x (%3% - %4%)\n") % top_left.x() % bottom_right.x() % top_left.y() % bottom_right.y(); std::cerr << boost::format("viewport=(%1% - %2%) x (%3% - %4%)\n") % vp_top_left.x() % vp_bottom_right.x() % vp_top_left.y() % vp_bottom_right.y(); std::cerr << boost::format("scrollbars=(%1% <= %2% <= %3%) x (%4% <= %5% <= %6%)\n") % v->horizontalScrollBar()->minimum() % v->horizontalScrollBar()->value() % v->horizontalScrollBar()->maximum() % v->verticalScrollBar()->minimum() % v->verticalScrollBar()->value() % v->verticalScrollBar()->maximum(); } } // namespace Qt } // namespace CGAL