void TextLabel::drawTextLayout(QPainter *painter, const QTextLayout &layout, const QRect &rect) { if (rect.width() < 1 || rect.height() < 1) { return; } QPixmap pixmap(rect.size()); pixmap.fill(Qt::transparent); QPainter p(&pixmap); p.setPen(painter->pen()); // Create the alpha gradient for the fade out effect QLinearGradient alphaGradient(0, 0, 1, 0); alphaGradient.setCoordinateMode(QGradient::ObjectBoundingMode); if (layout.textOption().textDirection() == Qt::LeftToRight) { alphaGradient.setColorAt(0, QColor(0, 0, 0, 255)); alphaGradient.setColorAt(1, QColor(0, 0, 0, 0)); } else { alphaGradient.setColorAt(0, QColor(0, 0, 0, 0)); alphaGradient.setColorAt(1, QColor(0, 0, 0, 255)); } QFontMetrics fm(layout.font()); int textHeight = layout.lineCount() * fm.lineSpacing(); QPointF position(0, (rect.height() - textHeight) / 2); QList<QRect> fadeRects; int fadeWidth = 30; // Draw each line in the layout for (int i = 0; i < layout.lineCount(); i++) { QTextLine line = layout.lineAt(i); line.draw(&p, position); // Add a fade out rect to the list if the line is too long if (line.naturalTextWidth() > rect.width()) { int x = int(qMin(line.naturalTextWidth(), (qreal)pixmap.width())) - fadeWidth; int y = int(line.position().y() + position.y()); QRect r = QStyle::visualRect(layout.textOption().textDirection(), pixmap.rect(), QRect(x, y, fadeWidth, int(line.height()))); fadeRects.append(r); } } // Reduce the alpha in each fade out rect using the alpha gradient if (!fadeRects.isEmpty()) { p.setCompositionMode(QPainter::CompositionMode_DestinationIn); foreach (const QRect &rect, fadeRects) { p.fillRect(rect, alphaGradient); }
void tst_QTextFormat::testTabsUsed() { QTextDocument doc; QTextCursor cursor(&doc); QList<QTextOption::Tab> tabs; QTextBlockFormat format; QTextOption::Tab tab; tab.position = 100; tabs.append(tab); format.setTabPositions(tabs); cursor.mergeBlockFormat(format); cursor.insertText("foo\tbar"); //doc.setPageSize(QSizeF(200, 200)); doc.documentLayout()->pageCount(); // force layout; QTextBlock block = doc.begin(); QTextLayout *layout = block.layout(); QVERIFY(layout); QCOMPARE(layout->lineCount(), 1); QTextLine line = layout->lineAt(0); QCOMPARE(line.cursorToX(4), 100.); QTextOption option = layout->textOption(); QCOMPARE(option.tabs().count(), tabs.count()); }
void TestDocumentLayout::placeAnchoredFrame() { initForNewTest(QString()); MockShape *picture = new MockShape(); picture->setSize(QSizeF(100, 100)); KTextAnchor *anchor = new KTextAnchor(picture); anchor->setOffset(QPointF(23, 45)); QTextCursor cursor(doc); KInlineTextObjectManager *manager = new KInlineTextObjectManager(); layout->setInlineTextObjectManager(manager); MockLayoutState *state = new MockLayoutState(doc); layout->setLayout(state); state->shape = shape1; QCOMPARE(doc->begin().text().length(), 0); manager->insertInlineObject(cursor, anchor); QCOMPARE(doc->begin().text().length(), 1); QCOMPARE(cursor.position(), 1); shape1->setPosition(QPointF(300, 300)); layout->layout(); QCOMPARE(picture->parent(), shape1); QCOMPARE(picture->position(), QPointF(23, 59.4)); cursor.setPosition(0); cursor.insertText("foo"); // moves my anchors slightly to the right/down and gives line height layout->layout(); QCOMPARE(picture->parent(), shape1); QPointF newPos = picture->position(); QVERIFY(newPos.x() > 23); QVERIFY(newPos.y() > 45); // it adds the baseline now cursor.movePosition(QTextCursor::End); cursor.insertText("\nNew Line\nAnd another"); layout->layout(); QCOMPARE(picture->position(), newPos); QTextLayout *firstLineLayout = doc->begin().layout(); QTextOption option = firstLineLayout->textOption(); option.setAlignment(Qt::AlignHCenter); firstLineLayout->setTextOption(option); layout->layout(); QTextLine first = doc->begin().layout()->lineAt(0); QVERIFY(first.isValid()); QVERIFY(first.naturalTextRect().x() > 10); newPos.setX(newPos.x() + first.naturalTextRect().x()); // text is moved due to alignment QCOMPARE(picture->position(), newPos); anchor->setOffset(QPointF()); anchor->setAlignment(KTextAnchor::Left); anchor->setAlignment(KTextAnchor::TopOfParagraph); layout->layout(); // image is 100 wide, now centered in a parent of 200 so X = 50 QCOMPARE(picture->position(), QPointF(50, 0)); }
int KTextDocumentLayout::hitTestIterated(QTextFrame::iterator begin, QTextFrame::iterator end, const QPointF &point, Qt::HitTestAccuracy accuracy) const { int position = -1; QTextFrame::iterator it = begin; for (it = begin; it != end; ++it) { QTextBlock block = it.currentBlock(); QTextTable *table = qobject_cast<QTextTable*>(it.currentFrame()); QTextFrame *subFrame = it.currentFrame(); if (table) { QTextTableCell cell = m_state->hitTestTable(table, point); if (cell.isValid()) { position = hitTestIterated(cell.begin(), cell.end(), point, accuracy); if (position == -1) position = cell.lastPosition(); return position; } continue; } else if (subFrame) { position = hitTestIterated(subFrame->begin(), subFrame->end(), point, accuracy); if (position != -1) return position; continue; } else { if (!block.isValid()) continue; } // kDebug(32500) <<"hitTest[" << point.x() <<"," << point.y() <<"]"; QTextLayout *layout = block.layout(); if (point.y() > layout->boundingRect().bottom()) { // just skip this block. position = block.position() + block.length() - 1; continue; } for (int i = 0; i < layout->lineCount(); i++) { QTextLine line = layout->lineAt(i); // kDebug(32500) <<" + line[" << line.textStart() <<"]:" << line.y() <<"-" << line.height(); if (point.y() > line.y() + line.height()) { position = line.textStart() + line.textLength(); continue; } if (accuracy == Qt::ExactHit && point.y() < line.y()) // between lines return -1; if (accuracy == Qt::ExactHit && // left or right of line (point.x() < line.x() || point.x() > line.x() + line.width())) return -1; if (point.x() > line.width() && layout->textOption().textDirection() == Qt::RightToLeft) { // totally right of RTL text means the position is the start of the text. return block.position() + line.textStart(); } return block.position() + line.xToCursor(point.x()); } } return -1; }