diff --git a/docsrc/manual/editing-map-events.rst b/docsrc/manual/editing-map-events.rst index 4a7ee536..7837d48d 100644 --- a/docsrc/manual/editing-map-events.rst +++ b/docsrc/manual/editing-map-events.rst @@ -260,7 +260,7 @@ Shift Ruler Tool ---------- -The Ruler Tool provides a convenient way to measure distance on the map. This is particularly useful for scripting object movement. With the Pointer Tool selected you can activate the ruler with a Right-click. With the ruler active you can drag the mouse around to extend the ruler. The ruler can be deactivated with another Right-click, or locked in place with a Left-click (Left-click again to unlock the ruler). The dimensions of the ruler are displayed in a tool-tip and in the status bar in the bottom left corner of the widnow. +The Ruler Tool provides a convenient way to measure distance on the map. This is particularly useful for scripting object movement. With the Pointer Tool selected you can activate the ruler with a Right-click. With the ruler active you can move the mouse around to extend the ruler. The ruler can be deactivated with another Right-click, or locked in place with a Left-click (Left-click again to unlock the ruler). .. figure:: images/editing-map-events/event-tool-ruler.gif :alt: Measuring metatile distance with the Ruler Tool diff --git a/docsrc/manual/images/editing-map-events/event-tool-ruler.gif b/docsrc/manual/images/editing-map-events/event-tool-ruler.gif index fdbbd12f..707c2037 100644 Binary files a/docsrc/manual/images/editing-map-events/event-tool-ruler.gif and b/docsrc/manual/images/editing-map-events/event-tool-ruler.gif differ diff --git a/include/editor.h b/include/editor.h index fc8cfe26..c1492b0f 100644 --- a/include/editor.h +++ b/include/editor.h @@ -204,7 +204,6 @@ private slots: void onHoveredMapMovementPermissionCleared(); void onSelectedMetatilesChanged(); void onWheelZoom(int); - void onMapRulerLengthChanged(); signals: void objectsChanged(); @@ -213,6 +212,7 @@ signals: void wildMonDataChanged(); void warpEventDoubleClicked(QString mapName, QString warpNum); void currentMetatilesSelectionChanged(); + void mapRulerStatusChanged(const QString &); }; #endif // EDITOR_H diff --git a/include/mainwindow.h b/include/mainwindow.h index a9180402..d9377993 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -128,6 +128,7 @@ private slots: void openNewMapPopupWindow(int, QVariant); void onNewMapCreated(); void onMapCacheCleared(); + void onMapRulerStatusChanged(const QString &); void on_action_NewMap_triggered(); void on_actionNew_Tileset_triggered(); @@ -207,6 +208,7 @@ private slots: void on_lineEdit_filterBox_textChanged(const QString &arg1); + void moveEvent(QMoveEvent *event); void closeEvent(QCloseEvent *); void eventTabChanged(int index); @@ -229,6 +231,7 @@ private slots: private: Ui::MainWindow *ui; + QLabel *label_MapRulerStatus; TilesetEditor *tilesetEditor = nullptr; RegionMapEditor *regionMapEditor = nullptr; MapImageExporter *mapImageExporter = nullptr; diff --git a/include/ui/graphicsview.h b/include/ui/graphicsview.h index 85fb7a73..960f7dc4 100644 --- a/include/ui/graphicsview.h +++ b/include/ui/graphicsview.h @@ -22,6 +22,7 @@ protected: void mouseMoveEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); void drawForeground(QPainter *painter, const QRectF &rect); + void moveEvent(QMoveEvent *event); }; //Q_DECLARE_METATYPE(GraphicsView) diff --git a/include/ui/mapruler.h b/include/ui/mapruler.h index 0ee6e698..650ecd65 100644 --- a/include/ui/mapruler.h +++ b/include/ui/mapruler.h @@ -2,8 +2,7 @@ #define MAPRULER_H #include -#include -#include +#include class MapRuler : public QGraphicsObject, private QLine @@ -14,11 +13,15 @@ public: MapRuler(QColor innerColor = Qt::yellow, QColor borderColor = Qt::black) : innerColor(innerColor), borderColor(borderColor), - mapSize(QSize()) - { - init(); - } - void init(); + mapSize(QSize()), + statusMessage(QString()), + xRuler(QRect()), + yRuler(QRect()), + cornerTick(QLine()), + anchored(false), + locked(false) + { } + QRectF boundingRect() const override; QPainterPath shape() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override; @@ -45,16 +48,18 @@ public: // Ruler height in metatiles int height() const { return qAbs(deltaY()); } - QString statusMessage; - public slots: void mouseEvent(QGraphicsSceneMouseEvent *event); void setMapDimensions(const QSize &size); +signals: + void statusChanged(const QString &statusMessage); + private: QColor innerColor; QColor borderColor; QSize mapSize; + QString statusMessage; QRect xRuler; QRect yRuler; QLineF cornerTick; @@ -63,19 +68,13 @@ private: static int thickness; + void init(); + void setAnchor(const QPointF &scenePos); + void setEndPos(const QPointF &scenePos); QPoint snapToWithinBounds(QPoint pos) const; - void setAnchor(const QPointF &scenePos, const QPoint &screenPos); - void endAnchor(); - void setEndPos(const QPointF &scenePos, const QPoint &screenPos); - void showDimensions(const QPoint &screenPos) const; - void hideDimensions() const; void updateGeometry(); int pixWidth() const { return width() * 16; } int pixHeight() const { return height() * 16; } - -signals: - void lengthChanged(); - void deactivated(const QPoint &endPos); }; #endif // MAPRULER_H diff --git a/src/editor.cpp b/src/editor.cpp index 0b4eb6be7..ce45443c 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -25,8 +25,7 @@ Editor::Editor(Ui::MainWindow* ui) this->playerViewRect = new MovableRect(&this->settings->playerViewRectEnabled, 30 * 8, 20 * 8, qRgb(255, 255, 255)); this->cursorMapTileRect = new CursorTileRect(&this->settings->cursorTileRectEnabled, qRgb(255, 255, 255)); this->map_ruler = new MapRuler(); - connect(this->map_ruler, &MapRuler::lengthChanged, this, &Editor::onMapRulerLengthChanged); - connect(this->map_ruler, &MapRuler::deactivated, this, &Editor::onHoveredMapMetatileChanged); + connect(this->map_ruler, &MapRuler::statusChanged, this, &Editor::mapRulerStatusChanged); /// Instead of updating the selected events after every single undo action /// (eg when the user rolls back several at once), only reselect events when @@ -935,24 +934,12 @@ void Editor::onHoveredMapMetatileChanged(const QPoint &pos) { } } -void Editor::onMapRulerLengthChanged() { - const QPoint pos = map_ruler->endPos(); - ui->statusBar->showMessage(QString("X: %1, Y: %2, Scale = %3x; %4") - .arg(pos.x()) - .arg(pos.y()) - .arg(QString::number(pow(scale_base, scale_exp), 'g', 2)) - .arg(map_ruler->statusMessage)); -} - void Editor::onHoveredMapMetatileCleared() { this->playerViewRect->setVisible(false); this->cursorMapTileRect->setVisible(false); if (map_item->paintingMode == MapPixmapItem::PaintMode::Metatiles || map_item->paintingMode == MapPixmapItem::PaintMode::EventObjects) { this->ui->statusBar->clearMessage(); - if (this->map_ruler->isAnchored()) { - this->ui->statusBar->showMessage(this->map_ruler->statusMessage); - } } } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index f239d4d6..f40d94c1 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -41,6 +41,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), + label_MapRulerStatus(nullptr), selectedObject(nullptr), selectedWarp(nullptr), selectedTrigger(nullptr), @@ -66,6 +67,7 @@ MainWindow::MainWindow(QWidget *parent) : MainWindow::~MainWindow() { + delete label_MapRulerStatus; delete ui; } @@ -139,6 +141,17 @@ void MainWindow::initCustomUI() { } delete ui->frame_mapTools->layout(); ui->frame_mapTools->setLayout(flowLayout); + + // Floating QLabel tool-window that displays over the map when the ruler is active + label_MapRulerStatus = new QLabel(ui->graphicsView_Map); + label_MapRulerStatus->setObjectName("label_MapRulerStatus"); + label_MapRulerStatus->setWindowFlags(Qt::Tool | Qt::CustomizeWindowHint | Qt::FramelessWindowHint); + label_MapRulerStatus->setFrameShape(QFrame::Box); + label_MapRulerStatus->setMargin(3); + label_MapRulerStatus->setPalette(palette()); + label_MapRulerStatus->setAlignment(Qt::AlignCenter); + label_MapRulerStatus->setTextFormat(Qt::PlainText); + label_MapRulerStatus->setTextInteractionFlags(Qt::TextSelectableByMouse); } void MainWindow::initExtraSignals() { @@ -154,6 +167,7 @@ void MainWindow::initEditor() { connect(this->editor, SIGNAL(warpEventDoubleClicked(QString,QString)), this, SLOT(openWarpMap(QString,QString))); connect(this->editor, SIGNAL(currentMetatilesSelectionChanged()), this, SLOT(currentMetatilesSelectionChanged())); connect(this->editor, SIGNAL(wildMonDataChanged()), this, SLOT(onWildMonDataChanged())); + connect(this->editor, &Editor::mapRulerStatusChanged, this, &MainWindow::onMapRulerStatusChanged); this->loadUserSettings(); @@ -2288,6 +2302,23 @@ void MainWindow::onWildMonDataChanged() { projectHasUnsavedChanges = true; } +void MainWindow::onMapRulerStatusChanged(const QString &status) { + if (status.isEmpty()) { + label_MapRulerStatus->hide(); + } else if (label_MapRulerStatus->parentWidget()) { + label_MapRulerStatus->setText(status); + label_MapRulerStatus->adjustSize(); + label_MapRulerStatus->show(); + label_MapRulerStatus->move(label_MapRulerStatus->parentWidget()->mapToGlobal(QPoint(6, 6))); + } +} + +void MainWindow::moveEvent(QMoveEvent *event) { + QMainWindow::moveEvent(event); + if (label_MapRulerStatus->isVisible() && label_MapRulerStatus->parentWidget()) + label_MapRulerStatus->move(label_MapRulerStatus->parentWidget()->mapToGlobal(QPoint(6, 6))); +} + void MainWindow::on_action_Export_Map_Image_triggered() { showExportMapImageWindow(false); } diff --git a/src/ui/graphicsview.cpp b/src/ui/graphicsview.cpp index f0b73aa3..0e518cf7 100644 --- a/src/ui/graphicsview.cpp +++ b/src/ui/graphicsview.cpp @@ -21,3 +21,10 @@ void GraphicsView::drawForeground(QPainter *painter, const QRectF&) { item->render(painter); } } + +void GraphicsView::moveEvent(QMoveEvent *event) { + QGraphicsView::moveEvent(event); + QLabel *label_MapRulerStatus = findChild("label_MapRulerStatus", Qt::FindDirectChildrenOnly); + if (label_MapRulerStatus && label_MapRulerStatus->isVisible()) + label_MapRulerStatus->move(mapToGlobal(QPoint(6, 6))); +} diff --git a/src/ui/mapruler.cpp b/src/ui/mapruler.cpp index ed404176..1f4bcc36 100644 --- a/src/ui/mapruler.cpp +++ b/src/ui/mapruler.cpp @@ -1,26 +1,13 @@ #include "mapruler.h" #include "metatile.h" -#include #include #include #include -#include int MapRuler::thickness = 3; -void MapRuler::init() { - setVisible(false); - setPoints(QPoint(), QPoint()); - anchored = false; - locked = false; - statusMessage = QString("Ruler: 0"); - xRuler = QRect(); - yRuler = QRect(); - cornerTick = QLine(); -} - QRectF MapRuler::boundingRect() const { return QRectF(-thickness, -thickness, pixWidth() + thickness * 2, pixHeight() + thickness * 2); } @@ -54,8 +41,6 @@ bool MapRuler::eventFilter(QObject*, QEvent *event) { auto mouse_event = static_cast(event); if (mouse_event->button() == Qt::RightButton || anchored) { mouseEvent(mouse_event); - event->accept(); - return true; } } @@ -64,14 +49,14 @@ bool MapRuler::eventFilter(QObject*, QEvent *event) { void MapRuler::mouseEvent(QGraphicsSceneMouseEvent *event) { if (!anchored && event->button() == Qt::RightButton) { - setAnchor(event->scenePos(), event->screenPos()); + setAnchor(event->scenePos()); } else if (anchored) { if (event->button() == Qt::LeftButton) locked = !locked; if (event->button() == Qt::RightButton) - endAnchor(); + init(); else - setEndPos(event->scenePos(), event->screenPos()); + setEndPos(event->scenePos()); } } @@ -83,7 +68,41 @@ void MapRuler::setMapDimensions(const QSize &size) { void MapRuler::setEnabled(bool enabled) { QGraphicsItem::setEnabled(enabled); if (!enabled && anchored) - endAnchor(); + init(); +} + +void MapRuler::init() { + prepareGeometryChange(); + hide(); + setPoints(QPoint(), QPoint()); + statusMessage = QString(); + xRuler = QRect(); + yRuler = QRect(); + cornerTick = QLine(); + anchored = false; + locked = false; + emit statusChanged(statusMessage); +} + +void MapRuler::setAnchor(const QPointF &scenePos) { + QPoint pos = Metatile::coordFromPixmapCoord(scenePos); + pos = snapToWithinBounds(pos); + anchored = true; + locked = false; + setPoints(pos, pos); + updateGeometry(); + show(); +} + +void MapRuler::setEndPos(const QPointF &scenePos) { + if (locked) + return; + QPoint pos = Metatile::coordFromPixmapCoord(scenePos); + pos = snapToWithinBounds(pos); + const QPoint lastEndPos = endPos(); + setP2(pos); + if (pos != lastEndPos) + updateGeometry(); } QPoint MapRuler::snapToWithinBounds(QPoint pos) const { @@ -98,46 +117,6 @@ QPoint MapRuler::snapToWithinBounds(QPoint pos) const { return pos; } -void MapRuler::setAnchor(const QPointF &scenePos, const QPoint &screenPos) { - QPoint pos = Metatile::coordFromPixmapCoord(scenePos); - pos = snapToWithinBounds(pos); - anchored = true; - locked = false; - setPoints(pos, pos); - updateGeometry(); - setVisible(true); - showDimensions(screenPos); -} - -void MapRuler::endAnchor() { - emit deactivated(endPos()); - hideDimensions(); - prepareGeometryChange(); - init(); -} - -void MapRuler::setEndPos(const QPointF &scenePos, const QPoint &screenPos) { - if (locked) - return; - QPoint pos = Metatile::coordFromPixmapCoord(scenePos); - pos = snapToWithinBounds(pos); - const QPoint lastEndPos = endPos(); - setP2(pos); - if (pos != lastEndPos) - updateGeometry(); - showDimensions(screenPos); -} - -void MapRuler::showDimensions(const QPoint &screenPos) const { - // This is a hack to make the tool tip follow the cursor since it won't change position if the text is the same. - QToolTip::showText(screenPos + QPoint(16, -8), statusMessage + ' '); - QToolTip::showText(screenPos + QPoint(16, -8), statusMessage); -} - -void MapRuler::hideDimensions() const { - QToolTip::hideText(); -} - void MapRuler::updateGeometry() { prepareGeometryChange(); setPos(QPoint(left() * 16 + 7, top() * 16 + 7)); @@ -149,7 +128,8 @@ void MapRuler::updateGeometry() { xRuler = QRect(0, pixHeight(), pixWidth() + thickness, thickness); yRuler = QRect(0, 0, thickness, pixHeight() + thickness); cornerTick = QLineF(yRuler.x() + 0.5, xRuler.y() + thickness - 0.5, yRuler.x() + thickness, xRuler.y()); - statusMessage = QString("Ruler: Left %1, Up %2").arg(width()).arg(height()); + statusMessage = QString("Ruler: Left %1, Up %2\nStart(%3, %4), End(%5, %6)").arg(width()).arg(height()) + .arg(anchor().x()).arg(anchor().y()).arg(endPos().x()).arg(endPos().y()); } else if (deltaX() < 0) { // Bottom-left xRuler = QRect(0, 0, pixWidth() + thickness, thickness); @@ -158,6 +138,8 @@ void MapRuler::updateGeometry() { statusMessage = QString("Ruler: Left %1").arg(width()); if (deltaY()) statusMessage += QString(", Down %1").arg(height()); + statusMessage += QString("\nStart(%1, %2), End(%3, %4)") + .arg(anchor().x()).arg(anchor().y()).arg(endPos().x()).arg(endPos().y()); } else if (deltaY() < 0) { // Top-right xRuler = QRect(0, pixHeight(), pixWidth() + thickness, thickness); @@ -166,7 +148,8 @@ void MapRuler::updateGeometry() { statusMessage = QString("Ruler: "); if (deltaX()) statusMessage += QString("Right %1, ").arg(width()); - statusMessage += QString("Up %1").arg(height()); + statusMessage += QString("Up %1\nStart(%2, %3), End(%4, %5)").arg(height()) + .arg(anchor().x()).arg(anchor().y()).arg(endPos().x()).arg(endPos().y()); } else { // Bottom-right xRuler = QRect(0, 0, pixWidth() + thickness, thickness); @@ -181,9 +164,11 @@ void MapRuler::updateGeometry() { statusMessage += ", "; statusMessage += QString("Down: %1").arg(height()); } + statusMessage += QString("\nStart(%1, %2), End(%3, %4)") + .arg(anchor().x()).arg(anchor().y()).arg(endPos().x()).arg(endPos().y()); } else { - statusMessage += QString("0"); + statusMessage += QString("0\nStart(%1, %2)").arg(anchor().x()).arg(anchor().y()); } } - emit lengthChanged(); + emit statusChanged(statusMessage); }