diff --git a/include/editor.h b/include/editor.h index 033c267a..510d942e 100644 --- a/include/editor.h +++ b/include/editor.h @@ -21,6 +21,7 @@ #include "mappixmapitem.h" #include "settings.h" #include "movablerect.h" +#include "cursortilerect.h" class DraggablePixmapItem; class MetatilesPixmapItem; @@ -96,7 +97,7 @@ public: QList borderItems; QList gridLines; MovableRect *playerViewRect = nullptr; - MovableRect *cursorMapTileRect = nullptr; + CursorTileRect *cursorMapTileRect = nullptr; QGraphicsScene *scene_metatiles = nullptr; QGraphicsScene *scene_current_metatile_selection = nullptr; @@ -149,6 +150,9 @@ private: QString getMovementPermissionText(uint16_t collision, uint16_t elevation); private slots: + void onMapStartPaint(QGraphicsSceneMouseEvent *event, MapPixmapItem *item); + void onMapEndPaint(QGraphicsSceneMouseEvent *event, MapPixmapItem *item); + void setSmartPathCursorMode(QGraphicsSceneMouseEvent *event); void mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item); void mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixmapItem *item); void onConnectionMoved(MapConnection*); diff --git a/include/ui/cursortilerect.h b/include/ui/cursortilerect.h new file mode 100644 index 00000000..4edbcae4 --- /dev/null +++ b/include/ui/cursortilerect.h @@ -0,0 +1,77 @@ +#ifndef CURSORTILERECT_H +#define CURSORTILERECT_H + +#include +#include +#include + +class CursorTileRect : public QGraphicsItem +{ +public: + CursorTileRect(bool *enabled, QRgb color); + QRectF boundingRect() const override + { + int width = this->width; + int height = this->height; + if (this->singleTileMode) { + width = 16; + height = 16; + } else if (!this->rightClickSelectionAnchored && this->smartPathMode && this->selectionHeight == 3 && this->selectionWidth == 3) { + width = 32; + height = 32; + } + qreal penWidth = 4; + return QRectF(-penWidth, + -penWidth, + width + penWidth * 2, + height + penWidth * 2); + } + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget) override + { + int width = this->width; + int height = this->height; + if (this->singleTileMode) { + width = 16; + height = 16; + } else if (this->smartPathInEffect()) { + width = 32; + height = 32; + } + + painter->setPen(this->color); + painter->drawRect(-1, -1, width + 2, height + 2); + painter->setPen(QColor(0, 0, 0)); + painter->drawRect(-2, -2, width + 4, height + 4); + painter->drawRect(0, 0, width, height); + } + void initAnchor(int coordX, int coordY); + void stopAnchor(); + void initRightClickSelectionAnchor(int coordX, int coordY); + void stopRightClickSelectionAnchor(); + void setSmartPathMode(); + bool getSmartPathMode() { return this->smartPathMode; } + void setSingleTileMode(); + void stopSingleTileMode(); + void setNormalPathMode(); + void updateLocation(int x, int y); + void updateSelectionSize(int width, int height); + bool *enabled; +private: + int width; + int height; + bool anchored; + bool rightClickSelectionAnchored; + bool smartPathMode; + bool singleTileMode; + int anchorCoordX; + int anchorCoordY; + int selectionWidth; + int selectionHeight; + QRgb color; + bool smartPathInEffect(); +}; + + +#endif // CURSORTILERECT_H diff --git a/include/ui/mappixmapitem.h b/include/ui/mappixmapitem.h index 4ab66b21..e5723890 100644 --- a/include/ui/mappixmapitem.h +++ b/include/ui/mappixmapitem.h @@ -43,6 +43,8 @@ private: static QList smartPathTable; signals: + void startPaint(QGraphicsSceneMouseEvent *, MapPixmapItem *); + void endPaint(QGraphicsSceneMouseEvent *, MapPixmapItem *); void mouseEvent(QGraphicsSceneMouseEvent *, MapPixmapItem *); void hoveredMapMetatileChanged(int x, int y); void hoveredMapMetatileCleared(); diff --git a/porymap.pro b/porymap.pro index 1d22850a..fb81f994 100644 --- a/porymap.pro +++ b/porymap.pro @@ -32,6 +32,7 @@ SOURCES += src/core/block.cpp \ src/ui/collisionpixmapitem.cpp \ src/ui/connectionpixmapitem.cpp \ src/ui/currentselectedmetatilespixmapitem.cpp \ + src/ui/cursortilerect.cpp \ src/ui/eventpropertiesframe.cpp \ src/ui/filterchildrenproxymodel.cpp \ src/ui/graphicsview.cpp \ @@ -79,6 +80,7 @@ HEADERS += include/core/block.h \ include/ui/collisionpixmapitem.h \ include/ui/connectionpixmapitem.h \ include/ui/currentselectedmetatilespixmapitem.h \ + include/ui/cursortilerect.h \ include/ui/eventpropertiesframe.h \ include/ui/filterchildrenproxymodel.h \ include/ui/graphicsview.h \ diff --git a/src/editor.cpp b/src/editor.cpp index 1571d29a..72960f95 100644 --- a/src/editor.cpp +++ b/src/editor.cpp @@ -18,7 +18,7 @@ Editor::Editor(Ui::MainWindow* ui) this->selected_events = new QList; this->settings = new Settings(); this->playerViewRect = new MovableRect(&this->settings->playerViewRectEnabled, 30 * 8, 20 * 8, qRgb(255, 255, 255)); - this->cursorMapTileRect = new MovableRect(&this->settings->cursorTileRectEnabled, 16, 16, qRgb(255, 255, 255)); + this->cursorMapTileRect = new CursorTileRect(&this->settings->cursorTileRectEnabled, qRgb(255, 255, 255)); } void Editor::saveProject() { @@ -36,7 +36,7 @@ void Editor::save() { } void Editor::undo() { - if (current_view) { + if (current_view && map_item->paintingEnabled) { map->undo(); map_item->draw(); collision_item->draw(); @@ -44,7 +44,7 @@ void Editor::undo() { } void Editor::redo() { - if (current_view) { + if (current_view && map_item->paintingEnabled) { map->redo(); map_item->draw(); collision_item->draw(); @@ -75,6 +75,7 @@ void Editor::setEditingMap() { } setBorderItemsVisible(ui->checkBox_ToggleBorder->isChecked()); setConnectionItemsVisible(false); + this->cursorMapTileRect->stopSingleTileMode(); } void Editor::setEditingCollision() { @@ -94,6 +95,7 @@ void Editor::setEditingCollision() { } setBorderItemsVisible(ui->checkBox_ToggleBorder->isChecked()); setConnectionItemsVisible(false); + this->cursorMapTileRect->setSingleTileMode(); } void Editor::setEditingObjects() { @@ -111,6 +113,7 @@ void Editor::setEditingObjects() { } setBorderItemsVisible(ui->checkBox_ToggleBorder->isChecked()); setConnectionItemsVisible(false); + this->cursorMapTileRect->setSingleTileMode(); } void Editor::setEditingConnections() { @@ -139,6 +142,7 @@ void Editor::setEditingConnections() { } setBorderItemsVisible(true, 0.4); setConnectionItemsVisible(true); + this->cursorMapTileRect->setSingleTileMode(); } void Editor::setDiveEmergeControls() { @@ -350,6 +354,8 @@ void Editor::onHoveredMetatileSelectionCleared() { } void Editor::onSelectedMetatilesChanged() { + QPoint size = this->metatile_selector_item->getSelectionDimensions(); + this->cursorMapTileRect->updateSelectionSize(size.x(), size.y()); this->redrawCurrentMetatilesSelection(); } @@ -441,7 +447,7 @@ bool Editor::setMap(QString map_name) { return true; } -void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item) { +void Editor::onMapStartPaint(QGraphicsSceneMouseEvent *event, MapPixmapItem *item) { if (!item->paintingEnabled) { return; } @@ -449,8 +455,36 @@ void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item QPointF pos = event->pos(); int x = static_cast(pos.x()) / 16; int y = static_cast(pos.y()) / 16; - this->playerViewRect->updateLocation(x, y); - this->cursorMapTileRect->updateLocation(x, y); + if (event->buttons() & Qt::RightButton && (map_edit_mode == "paint" || map_edit_mode == "fill")) { + this->cursorMapTileRect->initRightClickSelectionAnchor(x, y); + } else { + this->cursorMapTileRect->initAnchor(x, y); + } +} + +void Editor::onMapEndPaint(QGraphicsSceneMouseEvent *event, MapPixmapItem *item) { + if (!item->paintingEnabled) { + return; + } + this->cursorMapTileRect->stopRightClickSelectionAnchor(); + this->cursorMapTileRect->stopAnchor(); +} + +void Editor::setSmartPathCursorMode(QGraphicsSceneMouseEvent *event) +{ + bool smartPathsEnabled = event->modifiers() & Qt::ShiftModifier; + if (smartPathsEnabled || settings->smartPathsEnabled) { + this->cursorMapTileRect->setSmartPathMode(); + } else { + this->cursorMapTileRect->setNormalPathMode(); + } +} + +void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item) { + if (!item->paintingEnabled) { + return; + } + if (map_edit_mode == "paint") { if (event->buttons() & Qt::RightButton) { item->updateMetatileSelection(event); @@ -461,6 +495,7 @@ void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item item->floodFill(event); } } else { + this->setSmartPathCursorMode(event); item->paint(event); } } else if (map_edit_mode == "select") { @@ -483,7 +518,14 @@ void Editor::mouseEvent_map(QGraphicsSceneMouseEvent *event, MapPixmapItem *item } else if (map_edit_mode == "shift") { item->shift(event); } + + QPointF pos = event->pos(); + int x = static_cast(pos.x()) / 16; + int y = static_cast(pos.y()) / 16; + this->playerViewRect->updateLocation(x, y); + this->cursorMapTileRect->updateLocation(x, y); } + void Editor::mouseEvent_collision(QGraphicsSceneMouseEvent *event, CollisionPixmapItem *item) { if (!item->paintingEnabled) { return; @@ -592,6 +634,10 @@ void Editor::displayMapMetatiles() { map_item = new MapPixmapItem(map, this->metatile_selector_item, this->settings); connect(map_item, SIGNAL(mouseEvent(QGraphicsSceneMouseEvent*,MapPixmapItem*)), this, SLOT(mouseEvent_map(QGraphicsSceneMouseEvent*,MapPixmapItem*))); + connect(map_item, SIGNAL(startPaint(QGraphicsSceneMouseEvent*,MapPixmapItem*)), + this, SLOT(onMapStartPaint(QGraphicsSceneMouseEvent*,MapPixmapItem*))); + connect(map_item, SIGNAL(endPaint(QGraphicsSceneMouseEvent*,MapPixmapItem*)), + this, SLOT(onMapEndPaint(QGraphicsSceneMouseEvent*,MapPixmapItem*))); connect(map_item, SIGNAL(hoveredMapMetatileChanged(int, int)), this, SLOT(onHoveredMapMetatileChanged(int, int))); connect(map_item, SIGNAL(hoveredMapMetatileCleared()), diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 054f0e00..8759c319 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1623,6 +1623,7 @@ void MainWindow::on_toolButton_Paint_clicked() { editor->map_edit_mode = "paint"; editor->settings->mapCursor = QCursor(QPixmap(":/icons/pencil_cursor.ico"), 10, 10); + editor->cursorMapTileRect->stopSingleTileMode(); ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); @@ -1635,6 +1636,7 @@ void MainWindow::on_toolButton_Select_clicked() { editor->map_edit_mode = "select"; editor->settings->mapCursor = QCursor(QPixmap(":/icons/cursor.ico"), 0, 0); + editor->cursorMapTileRect->setSingleTileMode(); ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); @@ -1647,6 +1649,7 @@ void MainWindow::on_toolButton_Fill_clicked() { editor->map_edit_mode = "fill"; editor->settings->mapCursor = QCursor(QPixmap(":/icons/fill_color_cursor.ico"), 10, 10); + editor->cursorMapTileRect->setSingleTileMode(); ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); @@ -1659,6 +1662,7 @@ void MainWindow::on_toolButton_Dropper_clicked() { editor->map_edit_mode = "pick"; editor->settings->mapCursor = QCursor(QPixmap(":/icons/pipette_cursor.ico"), 10, 10); + editor->cursorMapTileRect->setSingleTileMode(); ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); @@ -1671,6 +1675,7 @@ void MainWindow::on_toolButton_Move_clicked() { editor->map_edit_mode = "move"; editor->settings->mapCursor = QCursor(QPixmap(":/icons/move.ico"), 7, 7); + editor->cursorMapTileRect->setSingleTileMode(); ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -1683,6 +1688,7 @@ void MainWindow::on_toolButton_Shift_clicked() { editor->map_edit_mode = "shift"; editor->settings->mapCursor = QCursor(QPixmap(":/icons/shift_cursor.ico"), 10, 10); + editor->cursorMapTileRect->setSingleTileMode(); ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); @@ -1837,7 +1843,13 @@ void MainWindow::on_pushButton_clicked() void MainWindow::on_checkBox_smartPaths_stateChanged(int selected) { - editor->settings->smartPathsEnabled = selected == Qt::Checked; + bool enabled = selected == Qt::Checked; + editor->settings->smartPathsEnabled = enabled; + if (enabled) { + editor->cursorMapTileRect->setSmartPathMode(); + } else { + editor->cursorMapTileRect->setNormalPathMode(); + } } void MainWindow::on_checkBox_ToggleBorder_stateChanged(int selected) diff --git a/src/ui/cursortilerect.cpp b/src/ui/cursortilerect.cpp new file mode 100644 index 00000000..8881e7b6 --- /dev/null +++ b/src/ui/cursortilerect.cpp @@ -0,0 +1,100 @@ +#include "cursortilerect.h" +#include "log.h" + +CursorTileRect::CursorTileRect(bool *enabled, QRgb color) +{ + this->enabled = enabled; + this->color = color; + this->width = 16; + this->height = 16; + this->smartPathMode = false; + this->singleTileMode = false; + this->anchored = false; + this->rightClickSelectionAnchored = false; + this->anchorCoordX = 0; + this->anchorCoordY = 0; + this->selectionWidth = 1; + this->selectionHeight = 1; +} + +void CursorTileRect::initAnchor(int coordX, int coordY) +{ + this->anchorCoordX = coordX; + this->anchorCoordY = coordY; + this->anchored = true; +} + +void CursorTileRect::stopAnchor() +{ + this->anchored = false; +} + +void CursorTileRect::initRightClickSelectionAnchor(int coordX, int coordY) +{ + this->anchorCoordX = coordX; + this->anchorCoordY = coordY; + this->rightClickSelectionAnchored = true; +} + +void CursorTileRect::stopRightClickSelectionAnchor() +{ + this->rightClickSelectionAnchored = false; +} + +void CursorTileRect::updateSelectionSize(int width, int height) +{ + this->selectionWidth = width; + this->selectionHeight = height; + this->width = width * 16; + this->height = height * 16; + this->prepareGeometryChange(); + this->update(); +} + +void CursorTileRect::setSmartPathMode() +{ + this->smartPathMode = true; +} + +void CursorTileRect::setSingleTileMode() +{ + this->singleTileMode = true; +} + +void CursorTileRect::stopSingleTileMode() +{ + this->singleTileMode = false; +} + +void CursorTileRect::setNormalPathMode() +{ + this->smartPathMode = false; +} + +bool CursorTileRect::smartPathInEffect() +{ + return !this->rightClickSelectionAnchored && this->smartPathMode && this->selectionHeight == 3 && this->selectionWidth == 3; +} + +void CursorTileRect::updateLocation(int coordX, int coordY) +{ + if (!this->singleTileMode) { + if (this->rightClickSelectionAnchored) { + coordX = qMin(coordX, this->anchorCoordX); + coordY = qMin(coordY, this->anchorCoordY); + } + else if (this->anchored && !this->smartPathInEffect()) { + int xDiff = coordX - this->anchorCoordX; + int yDiff = coordY - this->anchorCoordY; + if (xDiff < 0 && xDiff % this->selectionWidth != 0) xDiff -= this->selectionWidth; + if (yDiff < 0 && yDiff % this->selectionHeight != 0) yDiff -= this->selectionHeight; + + coordX = this->anchorCoordX + (xDiff / this->selectionWidth) * this->selectionWidth; + coordY = this->anchorCoordY + (yDiff / this->selectionHeight) * this->selectionHeight; + } + } + + this->setX(coordX * 16); + this->setY(coordY * 16); + this->setVisible(*this->enabled); +} diff --git a/src/ui/mappixmapitem.cpp b/src/ui/mappixmapitem.cpp index 0c7571bf..758b6802 100644 --- a/src/ui/mappixmapitem.cpp +++ b/src/ui/mappixmapitem.cpp @@ -515,6 +515,7 @@ void MapPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { int y = static_cast(pos.y()) / 16; this->paint_tile_initial_x = x; this->paint_tile_initial_y = y; + emit startPaint(event, this); emit mouseEvent(event, this); } void MapPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { @@ -524,5 +525,6 @@ void MapPixmapItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { emit mouseEvent(event, this); } void MapPixmapItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + emit endPaint(event, this); emit mouseEvent(event, this); }