#include "graphicsscene.h" #include #include #include #include #include #include #include #include #include #include #include #include GraphicsTextEdit::GraphicsTextEdit(QWidget* parent) : QTextEdit(parent) { viewport()->setWindowFlags(windowFlags() | Qt::FramelessWindowHint); viewport()->setAttribute(Qt::WA_TranslucentBackground); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); connect(this, SIGNAL(textChanged()), this, SLOT(on_textChanged())); } GraphicsTextEdit::~GraphicsTextEdit() { } #define BORDER_WIDTH 20 void GraphicsTextEdit::on_textChanged() { QFontMetrics fm(font()); QSize currentSize = this->size(); QStringList lineText = document()->toPlainText().split("\n", QString::SkipEmptyParts); int idealWidth = 0; for (const QString& str : lineText) { int width = fm.width(str); if (width > idealWidth) idealWidth = width; } int idelHeight = document()->lineCount() * fm.lineSpacing(); if (width() < idealWidth + BORDER_WIDTH) currentSize.setWidth(idealWidth + BORDER_WIDTH); if (height() < idelHeight + BORDER_WIDTH * 2) currentSize.setHeight(idelHeight + BORDER_WIDTH * 2); if (currentSize != this->size()) resize(currentSize); } GraphicsScene::GraphicsScene(QObject* parent) : QGraphicsScene(parent) , m_status(Normal) , m_activeItem(nullptr) , m_btn_pressed(0) , m_pen(QColor(255, 0, 0, 255)) , m_brush(QColor(255, 255, 255, 255)) , m_font(tr("SongTi")) { } GraphicsScene::~GraphicsScene() { } void GraphicsScene::setColor(const QColor& color) { m_pen.setColor(color); m_brush.setColor(color); } void GraphicsScene::setTextSize(int size) { m_font.setPointSize(size); } void GraphicsScene::setLineWidth(int width) { m_pen.setWidth(width); } void GraphicsScene::createShape(int flag) { if (m_activeItem != nullptr) { if (typeid(*m_activeItem) == typeid(QGraphicsProxyWidget)) removeItem(m_activeItem); m_activeItem = nullptr; m_status = Normal; } switch (flag) { case Rect: m_status = CreateRect; break; case Ellipse: m_status = CreateEllipse; break; case Line: m_status = CreateLine; break; case Text: m_status = CreateText; break; case Arrow: m_status = CreateArrow; break; case Pen: m_status = CreatePen; break; default: break; } } void GraphicsScene::unDo() { QList items = this->items(); if (items.count() < 2) return; removeItem(items.first()); } #define PI acos(-1) QPointF rotate(const QPointF& center, const QPointF& p, float angle) { float angle_ = angle; float x = (p.x() - center.x()) * cos(angle_) - (p.y() - center.y()) * sin(angle_) + center.x(); float y = (p.y() - center.y()) * cos(angle_) + (p.x() - center.x()) * sin(angle_) + center.y(); return QPointF(x, y); } float lineLength(const QPointF& p1, const QPointF& p2) { return sqrt(pow(p1.x() - p2.x(), 2) + pow(p1.y() - p2.y(), 2)); } QPainterPath GraphicsScene::createArrowPath(const QPointF& p1, const QPointF& p2) { float angle; if (p2.x() == p1.x()) if (p2.y() > p1.y()) angle = PI / 2; else angle = -PI / 2; else if (p2.x() < p1.x() && std::abs(p1.y() - p2.y()) < 0.000001) angle = PI; else { angle = atan((p2.y() - p1.y()) / (p2.x() - p1.x())); if (p2.y() < p1.y() && p2.x() < p1.x()) angle -= PI; if (p2.y() > p1.y() && p2.x() < p1.x()) angle += PI; } float length = lineLength(p1, p2); QPointF p_1 = rotate(p1, QPointF(p1.x() + length - 25, p1.y() + 15), angle); QPointF p_2 = rotate(p1, QPointF(p1.x() + length - 25, p1.y() - 15), angle); QPointF p_1_half = rotate(p1, QPointF(p1.x() + length - 22, p1.y() + 10), angle); QPointF p_2_half = rotate(p1, QPointF(p1.x() + length - 22, p1.y() - 10), angle); QPainterPath path; path.moveTo(p2); path.lineTo(p_2); path.lineTo(p_2_half); path.lineTo(p1); path.lineTo(p_1_half); path.lineTo(p_1); path.lineTo(p2); return path; } void GraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) { if (m_activeItem == nullptr) return; if (m_status == CreateRect) { QGraphicsRectItem* item = reinterpret_cast(m_activeItem); QPointF pos = mouseEvent->scenePos(); float left = qMin(pos.x(), m_startPoint.x()); float top = qMin(pos.y(), m_startPoint.y()); float right = qMax(pos.x(), m_startPoint.x()); float bottom = qMax(pos.y(), m_startPoint.y()); item->setRect(QRectF(QPointF(left, top), QPointF(right, bottom))); } else if (m_status == CreateEllipse) { QGraphicsEllipseItem* item = reinterpret_cast(m_activeItem); QPointF pos = mouseEvent->scenePos(); float left = qMin(pos.x(), m_startPoint.x()); float top = qMin(pos.y(), m_startPoint.y()); float right = qMax(pos.x(), m_startPoint.x()); float bottom = qMax(pos.y(), m_startPoint.y()); item->setRect(QRectF(QPointF(left, top), QPointF(right, bottom))); } else if (m_status == CreateLine) { QGraphicsLineItem* item = reinterpret_cast(m_activeItem); item->setLine(QLineF(m_startPoint, mouseEvent->scenePos())); } else if (m_status == CreateArrow) { QGraphicsPathItem* item = reinterpret_cast(m_activeItem); item->setPath(createArrowPath(m_startPoint, mouseEvent->scenePos())); } else if (m_status == CreatePen) { QGraphicsPathItem* item = reinterpret_cast(m_activeItem); QPainterPath path = item->path(); path.lineTo(mouseEvent->scenePos()); item->setPath(path); } } void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) { if (mouseEvent->button() == Qt::MouseButton::LeftButton) m_btn_pressed = 1; else if (mouseEvent->button() == Qt::MouseButton::RightButton) m_btn_pressed = 2; if (m_status == CreateRect) { m_activeItem = addRect(QRectF(mouseEvent->scenePos(), QSize(1, 1)), QPen(m_brush.color()), m_brush); m_startPoint = mouseEvent->scenePos(); } else if (m_status == CreateEllipse) { m_activeItem = addEllipse(QRectF(mouseEvent->scenePos(), QSize(1, 1)), m_pen, QBrush()); m_startPoint = mouseEvent->scenePos(); } else if (m_status == CreateLine) { m_activeItem = addLine(QLineF(mouseEvent->scenePos(), mouseEvent->scenePos()), m_pen); m_startPoint = mouseEvent->scenePos(); } else if (m_status == CreateArrow) { m_startPoint = mouseEvent->scenePos(); m_activeItem = addPath(createArrowPath(m_startPoint, mouseEvent->scenePos()), m_pen, QBrush(m_pen.color())); } else if (m_status == CreatePen) { m_startPoint = mouseEvent->scenePos(); QPainterPath path(m_startPoint); path.lineTo(m_startPoint + QPointF(1, 1)); m_activeItem = addPath(path, m_pen, QBrush()); } } void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) { m_btn_pressed = 0; if (m_activeItem != nullptr) { if (typeid(*m_activeItem) == typeid(QGraphicsProxyWidget)) { QRectF r(m_edit->mapToParent(QPoint()), m_edit->size()); if (!r.contains(mouseEvent->scenePos())) { QString text = m_edit->document()->toPlainText(); QFont font = m_edit->font(); removeItem(m_activeItem); QGraphicsTextItem* item = addText(text, font); item->setPos(m_edit->mapToParent(QPoint())); item->setDefaultTextColor(m_pen.color()); } } m_activeItem = nullptr; } if (m_status == CreateText) { if (m_activeItem != nullptr) if (typeid(*m_activeItem) == typeid(QGraphicsProxyWidget)) return; m_edit = new GraphicsTextEdit(); m_edit->setTextColor(m_pen.color()); m_edit->setFont(m_font); m_edit->setContextMenuPolicy(Qt::ContextMenuPolicy::NoContextMenu); m_activeItem = addWidget(m_edit, Qt::Widget); m_activeItem->setPos(mouseEvent->scenePos()); m_edit->setFocus(); } }