#include "graphicsItem/graphicsTextItem.h" #include "graphicsItem/itemControlHandle.h" #include "graphicsItem/graphicsItemGroup.h" #include #include #include #include #include #include GraphicsTextItem::GraphicsTextItem(QGraphicsItem *parent) : AbstractShapeType(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 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::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(parentItem()); if (!group) setHandleVisible(value.toBool()); else { setSelected(false); return QVariant::fromValue(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;