#include "graphicsscene.h" #include #include #include #include #include #include #include #include #include #include GraphicsTextEdit::GraphicsTextEdit(QWidget* parent) : QTextEdit(parent) { viewport()->setWindowFlags(Qt::FramelessWindowHint); //viewport()->setAttribute(Qt::WA_TranslucentBackground); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setContextMenuPolicy(Qt::ContextMenuPolicy::NoContextMenu); connect(this, SIGNAL(textChanged()), this, SLOT(on_textChanged())); setStyleSheet("QTextEdit{background-color: transparent; border: 3px solid red;}"); //setWindowOpacity(0.3); //setMouseTracking(true); } GraphicsTextEdit::~GraphicsTextEdit() { } void GraphicsTextEdit::setDefeaultColor(const QColor& color) { m_defeaultColor = color; setTextColor(m_defeaultColor); } #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); if (toPlainText().isEmpty()) setTextColor(m_defeaultColor); } 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")) , m_edit(nullptr) { } GraphicsScene::~GraphicsScene() { } void GraphicsScene::setColor(const QColor& color) { m_pen.setColor(color); m_brush.setColor(color); if (m_edit != nullptr) m_edit->setDefeaultColor(color); } void GraphicsScene::setTextSize(int size) { m_font.setPointSize(size); } void GraphicsScene::setLineWidth(int width) { m_pen.setWidth(width); } void GraphicsScene::setItemFlag(int flag) { if (m_status == CreateText) { if (m_activeItem != nullptr) { 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()); delete m_edit; m_edit = nullptr; m_activeItem = nullptr; } } 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: m_status = Normal; break; } } void GraphicsScene::unDo() { m_activeItem = nullptr; 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 (!sceneRect().contains(mouseEvent->scenePos())) 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) { if (mouseEvent->button() == Qt::MouseButton::RightButton) { QGraphicsScene::mouseReleaseEvent(mouseEvent); return; } m_btn_pressed = 0; if (m_activeItem != nullptr) if (typeid(*m_activeItem) != typeid(QGraphicsProxyWidget)) m_activeItem = nullptr; if (m_status == CreateText) { if (m_activeItem != nullptr) { QRectF r(m_edit->mapToParent(QPoint()), m_edit->size()); if (r.contains(mouseEvent->scenePos())) { QGraphicsScene::mouseReleaseEvent(mouseEvent); return; } 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()); delete m_edit; m_edit = nullptr; m_activeItem = nullptr; } else { m_edit = new GraphicsTextEdit(); m_edit->setDefeaultColor(m_pen.color()); m_edit->setFont(m_font); QGraphicsProxyWidget* widget = addWidget(m_edit, Qt::FramelessWindowHint); widget->setPos(mouseEvent->scenePos()); m_activeItem = widget; m_edit->setFocus(); } } }