#include "customrectitem.h" #include CustomRectItem::CustomRectItem(QGraphicsItem * parent) : QGraphicsRectItem(parent) , m_points() , m_cursorRotate() , m_handles() , m_handle(MOUSEHANDLE::handleNone) , m_cursor(Qt::ArrowCursor) , m_mousePressPos() , m_mousePressRect() , m_mouseRotateStart() , m_fLastAngle(0.0) , m_bhandleSelected(MOUSEHANDLE::handleNone) , m_isHover(false) { setAcceptHoverEvents(true); setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges); m_handles.insert(std::make_pair(MOUSEHANDLE::handleTopLeft, QRectF())); m_handles.insert(std::make_pair(MOUSEHANDLE::handleTopMiddle, QRectF())); m_handles.insert(std::make_pair(MOUSEHANDLE::handleTopRight, QRectF())); m_handles.insert(std::make_pair(MOUSEHANDLE::handleMiddleLeft, QRectF())); m_handles.insert(std::make_pair(MOUSEHANDLE::handleMiddleRight, QRectF())); m_handles.insert(std::make_pair(MOUSEHANDLE::handleBottomLeft, QRectF())); m_handles.insert(std::make_pair(MOUSEHANDLE::handleBottomMiddle, QRectF())); m_handles.insert(std::make_pair(MOUSEHANDLE::handleBottomRight, QRectF())); m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateTopLeft, QPointF())); m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateTopMiddle, QPointF())); m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateTopRight, QPointF())); m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateMiddleRight, QPointF())); m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateBottomRight, QPointF())); m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateBottomMiddle, QPointF())); m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateBottomLeft, QPointF())); m_points.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateMiddleLeft, QPointF())); m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateTopLeft, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateTopLeft]).scaled(c_rotate_cursor_size)))); m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateTopMiddle, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateTopMiddle]).scaled(c_rotate_cursor_size)))); m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateTopRight, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateTopRight]).scaled(c_rotate_cursor_size)))); m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateMiddleRight, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateMiddleRight]).scaled(c_rotate_cursor_size)))); m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateBottomRight, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateBottomRight]).scaled(c_rotate_cursor_size)))); m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateBottomMiddle, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateBottomMiddle]).scaled(c_rotate_cursor_size)))); m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateBottomLeft, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateBottomLeft]).scaled(c_rotate_cursor_size)))); m_cursorRotate.insert(std::make_pair(MOUSEROTATEHANDLE::handleRotateMiddleLeft, QCursor(QPixmap(mapCursors[MOUSEROTATEHANDLE::handleRotateMiddleLeft]).scaled(c_rotate_cursor_size)))); updateHandlesPos(); } CustomRectItem::~CustomRectItem() { } QPainterPath CustomRectItem::shape() const { QPainterPath path = QPainterPath(); path.addRect(this->rect()); if (this->isSelected()) { for (auto shape : m_handles) path.addEllipse(shape.second); } return path; } void CustomRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { QStyleOptionGraphicsItem op; if (widget == nullptr) op = *option; else op.initFrom(widget); if (option->state & QStyle::State_Selected) op.state = QStyle::State_None; QGraphicsRectItem::paint(painter, &op, widget); if (isSelected() == true) { painter->setRenderHint(QPainter::Antialiasing); painter->setBrush(QBrush(QColor(255, 255, 255, 255))); painter->setPen(QPen(QColor(0x293a56ff), 1.0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); for (auto it : m_handles) { if (m_bhandleSelected == MOUSEHANDLE::handleNone || it.first == m_bhandleSelected){ painter->drawRect(it.second); } } //绘制旋转圆形 QPen mPen; mPen.setWidth(2); mPen.setColor(Qt::green); painter->setPen(mPen); QRectF rect = m_handles[MOUSEHANDLE::handleTopMiddle2]; painter->drawEllipse(rect);//绘制圆形 } } QRectF CustomRectItem::boundingRect() const { auto o = c_handle_size + c_handle_space; return this->rect().adjusted(-o, -o, o, o); } void CustomRectItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event) { QGraphicsRectItem::hoverEnterEvent(event); m_isHover = true; } void CustomRectItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * event) { setCursor(Qt::ArrowCursor); QGraphicsRectItem::hoverLeaveEvent(event); m_isHover = false; } void CustomRectItem::hoverMoveEvent(QGraphicsSceneHoverEvent * event) { if (isSelected()) { m_handle = handleAt(event->pos()); if (MOUSEHANDLE::handleNone == m_handle){ m_cursor = Qt::SizeAllCursor; }else if(MOUSEHANDLE::handleTopMiddle2 == m_handle){ m_cursor = Qt::OpenHandCursor; } else { float angle = this->rotation() + 22.5; while (angle >= 360.0) angle -= 360; // choose the right cursor m_cursor = handleCursors[((int)m_handle + (int)(angle / 45) - 1) % c_handle_cursors_size]; } setCursor(m_cursor); } QGraphicsRectItem::hoverMoveEvent(event); } void CustomRectItem::mouseMoveEvent(QGraphicsSceneMouseEvent * event) { getRotateCursor(event->pos()); if (MOUSEHANDLE::handleNone != m_bhandleSelected) interactiveResize(event->pos()); else QGraphicsRectItem::mouseMoveEvent(event); } void CustomRectItem::mousePressEvent(QGraphicsSceneMouseEvent * event) { m_bhandleSelected = handleAt(event->pos()); qDebug() << "mousePressEvent" << m_bhandleSelected << endl; if (MOUSEHANDLE::handleNone != m_bhandleSelected) { m_mousePressPos = event->pos(); m_mousePressRect = boundingRect(); }else if(MOUSEHANDLE::handleTopMiddle2 == m_bhandleSelected){ qDebug() << "handleTopMiddle2" << endl; } QGraphicsRectItem::mousePressEvent(event); } void CustomRectItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event) { auto rr = this->rect(); auto angle = qDegreesToRadians(this->rotation()); auto p1 = rr.center(); auto origin = this->transformOriginPoint(); QPointF p2 = QPointF(0, 0); p2.setX(origin.x() + qCos(angle)*(p1.x() - origin.x()) - qSin(angle)*(p1.y() - origin.y())); p2.setY(origin.y() + qSin(angle)*(p1.x() - origin.x()) + qCos(angle)*(p1.y() - origin.y())); auto diff = p1 - p2; this->setRect(rr.adjusted(-diff.x(), -diff.y(), -diff.x(), -diff.y())); setTransformOriginPoint(this->rect().center()); updateHandlesPos(); m_bhandleSelected = MOUSEHANDLE::handleNone; m_mousePressPos = QPointF(); m_mousePressRect = QRectF(); this->update(); QGraphicsRectItem::mouseReleaseEvent(event); } void CustomRectItem::keyPressEvent(QKeyEvent * event) { switch (event->key()) { case Qt::Key_Up: this->moveBy(0, -1); event->setAccepted(true); break; case Qt::Key_Down: this->moveBy(0, 1); event->setAccepted(true); break; case Qt::Key_Left: this->moveBy(-1, 0); event->setAccepted(true); break; case Qt::Key_Right: this->moveBy(1, 0); event->setAccepted(true); break; default: event->setAccepted(false); break; } //QGraphicsRectItem::keyPressEvent(event); } void CustomRectItem::updateHandlesPos() { auto s = c_handle_size; auto b = boundingRect(); m_handles[MOUSEHANDLE::handleTopLeft] = QRectF(b.left(), b.top(), s, s); m_handles[MOUSEHANDLE::handleTopMiddle] = QRectF(b.center().x() - s / 2, b.top(), s, s); m_handles[MOUSEHANDLE::handleTopRight] = QRectF(b.right() - s, b.top(), s, s); m_handles[MOUSEHANDLE::handleMiddleLeft] = QRectF(b.left(), b.center().y() - s / 2, s, s); m_handles[MOUSEHANDLE::handleMiddleRight] = QRectF(b.right() - s, b.center().y() - s / 2, s, s); m_handles[MOUSEHANDLE::handleBottomLeft] = QRectF(b.left(), b.bottom() - s, s, s); m_handles[MOUSEHANDLE::handleBottomMiddle] = QRectF(b.center().x() - s / 2, b.bottom() - s, s, s); m_handles[MOUSEHANDLE::handleBottomRight] = QRectF(b.right() - s, b.bottom() - s, s, s); m_handles[MOUSEHANDLE::handleTopMiddle2] = QRectF(b.center().x() - s / 2, b.top()-20, s, s); } bool CustomRectItem::isHover() { return m_isHover; } QCursor CustomRectItem::getRotateCursor(const QPointF & point) { if (m_isHover == true || !isSelected()) return QCursor(); if (boundingRect().contains(mapFromScene(point))) return QCursor(); auto srcRect = rect(); auto frameRect = srcRect.adjusted(-c_rotate_tolerance, -c_rotate_tolerance, c_rotate_tolerance, c_rotate_tolerance); QPointF innerPoint = mapFromScene(point); if (!frameRect.contains(innerPoint)) return QCursor(); m_points[MOUSEROTATEHANDLE::handleRotateTopLeft] = srcRect.topLeft(); m_points[MOUSEROTATEHANDLE::handleRotateTopMiddle] = QPointF(srcRect.center().x(), srcRect.top()); m_points[MOUSEROTATEHANDLE::handleRotateTopRight] = srcRect.topRight(); m_points[MOUSEROTATEHANDLE::handleRotateMiddleRight] = QPointF(srcRect.right(), srcRect.center().y()); m_points[MOUSEROTATEHANDLE::handleRotateBottomRight] = srcRect.bottomRight(); m_points[MOUSEROTATEHANDLE::handleRotateBottomMiddle] = QPointF(srcRect.center().x(), srcRect.bottom()); m_points[MOUSEROTATEHANDLE::handleRotateBottomLeft] = srcRect.bottomLeft(); m_points[MOUSEROTATEHANDLE::handleRotateMiddleLeft] = QPointF(srcRect.left(), srcRect.center().y()); auto ret = MOUSEROTATEHANDLE::handleRotateNone; float l = 3.4028235E38; for (auto& iter : m_points) { auto length = getLength2(iter.second, innerPoint); if (length < l) { l = length; ret = iter.first; } } if (ret == MOUSEROTATEHANDLE::handleRotateNone) return QCursor(); float angle = this->rotation() + 22.5; while (angle >= 360.0) angle -= 360; ret = MOUSEROTATEHANDLE(((int)ret + (int)( angle/ 45)) % c_rotate_cursors_size); if (ret == MOUSEROTATEHANDLE::handleRotateNone) ret = MOUSEROTATEHANDLE::handleRotateTopLeft; return m_cursorRotate[ret]; } void CustomRectItem::setRotateStart(const QPointF & point) { m_mouseRotateStart = point; m_fLastAngle = rotation(); } void CustomRectItem::setRotateEnd(const QPointF & point) { QPointF ori = mapToScene(transformOriginPoint()); QPointF v1 = m_mouseRotateStart - ori; QPointF v2 = point - ori; float angle = atan2f(v2.y(), v2.x()) - atan2f(v1.y(), v1.x()); angle = m_fLastAngle + angle * 180 / 3.1415926; // angle = [0,360) while (angle < 0.0) angle += 360; while (angle >= 360.0) angle -= 360; setRotation(angle); } CustomRectItem::MOUSEHANDLE CustomRectItem::handleAt(const QPointF& point) { for (auto it : m_handles) { if (it.second.contains(point)) return it.first; } return MOUSEHANDLE::handleNone; } void CustomRectItem::interactiveResize(const QPointF & mousePos) { auto offset = c_handle_size + c_handle_space; auto bRect = boundingRect(); auto rr = this->rect(); auto diff = QPointF(0, 0); prepareGeometryChange(); if (m_bhandleSelected == MOUSEHANDLE::handleTopLeft) { auto fromX = m_mousePressRect.left(); auto fromY = m_mousePressRect.top(); auto toX = fromX + mousePos.x() - m_mousePressRect.x(); auto toY = fromY + mousePos.y() - m_mousePressRect.y(); if (!(toX - fromX >= rr.width() || toY - fromY >= rr.height())) { diff.setX(toX - fromX); diff.setY(toY - fromY); bRect.setLeft(toX); bRect.setTop(toY); rr.setLeft(bRect.left() + offset); rr.setTop(bRect.top() + offset); this->setRect(rr); } } else if (m_bhandleSelected == MOUSEHANDLE::handleTopMiddle) { auto fromY = m_mousePressRect.top(); auto toY = fromY + mousePos.y() - m_mousePressPos.y(); if (!(toY - fromY >= rr.height())) { diff.setY(toY - fromY); bRect.setTop(toY); rr.setTop(bRect.top() + offset); this->setRect(rr); } } else if (m_bhandleSelected == MOUSEHANDLE::handleTopRight) { auto fromX = m_mousePressRect.right(); auto fromY = m_mousePressRect.top(); auto toX = fromX + mousePos.x() - m_mousePressPos.x(); auto toY = fromY + mousePos.y() - m_mousePressPos.y(); if (!(fromX - toX >= rr.width() || toY - fromY >= rr.height())) { diff.setX(toX - fromX); diff.setY(toY - fromY); bRect.setRight(toX); bRect.setTop(toY); rr.setRight(bRect.right() - offset); rr.setTop(bRect.top() + offset); this->setRect(rr); } } else if (m_bhandleSelected == MOUSEHANDLE::handleMiddleLeft) { auto fromX = m_mousePressRect.left(); auto toX = fromX + mousePos.x() - m_mousePressPos.x(); if (!(toX - fromX >= rr.width())) { diff.setX(toX - fromX); bRect.setLeft(toX); rr.setLeft(bRect.left() + offset); this->setRect(rr); } } else if (m_bhandleSelected == MOUSEHANDLE::handleMiddleRight) { auto fromX = m_mousePressRect.right(); auto toX = fromX + mousePos.x() - m_mousePressPos.x(); if (!(fromX - toX >= rr.width())) { diff.setX(toX - fromX); bRect.setRight(toX); rr.setRight(bRect.right() - offset); this->setRect(rr); } } else if (m_bhandleSelected == MOUSEHANDLE::handleBottomLeft) { auto fromX = m_mousePressRect.left(); auto fromY = m_mousePressRect.bottom(); auto toX = fromX + mousePos.x() - m_mousePressPos.x(); auto toY = fromY + mousePos.y() - m_mousePressPos.y(); if (!(toX - fromX >= rr.width() || fromY - toY >= rr.height())) { diff.setX(toX - fromX); diff.setY(toY - fromY); bRect.setLeft(toX); bRect.setBottom(toY); rr.setLeft(bRect.left() + offset); rr.setBottom(bRect.bottom() - offset); this->setRect(rr); } } else if (m_bhandleSelected == MOUSEHANDLE::handleBottomMiddle) { auto fromY = m_mousePressRect.bottom(); auto toY = fromY + mousePos.y() - m_mousePressPos.y(); if (!(fromY - toY >= rr.height())) { diff.setY(toY - fromY); bRect.setBottom(toY); rr.setBottom(bRect.bottom() - offset); this->setRect(rr); } } else if (m_bhandleSelected == MOUSEHANDLE::handleBottomRight) { auto fromX = m_mousePressRect.right(); auto fromY = m_mousePressRect.bottom(); auto toX = fromX + mousePos.x() - m_mousePressPos.x(); auto toY = fromY + mousePos.y() - m_mousePressPos.y(); if (!(fromX - toX >= rr.width() || fromY - toY >= rr.height())) { diff.setX(toX - fromX); diff.setY(toY - fromY); bRect.setRight(toX); bRect.setBottom(toY); rr.setRight(bRect.right() - offset); rr.setBottom(bRect.bottom() - offset); this->setRect(rr); } } updateHandlesPos(); } float CustomRectItem::getLength2(const QPointF & point1, const QPointF & point2) { return (point1.x() - point2.x()) * (point1.x() - point2.x()) + (point1.y() - point2.y()) * (point1.y() - point2.y()); }