From 4e3ccf45d4b5b1de4b30bc26d8aaa43cdfead472 Mon Sep 17 00:00:00 2001 From: baydam Date: Wed, 13 Jan 2016 20:38:43 +0000 Subject: [PATCH] Add "zoom in/out/reset and fit to content" buttons --- MainWindow.cpp | 46 ++++++--- MainWindow.h | 1 + MapperGLCanvas.cpp | 215 ++++++++++++++++++++++++++++++++------- MapperGLCanvas.h | 36 ++++++- OutputGLCanvas.cpp | 1 + mapmap.qrc | 84 ++++++--------- resources/qss/mapmap.qss | 28 +++++ 7 files changed, 308 insertions(+), 103 deletions(-) diff --git a/MainWindow.cpp b/MainWindow.cpp index 426fffe..ace6336 100644 --- a/MainWindow.cpp +++ b/MainWindow.cpp @@ -131,23 +131,25 @@ void MainWindow::handlePaintItemSelectionChanged() void MainWindow::handleMappingItemSelectionChanged() { - if (mappingList->selectedItems().empty()) - { - removeCurrentMapping(); - } - else - { - QListWidgetItem* item = mappingList->currentItem(); - currentSelectedItem = item; - - // Set current paint and mappings. - uid mappingId = getItemId(*item); - Mapping::ptr mapping = mappingManager->getMappingById(mappingId); - uid paintId = mapping->getPaint()->getId(); - setCurrentMapping(mappingId); - setCurrentPaint(paintId); - } + if (mappingList->selectedItems().empty()) + { + removeCurrentMapping(); + } + else + { + QListWidgetItem* item = mappingList->currentItem(); + currentSelectedItem = item; + // Set current paint and mappings. + uid mappingId = getItemId(*item); + Mapping::ptr mapping = mappingManager->getMappingById(mappingId); + uid paintId = mapping->getPaint()->getId(); + setCurrentMapping(mappingId); + setCurrentPaint(paintId); + // Enable or not zoom tool buttons + sourceCanvas->enableZoomToolButtons(item ? true : false); + destinationCanvas->enableZoomToolButtons(item ? true : false); + } // Update canvases. updateCanvases(); @@ -1605,6 +1607,14 @@ void MainWindow::createActions() displayUndoStackAction->setChecked(_displayUndoStack); // Manage show/hide of Undo Stack connect(displayUndoStackAction, SIGNAL(toggled(bool)), this, SLOT(displayUndoStack(bool))); + + // Toggle display of zoom tool buttons + displayZoomToolAction = new QAction(tr("Display &Zoom Toolbar"), this); + displayZoomToolAction->setShortcut(tr("Alt+Z")); + displayZoomToolAction->setCheckable(true); + displayZoomToolAction->setChecked(true); + connect(displayZoomToolAction, SIGNAL(toggled(bool)), sourceCanvas, SLOT(showZoomToolBar(bool))); + connect(displayZoomToolAction, SIGNAL(toggled(bool)), destinationCanvas, SLOT(showZoomToolBar(bool))); } void MainWindow::startFullScreen() @@ -1673,6 +1683,7 @@ void MainWindow::createMenus() viewMenu->addAction(displayTestSignalAction); viewMenu->addSeparator(); viewMenu->addAction(displayUndoStackAction); + viewMenu->addAction(displayZoomToolAction); // Run. runMenu = menuBar->addMenu(tr("&Run")); @@ -1831,6 +1842,8 @@ void MainWindow::readSettings() // new in 0.3.2 if (settings.contains("displayUndoStack")) displayUndoStackAction->setChecked(settings.value("displayUndoStack").toBool()); + if (settings.contains("zoomToolBar")) + displayZoomToolAction->setChecked(settings.value("zoomToolBar").toBool()); } void MainWindow::writeSettings() @@ -1848,6 +1861,7 @@ void MainWindow::writeSettings() settings.setValue("displayTestSignal", displayTestSignalAction->isChecked()); settings.setValue("osc_receive_port", config_osc_receive_port); settings.setValue("displayUndoStack", displayUndoStackAction->isChecked()); + settings.setValue("zoomToolBar", displayZoomToolAction->isChecked()); } bool MainWindow::okToContinue() diff --git a/MainWindow.h b/MainWindow.h index ea5683a..7e2fbdb 100644 --- a/MainWindow.h +++ b/MainWindow.h @@ -325,6 +325,7 @@ private: QAction *displayTestSignalAction; QAction *stickyVerticesAction; QAction *displayUndoStackAction; + QAction *displayZoomToolAction; enum { MaxRecentFiles = 10 }; enum { MaxRecentVideo = 5 }; diff --git a/MapperGLCanvas.cpp b/MapperGLCanvas.cpp index b72f899..e2658f2 100644 --- a/MapperGLCanvas.cpp +++ b/MapperGLCanvas.cpp @@ -30,7 +30,8 @@ MapperGLCanvas::MapperGLCanvas(MainWindow* mainWindow, QWidget* parent, const QG _activeVertex(NO_VERTEX), _shapeGrabbed(false), // comment out? _shapeFirstGrab(false), // comment out? - _zoomLevel(0) + _zoomLevel(0), + _shapeIsAdapted(false) { // For now clicking on the window doesn't do anything. setDragMode(QGraphicsView::NoDrag); @@ -59,6 +60,11 @@ MapperGLCanvas::MapperGLCanvas(MainWindow* mainWindow, QWidget* parent, const QG // Black background. this->scene()->setBackgroundBrush(Qt::black); + + // Create zoom tool buttons + createZoomToolButtons(); + // Disable zoom tool buttons + enableZoomToolButtons(false); } MShape::ptr MapperGLCanvas::getCurrentShape() @@ -98,6 +104,73 @@ void MapperGLCanvas::currentShapeWasChanged() emit shapeChanged(getCurrentShape().data()); } +void MapperGLCanvas::applyZoomToView() +{ + // Re-bound zoom (for consistency). + qreal zoomFactor = getZoomFactor(); + // Get first of the list of all the views + QGraphicsView* view = this->scene()->views().first(); + // Resets the view transformation matrix + view->resetMatrix(); + // Scale the current view + view->scale(zoomFactor, zoomFactor); + // And update + view->update(); +} + +void MapperGLCanvas::createZoomToolButtons() +{ + // Create zoom tool bar + _zoomToolBox = new QWidget(this); + _zoomToolBox->setWindowFlags(Qt::WindowStaysOnTopHint); + _zoomToolBox->setObjectName("zoom-toolbox"); + + // Create vertical layout for buttons + QVBoxLayout* buttonsLayout = new QVBoxLayout; + buttonsLayout->setMargin(0); + // Create buttons + // Zoom In button + _zoomInButton = new QPushButton; + _zoomInButton->setIcon(QIcon(":/zoom-in")); + _zoomInButton->setIconSize(QSize(22, 22)); + _zoomInButton->setToolTip(tr("Enlarge the shape")); + _zoomInButton->setFixedSize(32, 32); + _zoomInButton->setObjectName("zoom-in"); + connect(_zoomInButton, SIGNAL(clicked()), this, SLOT(increaseZoomLevel())); + // Zoom Out button + _zoomOutButton = new QPushButton; + _zoomOutButton->setIcon(QIcon(":/zoom-out")); + _zoomOutButton->setIconSize(QSize(22, 22)); + _zoomOutButton->setToolTip(tr("Shrink the shape")); + _zoomOutButton->setFixedSize(32, 32); + _zoomOutButton->setObjectName("zoom-out"); + connect(_zoomOutButton, SIGNAL(clicked()), this, SLOT(decreaseZoomLevel())); + // Reset to normal size button. + _resetZoomButton = new QPushButton; + _resetZoomButton->setIcon(QIcon(":/reset-zoom")); + _resetZoomButton->setIconSize(QSize(22, 22)); + _resetZoomButton->setToolTip(tr("Reset the shape to the normal size")); + _resetZoomButton->setFixedSize(32, 32); + _resetZoomButton->setObjectName("reset-zoom"); + connect(_resetZoomButton, SIGNAL(clicked()), this, SLOT(resetZoomLevel())); + // Fit to view button + _fitToViewButton = new QPushButton; + _fitToViewButton->setIcon(QIcon(":/zoom-fit")); + _fitToViewButton->setIconSize(QSize(22, 22)); + _fitToViewButton->setToolTip(tr("Fit the shape to content view")); + _fitToViewButton->setFixedSize(32, 32); + _fitToViewButton->setObjectName("zoom-fit"); + connect(_fitToViewButton, SIGNAL(clicked()), this, SLOT(fitShapeInView())); + + // Add buttons into layout + buttonsLayout->addWidget(_zoomInButton); + buttonsLayout->addWidget(_zoomOutButton); + buttonsLayout->addWidget(_resetZoomButton); + buttonsLayout->addWidget(_fitToViewButton); + // Insert layout in widget + _zoomToolBox->setLayout(buttonsLayout); +} + // void MapperGLCanvas::mousePressEvent(QMouseEvent* event) @@ -311,14 +384,12 @@ void MapperGLCanvas::keyPressEvent(QKeyEvent* event) // Checks if the key has been handled by this function or needs to be deferred to superclass. bool handledKey = false; - // Active vertex selected. if (hasActiveVertex()) { MShape::ptr shape = getCurrentShape(); QPoint pos = mapFromScene(shape->getVertex(_activeVertex)); handledKey = true; - switch (event->key()) { // TODO: key tab should switch to next vertex: not working because somehow caught at a higher level // to switch between frames of the layout @@ -342,12 +413,6 @@ void MapperGLCanvas::keyPressEvent(QKeyEvent* event) pos.rx()--; break; default: - if (event->matches(QKeySequence::Undo)) - undoStack->undo(); - - else if (event->matches(QKeySequence::Redo)) - undoStack->redo(); - else handledKey = false; break; } @@ -358,6 +423,22 @@ void MapperGLCanvas::keyPressEvent(QKeyEvent* event) // TODO: this will always be called even if no arrow key has been pressed (small performance issue). // Enable to Undo and Redo when arrow keys move the position of vertices undoStack->push(new MoveVertexCommand(this, TransformShapeCommand::STEP, _activeVertex, scenePos)); + } else { + handledKey = true; + if (event->matches(QKeySequence::Undo)) + undoStack->undo(); + else if (event->matches(QKeySequence::Redo)) + undoStack->redo(); + else if (event->matches(QKeySequence::ZoomIn)) + increaseZoomLevel(); + else if (event->matches(QKeySequence::ZoomOut)) + decreaseZoomLevel(); + else if (event->modifiers() == Qt::CTRL) { + if(event->key() == Qt::Key_0) + resetZoomLevel(); + } + else + handledKey = false; } // Defer unhandled keys to parent. @@ -466,38 +547,20 @@ void MapperGLCanvas::deselectAll() void MapperGLCanvas::wheelEvent(QWheelEvent *event) { - int deltaLevel = event->delta() / 120; - qreal zoomFactor = qPow(MM::ZOOM_FACTOR, _zoomLevel); - if (deltaLevel > 0) + // [-120]-----[-1]|[1]++++++[120] + _deltaLevel = event->delta() / 120; + + if (_deltaLevel > 0) { - // First check if we're already at max. - while (deltaLevel && zoomFactor < MM::ZOOM_MAX) { - _zoomLevel++; - deltaLevel--; - zoomFactor = qPow(MM::ZOOM_FACTOR, _zoomLevel); - } - zoomFactor = qMin(zoomFactor, MM::ZOOM_MAX); + // Increase zoom level + increaseZoomLevel(); } else { - // First check if we're already at min. - while (deltaLevel && zoomFactor > MM::ZOOM_MIN) { - _zoomLevel--; - deltaLevel++; - zoomFactor = qPow(MM::ZOOM_FACTOR, _zoomLevel); - } - zoomFactor = qMax(zoomFactor, MM::ZOOM_MIN); + // Decrease zoom level + decreaseZoomLevel(); } - // Re-bound zoom (for consistency). - zoomFactor = getZoomFactor(); - - // Apply zoom to view. - QGraphicsView* view = scene()->views().first(); - view->resetMatrix(); - view->scale(zoomFactor, zoomFactor); - view->update(); - // Accept wheel scrolling event. event->accept(); } @@ -517,6 +580,88 @@ bool MapperGLCanvas::eventFilter(QObject *target, QEvent *event) } } +void MapperGLCanvas::increaseZoomLevel() +{ + qreal zoomFactor = qPow(MM::ZOOM_FACTOR, _zoomLevel); + + if (zoomFactor < MM::ZOOM_MAX) { + _zoomLevel++; + if (_deltaLevel) + _deltaLevel--; + zoomFactor = qPow(MM::ZOOM_FACTOR, _zoomLevel); + } + zoomFactor = qMin(zoomFactor, MM::ZOOM_MAX); + + // Reset adaptation + _shapeIsAdapted = false; + + // Apply to view + applyZoomToView(); +} + +void MapperGLCanvas::decreaseZoomLevel() +{ + qreal zoomFactor = qPow(MM::ZOOM_FACTOR, _zoomLevel); + + if (zoomFactor > MM::ZOOM_MIN) { + _zoomLevel--; + if (_deltaLevel) + _deltaLevel++; + zoomFactor = qPow(MM::ZOOM_FACTOR, _zoomLevel); + } + zoomFactor = qMax(zoomFactor, MM::ZOOM_MIN); + + // Reset adaptation + _shapeIsAdapted = false; + + // Apply to view + applyZoomToView(); +} + +void MapperGLCanvas::resetZoomLevel() +{ + // Reset zoom level to zero + _zoomLevel = 0; + + // Reset adaptation + _shapeIsAdapted = false; + + // Apply to view + applyZoomToView(); +} + +void MapperGLCanvas::fitShapeInView() +{ + // Reset zoom level before fit it + //resetZoomLevel(); + // Get first of the list of all the views + QGraphicsView* view = scene()->views().first(); + // Scales the view matrix + view->fitInView(this->scene()->itemsBoundingRect(), Qt::KeepAspectRatio); + // Get the horizontal scaling factor + _scalingFactor = view->matrix().m11(); + + // Adapt shape + _shapeIsAdapted = true; +} + +void MapperGLCanvas::showZoomToolBar(bool visible) +{ + if (visible) + _zoomToolBox->show(); + else + _zoomToolBox->hide(); +} + +void MapperGLCanvas::enableZoomToolButtons(bool enabled) +{ + // Enable/Disable all button + _zoomInButton->setEnabled(enabled); + _zoomOutButton->setEnabled(enabled); + _resetZoomButton->setEnabled(enabled); + _fitToViewButton->setEnabled(enabled); +} + void MapperGLCanvas::_glueVertex(QPointF* p) { diff --git a/MapperGLCanvas.h b/MapperGLCanvas.h index 0124686..28a155d 100644 --- a/MapperGLCanvas.h +++ b/MapperGLCanvas.h @@ -86,11 +86,17 @@ public: bool shapeGrabbed() const { return _shapeGrabbed; } bool vertexGrabbed() const { return _vertexGrabbed; } - qreal getZoomFactor() const { return qBound(qPow(MM::ZOOM_FACTOR, _zoomLevel), MM::ZOOM_MIN, MM::ZOOM_MAX); } + //qreal getZoomFactor() const { return qBound(qPow(MM::ZOOM_FACTOR, _zoomLevel), MM::ZOOM_MIN, MM::ZOOM_MAX); } + qreal getZoomFactor() const { return _shapeIsAdapted + ? _scalingFactor + : qBound(MM::ZOOM_MIN, qPow(MM::ZOOM_FACTOR, _zoomLevel), MM::ZOOM_MAX); } /// This function needs to be called after a shape inside the canvas has been changed for appropriate signals to be activated. void currentShapeWasChanged(); + // Apply zoom to view + void applyZoomToView(); + protected: // void initializeGL(); // void resizeGL(int width, int height); @@ -147,9 +153,27 @@ private: // The zoom level (in number of steps). int _zoomLevel; + // The scaling factor + qreal _scalingFactor; + + bool _shapeIsAdapted; + + // The delta level + int _deltaLevel; + // Pointer to MainWindow UndoStack QUndoStack *undoStack; + // Buttons for toolbox layout + QWidget* _zoomToolBox; + QPushButton* _zoomInButton; + QPushButton* _zoomOutButton; + QPushButton* _resetZoomButton; + QPushButton* _fitToViewButton; + + // Create zoom tool buttons + void createZoomToolButtons(); + signals: void shapeChanged(MShape*); void imageChanged(); @@ -168,6 +192,16 @@ public slots: // Event Filter bool eventFilter(QObject *target, QEvent *event); + // Zoom + void increaseZoomLevel(); + void decreaseZoomLevel(); + void resetZoomLevel(); + void fitShapeInView(); + + // Show/Hide zoom tool buttons + void showZoomToolBar(bool visible); + void enableZoomToolButtons(bool enabled); + protected: // TODO: Perhaps the sticky-sensitivity should be configurable through GUI void _glueVertex(QPointF* p); diff --git a/OutputGLCanvas.cpp b/OutputGLCanvas.cpp index d03fd50..8bd8236 100644 --- a/OutputGLCanvas.cpp +++ b/OutputGLCanvas.cpp @@ -30,6 +30,7 @@ OutputGLCanvas::OutputGLCanvas(MainWindow* mainWindow, QWidget* parent, const QG // Disable scrollbars. setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + showZoomToolBar(false); } void OutputGLCanvas::drawForeground(QPainter *painter , const QRectF &rect) diff --git a/mapmap.qrc b/mapmap.qrc index 561c045..699af80 100644 --- a/mapmap.qrc +++ b/mapmap.qrc @@ -1,53 +1,35 @@ - - resources/images/icons/newdoc_w.png - resources/images/icons/open_w.png - resources/images/icons/save_w.png - resources/images/icons/save_w.png - - resources/images/icons/fullscreen_w.png - resources/images/icons/nofullscreen_w.png - resources/images/icons/ctrl2_w.png - - resources/images/icons/add_movie_w.png - resources/images/icons/add_img_w.png - resources/images/icons/add_paint_w.png - - resources/images/shapes/add_quad.png - resources/images/shapes/add_triangle.png - resources/images/shapes/add_circle.png - - - - resources/images/icons/play_w.png - resources/images/icons/pause_w.png - resources/images/icons/rewind_w.png - - resources/images/shapes/add_quad.png - resources/images/shapes/add_triangle.png - resources/images/shapes/add_circle.png - - resources/images/shapes/add_circle.png - - resources/images/logo/logomapmap.png - resources/images/logo/logo_m_big_mapmap.png - resources/images/logo/splash.png - - resources/fonts/HelveticaNeueLTPro-Bd.otf - - resources/fonts/HelveticaNeueLTPro-Bd.otf - - resources/images/test-signal/test-signal.svg - - resources/qss/mapmap.qss - + + resources/images/icons/newdoc_w.png + resources/images/icons/open_w.png + resources/images/icons/save_w.png + resources/images/icons/save_w.png + resources/images/icons/fullscreen_w.png + resources/images/icons/nofullscreen_w.png + resources/images/icons/ctrl2_w.png + resources/images/icons/add_movie_w.png + resources/images/icons/add_img_w.png + resources/images/icons/add_paint_w.png + resources/images/shapes/add_quad.png + resources/images/shapes/add_triangle.png + resources/images/shapes/add_circle.png + resources/images/icons/play_w.png + resources/images/icons/pause_w.png + resources/images/icons/rewind_w.png + resources/images/shapes/add_quad.png + resources/images/shapes/add_triangle.png + resources/images/shapes/add_circle.png + resources/images/shapes/add_circle.png + resources/images/logo/logomapmap.png + resources/images/logo/logo_m_big_mapmap.png + resources/images/logo/splash.png + resources/fonts/HelveticaNeueLTPro-Bd.otf + resources/fonts/HelveticaNeueLTPro-Bd.otf + resources/images/test-signal/test-signal.svg + resources/qss/mapmap.qss + resources/images/icons/zoom_reset_w.png + resources/images/icons/zoom_in_w.png + resources/images/icons/zoom_out_w.png + resources/images/icons/zoom_fit_w.png + - diff --git a/resources/qss/mapmap.qss b/resources/qss/mapmap.qss index 2bcb487..91ddaa7 100644 --- a/resources/qss/mapmap.qss +++ b/resources/qss/mapmap.qss @@ -58,6 +58,34 @@ QGraphicsView { border-style: none; } +QPushButton#zoom-in, +QPushButton#zoom-out, +QPushButton#reset-zoom, +QPushButton#zoom-fit { + background-color: rgba(0, 0, 0, 0%); +} + +QPushButton:hover#zoom-in, QPushButton:checked#zoom-in, +QPushButton:hover#zoom-out, QPushButton:checked#zoom-out, +QPushButton:hover#reset-zoom, QPushButton:checked#reset-zoom, +QPushButton:hover#zoom-fit, QPushButton:checked#zoom-fit { + background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1, + stop: 0 #0c0927, stop: 1 #191C28); + border-radius: 2px; + border: none; +} + +QPushButton:pressed#zoom-in, +QPushButton:pressed#zoom-out, +QPushButton:pressed#reset-zoom, +QPushButton:pressed#zoom-fit { + border: none; +} + +QWidget#zoom-toolbox { + background-color: #272a36; +} + /* QListView::item:selected:!active { background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,