diff --git a/CHANGELOG.md b/CHANGELOG.md index 41147092..1e076930 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project somewhat adheres to [Semantic Versioning](https://semver.org/sp ### Changed - Separate `File > Duplicate Current Map/Layout` into two options to allow duplicating the current layout when a map is open. - The name field now receives focus immediately for the new map/layout dialogs. +- The middle mouse button can now be used to pan around the map views, rather than needing to select the Map Tool. This is a very convenient shortcut that matches popular image-editing programs. + - Previously, the middle mouse button could be used as a shortcut with the pencil tool to switch to bucket-fill mode. This is now achieved using the `Alt` key. ### Fixed - Fix rare crash while quitting Porymap. diff --git a/docsrc/manual/editing-map-tiles.rst b/docsrc/manual/editing-map-tiles.rst index 373e5bc5..0bfccfa9 100644 --- a/docsrc/manual/editing-map-tiles.rst +++ b/docsrc/manual/editing-map-tiles.rst @@ -82,6 +82,8 @@ Pencil Tool The Pencil Tool |pencil-tool| (``Tools > Pencil``, or ``N``) is your bread and butter when editing maps. Simply left-click to paint your current metatile selection onto the map. You can click and drag to paint a bigger portion of the map. When clicking and dragging, the metatiles will be painted as if they are snapping to a grid. This simplifies things like painting large areas of trees. +While using the Pencil Tool (or really, viewing any map view in Porymap), the middle mouse button can be pressed as a hotkey to pan around the map. This is a convenient shortcut as an alternative to selecting the Move Tool. + .. figure:: images/editing-map-tiles/snapping-painting.gif :alt: Painting a Large Metatile Selection :align: center diff --git a/include/ui/graphicsview.h b/include/ui/graphicsview.h index bf3a7e42..fc4baaad 100644 --- a/include/ui/graphicsview.h +++ b/include/ui/graphicsview.h @@ -4,12 +4,15 @@ #include #include + // For general utility features that we add to QGraphicsView class GraphicsView : public QGraphicsView { Q_OBJECT public: - GraphicsView(QWidget *parent = nullptr) : QGraphicsView(parent) {} + GraphicsView(QWidget *parent = nullptr) : QGraphicsView(parent) { + viewport()->installEventFilter(this); + } void centerOn(const QGraphicsView *other) { if (other && other->viewport()) { @@ -17,6 +20,64 @@ public: QGraphicsView::centerOn(other->mapToScene(center)); } } + + bool eventFilter(QObject *obj, QEvent *event) { + // The goal here is to enable pressing the middle mouse button to pan around the graphics view. + // In Qt, the normal way to do this is via setDragMode(). However, that dragging mechanism only + // works via the LEFT mouse button. To support middle mouse button, we have to hijack the middle + // mouse button press event and simulate a fake left button press event. We're not done there, + // though. The children pixmap items will also be receiving that fake button press along with their + // own copy of the original middle-mouse press event because of how QGraphicsScene event handling + // works. So, we maintain a this->isMiddleButtonScrollInProgress boolean which the Editor can query + // to determine if it should ignore mouse events on the pixmap items (e.g. painting, bucket fill). + if (obj == viewport()) { + if (enableMiddleMouseButtonScroll) { + if (event->type() == QEvent::MouseButtonPress) { + QMouseEvent *mouseEvent = static_cast(event); + if (mouseEvent->button() == Qt::MiddleButton) { + this->setDragMode(QGraphicsView::DragMode::ScrollHandDrag); + QMouseEvent* pressEvent = new QMouseEvent( + QEvent::GraphicsSceneMousePress, + mouseEvent->pos(), Qt::MouseButton::LeftButton, + Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier); + + this->isMiddleButtonScrollInProgress = true; + this->mousePressEvent(pressEvent); + } + + return false; + } + else if (event->type() == QEvent::MouseButtonRelease) { + QMouseEvent *mouseEvent = static_cast(event); + QMouseEvent* releaseEvent = new QMouseEvent( + QEvent::GraphicsSceneMouseRelease, + mouseEvent->pos(), Qt::MouseButton::LeftButton, + Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier); + this->mouseReleaseEvent(releaseEvent); + this->setDragMode(desiredDragMode); + this->isMiddleButtonScrollInProgress = false; + } + } + } + + return QGraphicsView::eventFilter(obj, event); + } + + bool getIsMiddleButtonScrollInProgress() { + return this->isMiddleButtonScrollInProgress; + } + + void setDesiredDragMode(DragMode mode) { + this->setDragMode(mode); + this->desiredDragMode = mode; + } + +protected: + bool enableMiddleMouseButtonScroll; + +private: + bool isMiddleButtonScrollInProgress; + DragMode desiredDragMode; }; class NoScrollGraphicsView : public GraphicsView diff --git a/include/ui/mapview.h b/include/ui/mapview.h index 34610bb1..5f65b20b 100644 --- a/include/ui/mapview.h +++ b/include/ui/mapview.h @@ -16,8 +16,10 @@ class MapView : public GraphicsView Q_OBJECT public: - MapView() : GraphicsView() {} - MapView(QWidget *parent) : GraphicsView(parent) {} + MapView() : MapView(nullptr) {} + MapView(QWidget *parent) : GraphicsView(parent) { + this->enableMiddleMouseButtonScroll = true; + } Editor *editor; diff --git a/src/editor.cpp b/src/editor.cpp index 6bce4288..2d4add0d 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -217,8 +217,8 @@ void Editor::setEditAction(EditAction editAction) { this->cursorMapTileRect->setSingleTileMode(!(editAction == EditAction::Paint && this->editMode == EditMode::Metatiles)); auto dragMode = (editAction == EditAction::Move) ? QGraphicsView::ScrollHandDrag : QGraphicsView::NoDrag; - ui->graphicsView_Map->setDragMode(dragMode); - ui->graphicsView_Connections->setDragMode(dragMode); + ui->graphicsView_Map->setDesiredDragMode(dragMode); + ui->graphicsView_Connections->setDesiredDragMode(dragMode); // Update cursor if (this->settings->betterCursors) { @@ -1434,7 +1434,7 @@ void Editor::adjustStraightPathPos(QGraphicsSceneMouseEvent *event, LayoutPixmap void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *item) { auto editAction = getEditAction(); - if (editAction == EditAction::Move) { + if (editAction == EditAction::Move || ui->graphicsView_Map->getIsMiddleButtonScrollInProgress()) { event->ignore(); return; } @@ -1450,7 +1450,7 @@ void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, LayoutPixmapItem *i } else { item->updateMetatileSelection(event); } - } else if (event->buttons() & Qt::MiddleButton) { + } else if (event->modifiers() & Qt::AltModifier) { if (event->modifiers() & Qt::ControlModifier) { item->magicFill(event); } else {