320 lines
8.9 KiB
C++
320 lines
8.9 KiB
C++
#include "graphicsItem/graphicsTextItem.h"
|
|
#include "graphicsItem/itemControlHandle.h"
|
|
#include "graphicsItem/graphicsItemGroup.h"
|
|
|
|
#include <QPainter>
|
|
#include <QStyleOptionGraphicsItem>
|
|
#include <QFont>
|
|
#include <QGraphicsScene>
|
|
#include <QFocusEvent>
|
|
#include <QTextDocument>
|
|
|
|
GraphicsTextItem::GraphicsTextItem(QGraphicsItem *parent)
|
|
: AbstractShapeType<QGraphicsTextItem>(parent)
|
|
{
|
|
m_type = T_item;
|
|
m_pen = QPen(Qt::NoPen);
|
|
m_brush = QBrush(Qt::NoBrush);
|
|
|
|
// 8 resize handles
|
|
m_vecHanle.reserve(H_left);
|
|
for (int i = H_leftTop; i <= H_left; i++) {
|
|
auto *h = new ItemControlHandle(this);
|
|
h->setType(T_resize);
|
|
h->setTag(i);
|
|
m_vecHanle.push_back(h);
|
|
}
|
|
// 4 rotate handles
|
|
for (int i = H_rotate_leftTop; i <= H_rotate_leftBottom; i++) {
|
|
auto *h = new ItemControlHandle(this);
|
|
h->setType(T_rotate);
|
|
h->setTag(i);
|
|
m_vecHanle.push_back(h);
|
|
}
|
|
|
|
setFlag(QGraphicsItem::ItemIsMovable, false); // we handle move via selector
|
|
setFlag(QGraphicsItem::ItemIsSelectable, true);
|
|
setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
|
|
setAcceptHoverEvents(true);
|
|
|
|
QFont defaultFont;
|
|
defaultFont.setPointSize(14);
|
|
setFont(defaultFont);
|
|
setDefaultTextColor(Qt::black);
|
|
setPlainText("Text");
|
|
|
|
updateSizeFromText();
|
|
m_boundingRect = QRectF(0, 0, m_dWidth, m_dHeight);
|
|
setTransformOriginPoint(m_boundingRect.center());
|
|
m_lastBoundingRect = m_boundingRect;
|
|
|
|
// Keep bounding rect in sync with text content during editing
|
|
connect(document(), &QTextDocument::contentsChanged, this, [this]() {
|
|
prepareGeometryChange();
|
|
updateSizeFromText();
|
|
m_boundingRect = QRectF(0, 0, m_dWidth, m_dHeight);
|
|
setTransformOriginPoint(m_boundingRect.center());
|
|
updateHandles();
|
|
m_lastBoundingRect = m_boundingRect;
|
|
});
|
|
}
|
|
|
|
GraphicsTextItem::~GraphicsTextItem() {}
|
|
|
|
QString GraphicsTextItem::getPropertyGroup(const QString &propertyName) const
|
|
{
|
|
QList<QString> properties = {
|
|
QStringLiteral("text"),
|
|
QStringLiteral("itemFont"),
|
|
QStringLiteral("textColor"),
|
|
QStringLiteral("backgroundColor")
|
|
};
|
|
|
|
if (!properties.contains(propertyName))
|
|
return {};
|
|
else
|
|
return QStringLiteral("基本信息");
|
|
}
|
|
|
|
QPainterPath GraphicsTextItem::shape()
|
|
{
|
|
QPainterPath path;
|
|
path.addRect(m_boundingRect);
|
|
return path;
|
|
}
|
|
|
|
void GraphicsTextItem::updateSizeFromText()
|
|
{
|
|
QSizeF textSize = document()->size();
|
|
double w = qMax(textSize.width(), 40.0);
|
|
double h = qMax(textSize.height(), 20.0);
|
|
m_dWidth = w;
|
|
m_dHeight = h;
|
|
}
|
|
|
|
void GraphicsTextItem::updateCoordinate()
|
|
{
|
|
if (!parentItem()) {
|
|
updateSizeFromText();
|
|
prepareGeometryChange();
|
|
m_boundingRect = QRectF(0, 0, m_dWidth, m_dHeight);
|
|
setTransformOriginPoint(m_boundingRect.center());
|
|
updateHandles();
|
|
}
|
|
m_lastBoundingRect = m_boundingRect;
|
|
m_dLastPointSize = font().pointSize();
|
|
}
|
|
|
|
void GraphicsTextItem::updateHandles()
|
|
{
|
|
AbstractShapeType<QGraphicsTextItem>::updateHandles();
|
|
}
|
|
|
|
void GraphicsTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
|
{
|
|
// Background fill
|
|
if (m_brush.style() != Qt::NoBrush) {
|
|
painter->setPen(Qt::NoPen);
|
|
painter->setBrush(m_brush);
|
|
painter->drawRect(m_boundingRect);
|
|
}
|
|
|
|
// Text rendering via QGraphicsTextItem
|
|
QGraphicsTextItem::paint(painter, option, widget);
|
|
|
|
// Selection indicator
|
|
if (option->state & QStyle::State_Selected) {
|
|
int nPenWidth = 1;
|
|
painter->setPen(QPen(QColor(70, 70, 70), nPenWidth, Qt::DashLine));
|
|
painter->setBrush(Qt::NoBrush);
|
|
painter->drawRect(m_boundingRect_selected);
|
|
|
|
painter->setBrush(Qt::red);
|
|
painter->drawEllipse(transformOriginPoint(), 4, 4);
|
|
}
|
|
}
|
|
|
|
void GraphicsTextItem::resize(int nHandle, double dSX, double dSY, const QPointF &basePoint)
|
|
{
|
|
switch (nHandle) {
|
|
case H_left:
|
|
case H_right:
|
|
dSY = 1;
|
|
break;
|
|
case H_top:
|
|
case H_bottom:
|
|
dSX = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
QTransform trans;
|
|
trans.translate(basePoint.x(), basePoint.y());
|
|
trans.scale(dSX, dSY);
|
|
trans.translate(-basePoint.x(), -basePoint.y());
|
|
|
|
prepareGeometryChange();
|
|
m_boundingRect = trans.mapRect(m_lastBoundingRect);
|
|
m_dWidth = m_boundingRect.width();
|
|
m_dHeight = m_boundingRect.height();
|
|
|
|
// Scale font size proportionally from pre-drag value
|
|
double avgScale = (qAbs(dSX) + qAbs(dSY)) / 2.0;
|
|
QFont f = font();
|
|
int newSize = qMax(1, qRound(m_dLastPointSize * avgScale));
|
|
f.setPointSize(newSize);
|
|
setFont(f);
|
|
|
|
setTransformOriginPoint(m_boundingRect.center());
|
|
updateHandles();
|
|
}
|
|
|
|
void GraphicsTextItem::move(const QPointF &pt)
|
|
{
|
|
moveBy(pt.x(), pt.y());
|
|
}
|
|
|
|
QVariant GraphicsTextItem::itemChange(GraphicsItemChange change, const QVariant &value)
|
|
{
|
|
if (change == QGraphicsItem::ItemSelectedHasChanged) {
|
|
QGraphicsItemGroup *group = dynamic_cast<QGraphicsItemGroup *>(parentItem());
|
|
if (!group)
|
|
setHandleVisible(value.toBool());
|
|
else {
|
|
setSelected(false);
|
|
return QVariant::fromValue<bool>(false);
|
|
}
|
|
}
|
|
return QGraphicsTextItem::itemChange(change, value);
|
|
}
|
|
|
|
void GraphicsTextItem::startEditing()
|
|
{
|
|
m_bEditing = true;
|
|
setHandleVisible(false);
|
|
setTextInteractionFlags(Qt::TextEditorInteraction);
|
|
setFocus();
|
|
}
|
|
|
|
void GraphicsTextItem::endEditing()
|
|
{
|
|
m_bEditing = false;
|
|
setTextInteractionFlags(Qt::NoTextInteraction);
|
|
updateCoordinate();
|
|
if (isSelected())
|
|
setHandleVisible(true);
|
|
}
|
|
|
|
void GraphicsTextItem::focusOutEvent(QFocusEvent *event)
|
|
{
|
|
QGraphicsTextItem::focusOutEvent(event);
|
|
endEditing();
|
|
}
|
|
|
|
void GraphicsTextItem::focusInEvent(QFocusEvent *event)
|
|
{
|
|
QGraphicsTextItem::focusInEvent(event);
|
|
setHandleVisible(false);
|
|
}
|
|
|
|
void GraphicsTextItem::createOperationCopy()
|
|
{
|
|
m_pOperationCopy = new QGraphicsPathItem(shape());
|
|
m_pOperationCopy->setPen(Qt::DashLine);
|
|
m_pOperationCopy->setPos(pos());
|
|
m_pOperationCopy->setTransformOriginPoint(transformOriginPoint());
|
|
m_pOperationCopy->setTransform(transform());
|
|
m_pOperationCopy->setRotation(rotation());
|
|
m_pOperationCopy->setScale(scale());
|
|
m_pOperationCopy->setZValue(zValue());
|
|
|
|
QGraphicsScene *s = scene();
|
|
if (s && m_pOperationCopy) {
|
|
s->addItem(m_pOperationCopy);
|
|
m_movingIniPos = pos();
|
|
}
|
|
}
|
|
|
|
void GraphicsTextItem::removeOperationCopy()
|
|
{
|
|
QGraphicsScene *s = scene();
|
|
if (s && m_pOperationCopy) {
|
|
if (pos() != m_pOperationCopy->pos())
|
|
setPos(m_pOperationCopy->pos());
|
|
if (rotation() != m_pOperationCopy->rotation())
|
|
setRotation(m_pOperationCopy->rotation());
|
|
s->removeItem(m_pOperationCopy);
|
|
delete m_pOperationCopy;
|
|
m_pOperationCopy = nullptr;
|
|
}
|
|
}
|
|
|
|
void GraphicsTextItem::moveOperationCopy(const QPointF &distance)
|
|
{
|
|
if (m_pOperationCopy)
|
|
m_pOperationCopy->setPos(m_movingIniPos + distance);
|
|
}
|
|
|
|
void GraphicsTextItem::rotateOperationCopy(const double &dAngle)
|
|
{
|
|
if (m_pOperationCopy)
|
|
m_pOperationCopy->setRotation(dAngle);
|
|
}
|
|
|
|
void GraphicsTextItem::syncRotationDataFromParent(const double &data)
|
|
{
|
|
m_dSyncRotationByParent += data;
|
|
if (m_dSyncRotationByParent > 180)
|
|
m_dSyncRotationByParent -= 360;
|
|
if (m_dSyncRotationByParent < -180)
|
|
m_dSyncRotationByParent += 360;
|
|
}
|
|
|
|
#include "util/serializationUtils.h"
|
|
|
|
QJsonObject GraphicsTextItem::serialize() const
|
|
{
|
|
QJsonObject obj = serializeCommon(this, "text");
|
|
obj["text"] = toPlainText();
|
|
QJsonObject fontObj;
|
|
fontObj["family"] = font().family();
|
|
fontObj["bold"] = font().bold();
|
|
fontObj["italic"] = font().italic();
|
|
fontObj["underline"] = font().underline();
|
|
fontObj["pointSize"] = font().pointSize();
|
|
obj["font"] = fontObj;
|
|
obj["textColor"] = defaultTextColor().name(QColor::HexArgb);
|
|
obj["backgroundColor"] = m_brush.color().name(QColor::HexArgb);
|
|
return obj;
|
|
}
|
|
|
|
#include "util/serializationRegistry.h"
|
|
|
|
QGraphicsItem *GraphicsTextItem::createFromJson(const QJsonObject &obj)
|
|
{
|
|
auto *item = new GraphicsTextItem();
|
|
item->setPlainText(obj["text"].toString());
|
|
QJsonObject f = obj["font"].toObject();
|
|
QFont font(f["family"].toString(), f["pointSize"].toInt(14));
|
|
font.setBold(f["bold"].toBool());
|
|
font.setItalic(f["italic"].toBool());
|
|
font.setUnderline(f["underline"].toBool());
|
|
item->setFont(font);
|
|
item->setDefaultTextColor(QColor(obj["textColor"].toString()));
|
|
QColor bgColor(obj["backgroundColor"].toString());
|
|
if (bgColor.isValid())
|
|
item->setBrushColor(bgColor);
|
|
applyCommon(item, obj);
|
|
item->updateSizeFromText();
|
|
item->updateCoordinate();
|
|
item->setHandleVisible(false);
|
|
return item;
|
|
}
|
|
|
|
static struct TextItemRegistrar {
|
|
TextItemRegistrar() {
|
|
registerItemFactory("text", &GraphicsTextItem::createFromJson);
|
|
}
|
|
} _textItemRegistrar;
|