299 lines
8.6 KiB
C++
299 lines
8.6 KiB
C++
#include "graphicsscene.h"
|
|
#include <QGraphicsSceneMouseEvent>
|
|
#include <QGraphicsRectItem>
|
|
#include <QGraphicsEllipseItem>
|
|
#include <QGraphicsProxyWidget>
|
|
#include <QScrollBar>
|
|
#include <QPen>
|
|
#include <QBrush>
|
|
#include <QGraphicsView>
|
|
#include <QDebug>
|
|
#include <qmath.h>
|
|
|
|
GraphicsTextEdit::GraphicsTextEdit(QWidget* parent)
|
|
: QTextEdit(parent)
|
|
{
|
|
viewport()->setWindowFlag(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<QGraphicsItem*> 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<QGraphicsRectItem*>(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<QGraphicsEllipseItem*>(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<QGraphicsLineItem*>(m_activeItem);
|
|
item->setLine(QLineF(m_startPoint, mouseEvent->scenePos()));
|
|
}
|
|
else if (m_status == CreateArrow)
|
|
{
|
|
QGraphicsPathItem* item = reinterpret_cast<QGraphicsPathItem*>(m_activeItem);
|
|
item->setPath(createArrowPath(m_startPoint, mouseEvent->scenePos()));
|
|
}
|
|
else if (m_status == CreatePen)
|
|
{
|
|
QGraphicsPathItem* item = reinterpret_cast<QGraphicsPathItem*>(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();
|
|
}
|
|
}
|