porymap/src/ui/movablerect.cpp
GriffinR f776a31e4a
Merge pull request #719 from GriffinRichards/local-id
Support local ID strings, misc event fixes
2025-04-24 16:16:31 -04:00

185 lines
5.6 KiB
C++

#include <QCursor>
#include <QGraphicsSceneHoverEvent>
#include <QMessageBox>
#include "movablerect.h"
#include "utility.h"
MovableRect::MovableRect(bool *enabled, const QRectF &rect, const QRgb &color)
: QGraphicsRectItem(rect),
enabled(enabled),
baseRect(rect),
color(color)
{
updateVisibility();
}
/// Center rect on grid position (x, y)
void MovableRect::updateLocation(int x, int y) {
setRect(this->baseRect.x() + (x * 16),
this->baseRect.y() + (y * 16),
this->baseRect.width(),
this->baseRect.height());
updateVisibility();
}
void MovableRect::setActive(bool active) {
this->active = active;
updateVisibility();
}
void MovableRect::updateVisibility() {
setVisible(*this->enabled && this->active);
}
/******************************************************************************
************************************************************************
******************************************************************************/
ResizableRect::ResizableRect(QObject *parent, bool *enabled, int width, int height, QRgb color)
: QObject(parent),
MovableRect(enabled, QRect(0, 0, width * 16, height * 16), color)
{
setAcceptHoverEvents(true);
setFlags(this->flags() | QGraphicsItem::ItemIsMovable);
}
ResizableRect::Edge ResizableRect::detectEdge(int x, int y) {
QRectF edge = this->boundingRect();
if (x <= edge.left() + this->lineWidth) {
if (y >= edge.top() + 2 * this->lineWidth) {
if (y <= edge.bottom() - 2 * this->lineWidth) {
return ResizableRect::Edge::Left;
}
else {
return ResizableRect::Edge::BottomLeft;
}
}
else {
return ResizableRect::Edge::TopLeft;
}
}
else if (x >= edge.right() - this->lineWidth) {
if (y >= edge.top() + 2 * this->lineWidth) {
if (y <= edge.bottom() - 2 * this->lineWidth) {
return ResizableRect::Edge::Right;
}
else {
return ResizableRect::Edge::BottomRight;
}
}
else {
return ResizableRect::Edge::TopRight;
}
}
else {
if (y <= edge.top() + this->lineWidth) {
return ResizableRect::Edge::Top;
}
else if (y >= edge.bottom() - this->lineWidth) {
return ResizableRect::Edge::Bottom;
}
}
return ResizableRect::Edge::None;
}
void ResizableRect::updatePosFromRect(QRect newRect) {
prepareGeometryChange();
this->setRect(newRect);
emit this->rectUpdated(newRect);
}
void ResizableRect::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
switch (this->detectEdge(event->pos().x(), event->pos().y())) {
case ResizableRect::Edge::None:
default:
break;
case ResizableRect::Edge::Left:
case ResizableRect::Edge::Right:
this->setCursor(Qt::SizeHorCursor);
break;
case ResizableRect::Edge::Top:
case ResizableRect::Edge::Bottom:
this->setCursor(Qt::SizeVerCursor);
break;
case ResizableRect::Edge::TopRight:
case ResizableRect::Edge::BottomLeft:
this->setCursor(Qt::SizeBDiagCursor);
break;
case ResizableRect::Edge::TopLeft:
case ResizableRect::Edge::BottomRight:
this->setCursor(Qt::SizeFDiagCursor);
break;
}
}
void ResizableRect::hoverLeaveEvent(QGraphicsSceneHoverEvent *) {
this->unsetCursor();
}
void ResizableRect::mousePressEvent(QGraphicsSceneMouseEvent *event) {
int x = event->pos().x();
int y = event->pos().y();
this->clickedPos = event->scenePos();
this->clickedRect = this->rect().toAlignedRect();
this->clickedEdge = this->detectEdge(x, y);
}
void ResizableRect::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
int dx = Util::roundUp(event->scenePos().x() - this->clickedPos.x(), 16);
int dy = Util::roundUp(event->scenePos().y() - this->clickedPos.y(), 16);
QRect resizedRect = this->clickedRect;
switch (this->clickedEdge) {
case ResizableRect::Edge::None:
default:
return;
case ResizableRect::Edge::Left:
resizedRect.adjust(dx, 0, 0, 0);
break;
case ResizableRect::Edge::Right:
resizedRect.adjust(0, 0, dx, 0);
break;
case ResizableRect::Edge::Top:
resizedRect.adjust(0, dy, 0, 0);
break;
case ResizableRect::Edge::Bottom:
resizedRect.adjust(0, 0, 0, dy);
break;
case ResizableRect::Edge::TopRight:
resizedRect.adjust(0, dy, dx, 0);
break;
case ResizableRect::Edge::BottomLeft:
resizedRect.adjust(dx, 0, 0, dy);
break;
case ResizableRect::Edge::TopLeft:
resizedRect.adjust(dx, dy, 0, 0);
break;
case ResizableRect::Edge::BottomRight:
resizedRect.adjust(0, 0, dx, dy);
break;
}
// Lower limits: smallest possible size is 16x16 square
if (resizedRect.width() < 16) {
if (dx < 0) { // right sided adjustment made
resizedRect.setWidth(16);
} else { // left sided adjustment slightly more complicated
int dxMax = this->clickedRect.right() - this->clickedRect.left() - 16;
resizedRect.adjust(dxMax - dx, 0, 0, 0);
}
}
if (resizedRect.height() < 16) {
if (dy < 0) { // bottom
resizedRect.setHeight(16);
} else { // top
int dyMax = this->clickedRect.bottom() - this->clickedRect.top() - 16;
resizedRect.adjust(0, dyMax - dy, 0, 0);
}
}
// Upper limits: clip resized to limit rect
this->updatePosFromRect(resizedRect & this->limit);
}