📄 qtextdocumentlayout.cpp
字号:
*position = cell.firstPosition(); HitPoint hp = hitTest(cell.begin(), PointInside, point - td->cellPosition(cell), position, l, accuracy); if (hp == PointExact) return hp; if (hp == PointAfter) *position = cell.lastPosition(); return PointInside;}QTextDocumentLayoutPrivate::HitPointQTextDocumentLayoutPrivate::hitTest(QTextBlock bl, const QFixedPoint &point, int *position, QTextLayout **l, Qt::HitTestAccuracy accuracy) const{ QTextLayout *tl = bl.layout(); QRectF textrect = tl->boundingRect(); textrect.translate(tl->position());// LDEBUG << " checking block" << bl.position() << "point=" << point// << " tlrect" << textrect; *position = bl.position(); if (point.y.toReal() < textrect.top()) {// LDEBUG << " before pos=" << *position; return PointBefore; } else if (point.y.toReal() > textrect.bottom()) { *position += bl.length();// LDEBUG << " after pos=" << *position; return PointAfter; } QPointF pos = point.toPointF() - tl->position(); // ### rtl? HitPoint hit = PointInside; *l = tl; int off = 0; for (int i = 0; i < tl->lineCount(); ++i) { QTextLine line = tl->lineAt(i); const QRectF lr = line.naturalTextRect(); if (lr.top() > pos.y()) { off = qMin(off, line.textStart()); } else if (lr.bottom() <= pos.y()) { off = qMax(off, line.textStart() + line.textLength()); } else { if (lr.left() <= pos.x() && lr.right() >= pos.x()) hit = PointExact; // when trying to hit an anchor we want it to hit not only in the left // half if (accuracy == Qt::ExactHit) off = line.xToCursor(pos.x(), QTextLine::CursorOnCharacter); else off = line.xToCursor(pos.x(), QTextLine::CursorBetweenCharacters); break; } } *position += off;// LDEBUG << " inside=" << hit << " pos=" << *position; return hit;}// ### could be moved to QTextBlockqreal QTextDocumentLayoutPrivate::indent(QTextBlock bl) const{ Q_Q(const QTextDocumentLayout); QTextBlockFormat blockFormat = bl.blockFormat(); qreal indent = blockFormat.indent(); QTextObject *object = q->document()->objectForFormat(blockFormat); if (object) indent += object->format().toListFormat().indent(); qreal scale = 1; if (q->paintDevice()) { extern int qt_defaultDpi(); scale = qreal(q->paintDevice()->logicalDpiY()) / qreal(qt_defaultDpi()); } return indent * TextIndentValue * scale;}void QTextDocumentLayoutPrivate::drawBorder(QPainter *painter, const QRectF &rect, qreal topMargin, qreal bottomMargin, qreal border, const QBrush &brush, QTextFrameFormat::BorderStyle style) const{ Q_Q(const QTextDocumentLayout); const qreal pageHeight = q->document()->pageSize().height(); const int topPage = pageHeight > 0 ? static_cast<int>(rect.top() / pageHeight) : 0; const int bottomPage = pageHeight > 0 ? static_cast<int>((rect.bottom() + border) / pageHeight) : 0; QCss::BorderStyle cssStyle = static_cast<QCss::BorderStyle>(style + 1); for (int i = topPage; i <= bottomPage; ++i) { QRectF clipped = rect; if (topPage != bottomPage) { clipped.setTop(qMax(clipped.top(), i * pageHeight + topMargin - border)); clipped.setBottom(qMin(clipped.bottom(), (i + 1) * pageHeight - bottomMargin)); if (clipped.bottom() <= clipped.top()) continue; } qDrawEdge(painter, clipped.left(), clipped.top(), clipped.left() + border, clipped.bottom() + border, 0, 0, QCss::LeftEdge, cssStyle, brush); qDrawEdge(painter, clipped.left() + border, clipped.top(), clipped.right() + border, clipped.top() + border, 0, 0, QCss::TopEdge, cssStyle, brush); qDrawEdge(painter, clipped.right(), clipped.top() + border, clipped.right() + border, clipped.bottom(), 0, 0, QCss::RightEdge, cssStyle, brush); qDrawEdge(painter, clipped.left() + border, clipped.bottom(), clipped.right() + border, clipped.bottom() + border, 0, 0, QCss::BottomEdge, cssStyle, brush); }}void QTextDocumentLayoutPrivate::drawFrameDecoration(QPainter *painter, QTextFrame *frame, QTextFrameData *fd, const QRectF &clip, const QRectF &rect) const{ if (fd->border != 0) { painter->save(); painter->setBrush(Qt::lightGray); painter->setPen(Qt::NoPen); const qreal leftEdge = rect.left() + fd->leftMargin.toReal(); const qreal border = fd->border.toReal(); const qreal topMargin = fd->topMargin.toReal(); const qreal leftMargin = fd->leftMargin.toReal(); const qreal bottomMargin = fd->bottomMargin.toReal(); const qreal rightMargin = fd->rightMargin.toReal(); const qreal w = rect.width() - 2 * border - leftMargin - rightMargin; const qreal h = rect.height() - 2 * border - topMargin - bottomMargin; drawBorder(painter, QRectF(leftEdge, rect.top() + topMargin, w + border, h + border), fd->effectiveTopMargin.toReal(), fd->effectiveBottomMargin.toReal(), border, frame->frameFormat().borderBrush(), frame->frameFormat().borderStyle()); painter->restore(); } const QBrush bg = frame->frameFormat().background(); if (bg != Qt::NoBrush) { QRectF bgRect = rect; bgRect.adjust((fd->leftMargin + fd->border).toReal(), (fd->topMargin + fd->border).toReal(), - (fd->rightMargin + fd->border).toReal(), - (fd->bottomMargin + fd->border).toReal()); QRectF gradientRect; // invalid makes it default to bgRect if (!frame->parentFrame()) { bgRect = clip; gradientRect.setWidth(painter->device()->width()); gradientRect.setHeight(painter->device()->height()); } fillBackground(painter, bgRect, bg, gradientRect); }}static void adjustContextSelectionsForCell(QAbstractTextDocumentLayout::PaintContext &cell_context, const QTextTableCell &cell, int r, int c, const int *selectedTableCells){ for (int i = 0; i < cell_context.selections.size(); ++i) { int row_start = selectedTableCells[i * 4]; int col_start = selectedTableCells[i * 4 + 1]; int num_rows = selectedTableCells[i * 4 + 2]; int num_cols = selectedTableCells[i * 4 + 3]; if (row_start != -1) { if (r >= row_start && r < row_start + num_rows && c >= col_start && c < col_start + num_cols) { int firstPosition = cell.firstPosition(); int lastPosition = cell.lastPosition(); // make sure empty cells are still selected if (firstPosition == lastPosition) ++lastPosition; cell_context.selections[i].cursor.setPosition(firstPosition); cell_context.selections[i].cursor.setPosition(lastPosition, QTextCursor::KeepAnchor); } else { cell_context.selections[i].cursor.clearSelection(); } } }}void QTextDocumentLayoutPrivate::drawFrame(const QPointF &offset, QPainter *painter, const QAbstractTextDocumentLayout::PaintContext &context, QTextFrame *frame) const{ Q_Q(const QTextDocumentLayout); QTextFrameData *fd = data(frame); // ####### if (fd->layoutDirty) return; Q_ASSERT(!fd->sizeDirty); Q_ASSERT(!fd->layoutDirty); const QPointF off = offset + fd->position.toPointF(); if (context.clip.isValid() && (off.y() > context.clip.bottom() || off.y() + fd->size.height.toReal() < context.clip.top() || off.x() > context.clip.right() || off.x() + fd->size.width.toReal() < context.clip.left())) return;// LDEBUG << debug_indent << "drawFrame" << frame->firstPosition() << "--" << frame->lastPosition() << "at" << offset;// INC_INDENT; // if the cursor is /on/ a table border we may need to repaint it // afterwards, as we usually draw the decoration first QTextBlock cursorBlockNeedingRepaint; QPointF offsetOfRepaintedCursorBlock = off; QTextTable *table = qobject_cast<QTextTable *>(frame); const QRectF frameRect(off, fd->size.toSizeF()); if (table) { const int rows = table->rows(); const int columns = table->columns(); QTextTableData *td = static_cast<QTextTableData *>(data(table)); QVarLengthArray<int> selectedTableCells(context.selections.size() * 4); for (int i = 0; i < context.selections.size(); ++i) { const QAbstractTextDocumentLayout::Selection &s = context.selections.at(i); int row_start = -1, col_start = -1, num_rows = -1, num_cols = -1; if (s.cursor.currentTable() == table) s.cursor.selectedTableCells(&row_start, &num_rows, &col_start, &num_cols); selectedTableCells[i * 4] = row_start; selectedTableCells[i * 4 + 1] = col_start; selectedTableCells[i * 4 + 2] = num_rows; selectedTableCells[i * 4 + 3] = num_cols; } QFixed pageHeight = QFixed::fromReal(q->document()->pageSize().height()); if (pageHeight <= 0) pageHeight = QFIXED_MAX; const int tableStartPage = (td->position.y / pageHeight).truncate(); const int tableEndPage = ((td->position.y + td->size.height) / pageHeight).truncate(); qreal border = td->border.toReal(); drawFrameDecoration(painter, frame, fd, context.clip, frameRect); // draw the table headers const int headerRowCount = qMin(table->format().headerRowCount(), rows - 1); int page = tableStartPage + 1; while (page <= tableEndPage) { const QFixed pageTop = page * pageHeight + td->effectiveTopMargin + td->cellSpacing + td->border; const qreal headerOffset = (pageTop - td->rowPositions.at(0)).toReal(); for (int r = 0; r < headerRowCount; ++r) { for (int c = 0; c < columns; ++c) { QTextTableCell cell = table->cellAt(r, c); QAbstractTextDocumentLayout::PaintContext cell_context = context; adjustContextSelectionsForCell(cell_context, cell, r, c, selectedTableCells.data()); QRectF cellRect = td->cellRect(cell); cellRect.translate(off.x(), headerOffset); // we need to account for the cell border in the clipping test if (cell_context.clip.isValid() && !cellRect.adjusted(1 - border, 1 - border, border, border).intersects(cell_context.clip)) continue; drawTableCell(cellRect, painter, cell_context, table, td, r, c, &cursorBlockNeedingRepaint, &offsetOfRepaintedCursorBlock); } } ++page; } int firstRow = 0; int lastRow = rows; if (context.clip.isValid()) { QVector<QFixed>::ConstIterator rowIt = qLowerBound(td->rowPositions.constBegin(), td->rowPositions.constEnd(), QFixed::fromReal(context.clip.top() - off.y())); if (rowIt != td->rowPositions.constEnd() && rowIt != td->rowPositions.constBegin()) { --rowIt; firstRow = rowIt - td->rowPositions.constBegin(); } rowIt = qUpperBound(td->rowPositions.constBegin(), td->rowPositions.constEnd(), QFixed::fromReal(context.clip.bottom() - off.y())); if (rowIt != td->rowPositions.constEnd()) { ++rowIt; lastRow = rowIt - td->rowPositions.constBegin(); } } for (int c = 0; c < columns; ++c) { QTextTableCell cell = table->cellAt(firstRow, c); firstRow = qMin(firstRow, cell.row()); } for (int r = firstRow; r < lastRow; ++r) { for (int c = 0; c < columns; ++c) { QTextTableCell cell = table->cellAt(r, c); QAbstractTextDocumentLayout::PaintContext cell_context = context; adjustContextSelectionsForCell(cell_context, cell, r, c, selectedTableCells.data()); QRectF cellRect = td->cellRect(cell); cellRect.translate(off); // we need to account for the cell border in the clipping test if (cell_context.clip.isValid() && !cellRect.adjusted(1 - border, 1 - border, border, border).intersects(cell_context.clip)) continue; drawTableCell(cellRect, painter, cell_context, table, td, r, c, &cursorBlockNeedingRepaint, &offsetOfRepaintedCursorBlock); } } } else { drawFrameDecoration(painter, frame, fd, context.clip, frameRect); QTextFrame::Iterator it = frame->begin(); if (frame == q->document()->rootFrame()) it = frameIteratorForYPosition(QFixed::fromReal(context.clip.top())); QList<QTextFrame *> floats; for (int i = 0; i < fd->floats.count(); ++i) floats.append(fd->floats.at(i)); drawFlow(off, painter, context, it, floats, &cursorBlockNeedingRepaint); } if (cursorBlockNeedingRepaint.isValid()) { const QPen oldPen = painter->pen(); painter->setPen(context.palette.color(QPalette::Text)); const int cursorPos = context.cursorPosition - cursorBlockNeedingRepaint.position(); cursorBlockNeedingRepaint.layout()->drawCursor(painter, offsetOfRepaintedCursorBlock, cursorPos, cursorWidth); painter->setPen(oldPen); }// DEC_INDENT; return;}void QTextDocumentLayoutPrivate::drawTableCell(const QRectF &cellRect, QPainter *painter, const QAbstractTextDocumentLayout::PaintContext &cell_context, QTextTable *table, QTextTableData *td, int r, int c, QTextBlock *cursorBlockNeedingRepaint, QPointF *cursorBlockOffset) const{ QTextTableCell cell = table->cellAt(r, c);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -