Exemple #1
0
void TestDocumentLayout::testCenteredItems()
{
    initForNewTest("ListItem\nListItem\nListItem");

    KoListStyle listStyle;
    KoListLevelProperties llp;
    llp.setStyle(KoListStyle::DecimalItem);
    listStyle.setLevelProperties(llp);

    QTextBlock block = m_doc->begin(); // normal block
    QVERIFY(block.isValid());
    listStyle.applyStyle(block);
    block = block.next(); // centered block
    QVERIFY(block.isValid());
    listStyle.applyStyle(block);
    QTextBlockFormat fmt;
    fmt.setAlignment(Qt::AlignHCenter);
    QTextCursor cursor(block);
    cursor.mergeBlockFormat(fmt);
    block = block.next(); // centered RTL text.
    listStyle.applyStyle(block);
    cursor = QTextCursor(block);
    fmt.setProperty(KoParagraphStyle::TextProgressionDirection, KoText::RightLeftTopBottom);
    cursor.mergeBlockFormat(fmt);

    m_layout->layout();

    block = m_doc->begin();
    QTextLayout *layout = block.layout();
    QTextLine line1 = layout->lineAt(0);
    KoTextBlockData *data1 = dynamic_cast<KoTextBlockData *>(block.userData());
    QVERIFY(line1.isValid());
    QVERIFY(line1.width() < 200); // the counter takes some space.

    block = block.next();
    layout = block.layout();
    QTextLine line2 = layout->lineAt(0);
    KoTextBlockData *data2 = dynamic_cast<KoTextBlockData *>(block.userData());
    QVERIFY(line2.isValid());
    QVERIFY(line2.width() < 200); // the counter takes some space.
    QCOMPARE(line1.width(), line2.width());

    const qreal width1 = line1.naturalTextWidth() + data1->counterWidth() + data1->counterSpacing();
    const qreal width2 = line2.naturalTextWidth() + data2->counterWidth() + data2->counterSpacing();
    QCOMPARE(width1, width2);
    QVERIFY(data1->counterPosition().x() < data2->counterPosition().x());
    const qreal padding = (200 - width2) / 2;
    QVERIFY(padding > 0);// not really a layout test, but the rest will be bogus otherwise.
    QCOMPARE(data2->counterPosition().x(), padding); // close to the centered text.

    // right to left parag places the counter on the right. Its centered, so not the far right.
    block = block.next();
    layout = block.layout();
    QTextLine line = layout->lineAt(0);
    KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData());
    QCOMPARE(data->counterPosition().x(), 200 - padding - data->counterWidth());
}
Exemple #2
0
void TestDocumentLayout::placeAnchoredFrame3()
{
    // basic inline frame that acts like a really big character
    initForNewTest(QString(loremIpsum));
    MockShape *picture = new MockShape();
    picture->setSize(QSizeF(100, 100));
    KTextAnchor *anchor = new KTextAnchor(picture);
    anchor->setAlignment(KTextAnchor::VerticalOffset);
    anchor->setAlignment(KTextAnchor::HorizontalOffset);
    QTextCursor cursor(doc);
    KInlineTextObjectManager *manager = new KInlineTextObjectManager();
    layout->setInlineTextObjectManager(manager);
    MockLayoutState *state = new MockLayoutState(doc);
    layout->setLayout(state);
    state->shape = shape1;
    manager->insertInlineObject(cursor, anchor);
    layout->layout();

/*
    I have two goals with 'offset'.
    One is that I want to be able to change the baseline of my anchored object.
    The other is that OOo / ODF allows me to have an arbitairy distance from my anchor
    so I can place something at the center of my page or whatever.

    So what about I switch from the first to the latter based on the font height.
        If my offset 'x' != 0,  make the image floating.
        If my offset 'y' is such that it would be above or below my line; make floating.
*/

    QTextLayout *lay = doc->begin().layout();
    QVERIFY(lay->lineCount() >= 2);
    QTextLine line = lay->lineAt(0);
    QCOMPARE(line.descent(), (qreal) 100);
    QCOMPARE(line.position(), QPointF());
    line = lay->lineAt(1);
    QVERIFY(line.height() < 20);

    // now move the character which makes it a shape to run around and no longer
    // a big character.
    anchor->setOffset(QPointF(50, 20));
    layout->layout();

    lay = doc->begin().layout();
    QVERIFY(lay->lineCount() >= 2);
    line = lay->lineAt(0);
    QVERIFY(line.height() < 20);
    QCOMPARE(line.position(), QPointF());
    line = lay->lineAt(1);
    QVERIFY(line.height() < 20);
    QCOMPARE(line.position().x(), 0.);
    QVERIFY(qAbs(line.position().y() - 14.4) <  0.125);
}
Exemple #3
0
void YTDelegate::layoutText(QTextLayout& textLayout, QString text, QSize constraint) const
{
    QTextOption textOption(Qt::AlignJustify);
    textLayout.setTextOption(textOption);
    textLayout.setText(text);
    textLayout.beginLayout();
    int lHeight = 0;
    while(true){
        QTextLine line = textLayout.createLine();
        if(!line.isValid())
            break;
        line.setLineWidth(constraint.width());
        line.setPosition(QPointF(0, lHeight));
        if(lHeight + line.height() > constraint.height())
        {
            QTextLine lastLine = textLayout.lineAt(textLayout.lineCount() - 2);
            QString lastString = text.mid(lastLine.textStart());
            QFontMetrics fm(textLayout.font());
            text.chop(lastString.length());
            text += fm.elidedText(lastString, Qt::ElideRight, constraint.width()-1);
            textLayout.endLayout();
            layoutText(textLayout, text, constraint);
            return;
        }
        lHeight += line.height();
        lHeight += line.leading();
    }
    textLayout.endLayout();
}
Exemple #4
0
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());

}
Exemple #5
0
QList<QGlyphRun> QTextFragment::glyphRuns(int pos, int len) const
{
    if (!p || !n)
        return QList<QGlyphRun>();

    int blockNode = p->blockMap().findNode(position());

    const QTextBlockData *blockData = p->blockMap().fragment(blockNode);
    QTextLayout *layout = blockData->layout;

    int blockPosition = p->blockMap().position(blockNode);
    if (pos < 0)
        pos = position() - blockPosition;
    if (len < 0)
        len = length();
    if (len == 0)
        return QList<QGlyphRun>();

    QList<QGlyphRun> ret;
    for (int i=0; i<layout->lineCount(); ++i) {
        QTextLine textLine = layout->lineAt(i);
        ret += textLine.glyphRuns(pos, len);
    }

    return ret;
}
Exemple #6
0
    void setContent(const ToolTipContent &data)
    {
        QString html;
        if (!data.mainText().isEmpty()) {
            html.append("<div><b>" + data.mainText() + "</b></div>");
        }
        html.append(data.subText());

        m_anchor.clear();
        m_document->clear();
        data.registerResources(m_document);
        if (!html.isEmpty()) {
            m_document->setHtml("<p>" + html + "</p>");
        }
        m_document->adjustSize();

        m_haloRects.clear();
        QTextLayout *layout = m_document->begin().layout();
        //layout->setPosition(QPointF(textRect.x(), textBoundingRect->y()));
        QTextLine line;
        for (int i = 0; i < layout->lineCount(); ++i) {
            line = layout->lineAt(i);

            // Add halo rect only when a non empty line is found
            if (line.naturalTextWidth()) {
                m_haloRects.append(line.naturalTextRect().translated(layout->position().toPoint()).toRect().translated(m_margin, m_margin));
            }
        }

        update();
    }
Exemple #7
0
void TestDocumentLayout::testBasicList()
{
    initForNewTest("Base\nListItem\nListItem2: The quick brown fox jums over the lazy dog.\nNormal\nNormal");

    KoParagraphStyle style;
    QTextBlock block = m_doc->begin();
    style.applyStyle(block);
    block = block.next();
    QVERIFY(block.isValid());

    KoListStyle listStyle;
    KoListLevelProperties level1;
    level1.setStyle(KoListStyle::Bullet);
    listStyle.setLevelProperties(level1);
    style.setListStyle(&listStyle);
    style.applyStyle(block); // make this a listStyle
    QVERIFY(block.textList());
    QCOMPARE(block.textList()->format().intProperty(QTextListFormat::ListStyle), (int) KoListStyle::Bullet);
    block = block.next();
    QVERIFY(block.isValid());
    style.applyStyle(block); // make this a listStyle

    m_layout->layout();
    QTextLayout *blockLayout = m_block.layout();

    QCOMPARE(blockLayout->lineAt(0).x(), 0.0);
    block = m_doc->begin().next();
    QVERIFY(block.isValid());
    blockLayout = block.layout(); // parag 2
    KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData());
    QVERIFY(data);
    qreal counterSpacing = data->counterSpacing();
    QVERIFY(counterSpacing > 0.);
    // 12 is hardcoded to be the width of a discitem (taken from the default font):
    QCOMPARE(blockLayout->lineAt(0).x(), 12.0 + counterSpacing);
    block = block.next();
    QVERIFY(block.isValid());
    blockLayout = block.layout(); // parag 3
    QCOMPARE(blockLayout->lineAt(0).x(), 12.0 + counterSpacing);
    QVERIFY(blockLayout->lineCount() > 1);
    QCOMPARE(blockLayout->lineAt(1).x(), 12.0 + counterSpacing); // make sure not only the first line is indented
    block = block.next();
    QVERIFY(block.isValid());
    blockLayout = block.layout(); // parag 4
    QCOMPARE(blockLayout->lineAt(0).x(), 0.0);
}
Exemple #8
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;
}
Exemple #9
0
void TestSections::testBasicLayout()
{
    KSectionStyle *sectionStyle = new KSectionStyle();
    Q_ASSERT(sectionStyle);
    sectionStyle->setLeftMargin(0.0);
    sectionStyle->setRightMargin(0.0);

    initTest(sectionStyle);

    m_layout->layout();

    // a block in a section with no special margins or columns should be just as wide
    // as the reference (first) block.
    QTextLayout *blockLayout = m_doc->begin().layout();
    QCOMPARE(blockLayout->lineAt(0).width(), 200.0);

    blockLayout = m_doc->begin().next().layout();
    QCOMPARE(blockLayout->lineAt(0).width(), 200.0);
    cleanupTest();
}
Exemple #10
0
void TestSections::testMoveByMargin()
{
    KSectionStyle *sectionStyle = new KSectionStyle();
    Q_ASSERT(sectionStyle);
    sectionStyle->setLeftMargin(20.0);
    sectionStyle->setRightMargin(-20.0);

    initTest(sectionStyle);

    m_layout->layout();

    // a block in a section with margins (and no columns) that essentially just moves the block
    // should be just as wide as the reference (first) block.
    QTextLayout *blockLayout = m_doc->begin().layout();
    QCOMPARE(blockLayout->lineAt(0).width(), 200.0);

    blockLayout = m_doc->begin().next().layout();
    QCOMPARE(blockLayout->lineAt(0).width(), 200.0);
    cleanupTest();
}
ParagraphFragment::ParagraphFragment(KShape *shape, const QTextBlock &textBlock, KParagraphStyle *style)
        : m_shape(shape)
{
    QTextLayout *layout = textBlock.layout();

    m_isSingleLine = (layout->lineCount() == 1);

    // border rectangle left and right
    m_border.setLeft(0.0);
    m_border.setRight(shape->size().width());

    // first line rectangle
    m_firstLine = layout->lineAt(0).rect();
    m_firstLine.setRight(m_border.right() - style->rightMargin());

    // counter rectangle
    KTextBlockData *blockData = static_cast<KTextBlockData*>(textBlock.userData());
    if (blockData != NULL) {
        m_counter = QRectF(blockData->counterPosition(), QSizeF(blockData->counterWidth() - blockData->counterSpacing(), m_firstLine.height()));
    }

    // following lines rectangle
    if (!m_isSingleLine) {
        m_followingLines = QRectF(layout->lineAt(1).rect().topLeft(), layout->lineAt(layout->lineCount() - 1).rect().bottomRight());
    } else {
        m_followingLines = m_firstLine;
    }

    // border rectangle top and bottom
    m_border.setTop(m_firstLine.top() - style->topMargin());
    m_border.setBottom(m_isSingleLine ? m_firstLine.bottom() + style->bottomMargin() : m_followingLines.bottom() + style->bottomMargin());

    // TODO: the lines overlap slightly so right now we simply
    // calculate the mean of the two y-values, should be handled properly
    if (!m_isSingleLine) {
        qreal lineBreak((m_firstLine.bottom() + m_followingLines.top()) / 2.0);
        m_firstLine.setBottom(lineBreak);
        m_counter.setBottom(lineBreak);
        m_followingLines.setTop(lineBreak);
    }
}
Exemple #12
0
void TestSections::testShrinkByMargin()
{
    KSectionStyle *sectionStyle = new KSectionStyle();
    Q_ASSERT(sectionStyle);
    sectionStyle->setLeftMargin(20.0);
    sectionStyle->setRightMargin(20.0);

    initTest(sectionStyle);

    m_layout->layout();

    // a block in a section with margins (and no columns) should be exact amoung less wide
    // as the reference (first) block.
    QTextLayout *blockLayout = m_doc->begin().layout();
    QCOMPARE(blockLayout->lineAt(0).width(), 200.0);

    blockLayout = m_doc->begin().next().layout();
    QEXPECT_FAIL("", "unimplemented", Abort);
    QCOMPARE(blockLayout->lineAt(0).width(), 160.0);
    cleanupTest();
}
qreal TextDocumentLayout::blockWidth(const QTextBlock &block)
{
    QTextLayout *layout = block.layout();
    if (!layout->lineCount())
        return 0; // only for layouted blocks
    qreal blockWidth = 0;
    for (int i = 0; i < layout->lineCount(); ++i) {
        QTextLine line = layout->lineAt(i);
        blockWidth = qMax(line.naturalTextWidth() + 8, blockWidth);
    }
    return blockWidth;
}
void TestTableLayout::testColumnWidthUndefined()
{
    setupTest("","","","","","");
    m_layout->layout();

    QCOMPARE(m_table->columns(), 3);
    QCOMPARE(m_table->rows(), 3);
    QVERIFY(qAbs(m_block.layout()->lineAt(0).width() - 200.0) < ROUNDING);
    QTextLayout *lay = bottomLeftCellBlock().layout();
    QVERIFY(lay);
    QCOMPARE(lay->lineCount(), 1);
    QVERIFY(qAbs(lay->lineAt(0).width() - 200.0/3) < ROUNDING);
    lay = bottomMidCellBlock().layout();
    QVERIFY(lay);
    QCOMPARE(lay->lineCount(), 1);
    QVERIFY(qAbs(lay->lineAt(0).width() - 200.0/3) < ROUNDING);
    lay = bottomRightCellBlock().layout();
    QVERIFY(lay);
    QCOMPARE(lay->lineCount(), 1);
    QVERIFY(qAbs(lay->lineAt(0).width() - 200.0/3) < ROUNDING);
}
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);
        }
Exemple #16
0
QPainterPath Text::shape() const
      {
      QPainterPath pp;
#if 0
      for (QTextBlock tb = doc()->begin(); tb.isValid(); tb = tb.next()) {
            QTextLayout* tl = tb.layout();
            int n = tl->lineCount();
            for (int i = 0; i < n; ++i) {
                  QTextLine l = tl->lineAt(i);
                  QRectF r(l.naturalTextRect().translated(tl->position()));
                  r.adjust(-l.position().x(), 0.0, 0.0, 0.0);
                  pp.addRect(r);
                  }
            }
#endif
      return pp;
      }
QRectF TextDocumentLayout::blockBoundingRect(const QTextBlock &block) const
{
    if (!block.isValid()) { return QRectF(); }
    QTextLayout *tl = block.layout();

    if (!tl->lineCount())
        const_cast<TextDocumentLayout*>(this)->layoutBlock(block);


    QRectF br;
    if (block.isVisible()) {
        br = QRectF(QPointF(0, 0), tl->boundingRect().bottomRight());
        if (tl->lineCount() == 1)
            br.setWidth(qMax(br.width(), tl->lineAt(0).naturalTextWidth()));
        qreal margin = document()->documentMargin();
        br.adjust(0, 0, margin, 0);
        if (!block.next().isValid())
            br.adjust(0, 0, 0, margin);
    }
    return br;
}
void QQuickTextNodeEngine::addTextBlock(QTextDocument *textDocument, const QTextBlock &block, const QPointF &position, const QColor &textColor, const QColor &anchorColor, int selectionStart, int selectionEnd)
{
    Q_ASSERT(textDocument);
#ifndef QT_NO_IM
    int preeditLength = block.isValid() ? block.layout()->preeditAreaText().length() : 0;
    int preeditPosition = block.isValid() ? block.layout()->preeditAreaPosition() : -1;
#endif

    QVarLengthArray<QTextLayout::FormatRange> colorChanges;
    mergeFormats(block.layout(), &colorChanges);

    QPointF blockPosition = textDocument->documentLayout()->blockBoundingRect(block).topLeft() + position;
    if (QTextList *textList = block.textList()) {
        QPointF pos = blockPosition;
        QTextLayout *layout = block.layout();
        if (layout->lineCount() > 0) {
            QTextLine firstLine = layout->lineAt(0);
            Q_ASSERT(firstLine.isValid());

            setCurrentLine(firstLine);

            QRectF textRect = firstLine.naturalTextRect();
            pos += textRect.topLeft();
            if (block.textDirection() == Qt::RightToLeft)
                pos.rx() += textRect.width();

            const QTextCharFormat charFormat = block.charFormat();
            QFont font(charFormat.font());
            QFontMetricsF fontMetrics(font);
            QTextListFormat listFormat = textList->format();

            QString listItemBullet;
            switch (listFormat.style()) {
            case QTextListFormat::ListCircle:
                listItemBullet = QChar(0x25E6); // White bullet
                break;
            case QTextListFormat::ListSquare:
                listItemBullet = QChar(0x25AA); // Black small square
                break;
            case QTextListFormat::ListDecimal:
            case QTextListFormat::ListLowerAlpha:
            case QTextListFormat::ListUpperAlpha:
            case QTextListFormat::ListLowerRoman:
            case QTextListFormat::ListUpperRoman:
                listItemBullet = textList->itemText(block);
                break;
            default:
                listItemBullet = QChar(0x2022); // Black bullet
                break;
            };

            QSizeF size(fontMetrics.width(listItemBullet), fontMetrics.height());
            qreal xoff = fontMetrics.width(QLatin1Char(' '));
            if (block.textDirection() == Qt::LeftToRight)
                xoff = -xoff - size.width();
            setPosition(pos + QPointF(xoff, 0));

            QTextLayout layout;
            layout.setFont(font);
            layout.setText(listItemBullet); // Bullet
            layout.beginLayout();
            QTextLine line = layout.createLine();
            line.setPosition(QPointF(0, 0));
            layout.endLayout();

            QList<QGlyphRun> glyphRuns = layout.glyphRuns();
            for (int i=0; i<glyphRuns.size(); ++i)
                addUnselectedGlyphs(glyphRuns.at(i));
        }
    }

    int textPos = block.position();
    QTextBlock::iterator blockIterator = block.begin();

    while (!blockIterator.atEnd()) {
        QTextFragment fragment = blockIterator.fragment();
        QString text = fragment.text();
        if (text.isEmpty())
            continue;

        QTextCharFormat charFormat = fragment.charFormat();
        QFont font(charFormat.font());
        QFontMetricsF fontMetrics(font);

        int fontHeight = fontMetrics.descent() + fontMetrics.ascent();
        int valign = charFormat.verticalAlignment();
        if (valign == QTextCharFormat::AlignSuperScript)
            setPosition(QPointF(blockPosition.x(), blockPosition.y() - fontHeight / 2));
        else if (valign == QTextCharFormat::AlignSubScript)
            setPosition(QPointF(blockPosition.x(), blockPosition.y() + fontHeight / 6));
        else
            setPosition(blockPosition);

        if (text.contains(QChar::ObjectReplacementCharacter)) {
            QTextFrame *frame = qobject_cast<QTextFrame *>(textDocument->objectForFormat(charFormat));
            if (frame && frame->frameFormat().position() == QTextFrameFormat::InFlow) {
                int blockRelativePosition = textPos - block.position();
                QTextLine line = block.layout()->lineForTextPosition(blockRelativePosition);
                if (!currentLine().isValid()
                        || line.lineNumber() != currentLine().lineNumber()) {
                    setCurrentLine(line);
                }

                QQuickTextNodeEngine::SelectionState selectionState =
                        (selectionStart < textPos + text.length()
                         && selectionEnd >= textPos)
                        ? QQuickTextNodeEngine::Selected
                        : QQuickTextNodeEngine::Unselected;

                addTextObject(QPointF(), charFormat, selectionState, textDocument, textPos);
            }
            textPos += text.length();
        } else {
            if (charFormat.foreground().style() != Qt::NoBrush)
                setTextColor(charFormat.foreground().color());
            else if (charFormat.isAnchor())
                setTextColor(anchorColor);
            else
                setTextColor(textColor);

            int fragmentEnd = textPos + fragment.length();
#ifndef QT_NO_IM
            if (preeditPosition >= 0
                    && (preeditPosition + block.position()) >= textPos
                    && (preeditPosition + block.position()) <= fragmentEnd) {
                fragmentEnd += preeditLength;
            }
#endif
            if (charFormat.background().style() != Qt::NoBrush) {
                QTextLayout::FormatRange additionalFormat;
                additionalFormat.start = textPos - block.position();
                additionalFormat.length = fragmentEnd - textPos;
                additionalFormat.format = charFormat;
                colorChanges << additionalFormat;
            }

            textPos = addText(block, charFormat, textColor, colorChanges, textPos, fragmentEnd,
                                                 selectionStart, selectionEnd);
        }

        ++blockIterator;
    }

#ifndef QT_NO_IM
    if (preeditLength >= 0 && textPos <= block.position() + preeditPosition) {
        setPosition(blockPosition);
        textPos = block.position() + preeditPosition;
        QTextLine line = block.layout()->lineForTextPosition(preeditPosition);
        if (!currentLine().isValid()
                || line.lineNumber() != currentLine().lineNumber()) {
            setCurrentLine(line);
        }
        textPos = addText(block, block.charFormat(), textColor, colorChanges,
                                             textPos, textPos + preeditLength,
                                             selectionStart, selectionEnd);
    }
#endif

    setCurrentLine(QTextLine()); // Reset current line because the text layout changed
    m_hasContents = true;
}
Exemple #19
0
void TextLayer::recreateTexture(VidgfxContext *gfx)
{
	if(!m_isTexDirty)
		return; // Don't waste any time if it hasn't changed
	m_isTexDirty = false;

	// Delete existing texture if one exists
	if(m_texture != NULL)
		vidgfx_context_destroy_tex(gfx, m_texture);
	m_texture = NULL;

	// Determine texture size. We need to keep in mind that the text in the
	// document might extend outside of the layer's bounds.
	m_document.setTextWidth(m_rect.width());
	QSize size(
		(int)ceilf(m_document.size().width()),
		(int)ceilf(m_document.size().height()));

	if(m_document.isEmpty() || size.isEmpty()) {
		// Nothing to display
		return;
	}

	// Create temporary canvas. We need to be careful here as text is rendered
	// differently on premultiplied vs non-premultiplied pixel formats. On a
	// premultiplied format text is rendered with subpixel rendering enabled
	// while on a non-premultiplied format it is not. As we don't want subpixel
	// rendering we use the standard ARGB32 format.
	QSize imgSize(
		size.width() + m_strokeSize * 2, size.height() + m_strokeSize * 2);
	QImage img(imgSize, QImage::Format_ARGB32);
	img.fill(Qt::transparent);
	QPainter p(&img);
	p.setRenderHint(QPainter::Antialiasing, true);

	// Render text
	//m_document.drawContents(&p);

	// Render stroke
	if(m_strokeSize > 0) {
#define STROKE_TECHNIQUE 0
#if STROKE_TECHNIQUE == 0
		// Technique 0: Use QTextDocument's built-in text outliner
		//quint64 timeStart = App->getUsecSinceExec();

		QTextDocument *outlineDoc = m_document.clone(this);

		QTextCharFormat format;
		QPen pen(m_strokeColor, (double)(m_strokeSize * 2));
		pen.setJoinStyle(Qt::RoundJoin);
		format.setTextOutline(pen);
		QTextCursor cursor(outlineDoc);
		cursor.select(QTextCursor::Document);
		cursor.mergeCharFormat(format);

		// Take into account the stroke offset
		p.translate(m_strokeSize, m_strokeSize);

		//quint64 timePath = App->getUsecSinceExec();
		outlineDoc->drawContents(&p);
		delete outlineDoc;

		//quint64 timeEnd = App->getUsecSinceExec();
		//appLog() << "Path time = " << (timePath - timeStart) << " usec";
		//appLog() << "Render time = " << (timeEnd - timePath) << " usec";
		//appLog() << "Full time = " << (timeEnd - timeStart) << " usec";
#elif STROKE_TECHNIQUE == 1
		// Technique 1: Create a text QPainterPath and stroke it
		quint64 timeStart = App->getUsecSinceExec();

		// Create the path for the text's stroke
		QPainterPath path;
		QTextBlock &block = m_document.firstBlock();
		int numBlocks = m_document.blockCount();
		for(int i = 0; i < numBlocks; i++) {
			QTextLayout *layout = block.layout();
			for(int j = 0; j < layout->lineCount(); j++) {
				QTextLine &line = layout->lineAt(j);
				const QString text = block.text().mid(
					line.textStart(), line.textLength());
				QPointF pos = layout->position() + line.position();
				pos.ry() += line.ascent();
				//appLog() << pos << ": " << text;
				path.addText(pos, block.charFormat().font(), text);
			}
			block = block.next();
		}

		quint64 timePath = App->getUsecSinceExec();
		path = path.simplified(); // Fixes gaps with large stroke sizes
		quint64 timeSimplify = App->getUsecSinceExec();

		// Render the path
		//p.strokePath(path, QPen(m_strokeColor, m_strokeSize));

		// Convert it to a stroke
		QPainterPathStroker stroker;
		stroker.setWidth(m_strokeSize);
		//stroker.setCurveThreshold(2.0);
		stroker.setJoinStyle(Qt::RoundJoin);
		path = stroker.createStroke(path);

		// Render the path
		p.fillPath(path, m_strokeColor);

		quint64 timeEnd = App->getUsecSinceExec();
		appLog() << "Path time = " << (timePath - timeStart) << " usec";
		appLog() << "Simplify time = " << (timeSimplify - timePath) << " usec";
		appLog() << "Render time = " << (timeEnd - timeSimplify) << " usec";
		appLog() << "Full time = " << (timeEnd - timeStart) << " usec";
#elif STROKE_TECHNIQUE == 2
		// Technique 2: Similar to technique 1 but do each block separately
		quint64 timeStart = App->getUsecSinceExec();
		quint64 timeTotalSimplify = 0;
		quint64 timeTotalRender = 0;

		// Create the path for the text's stroke
		QTextBlock &block = m_document.firstBlock();
		int numBlocks = m_document.blockCount();
		for(int i = 0; i < numBlocks; i++) {
			// Convert this block to a painter path
			QPainterPath path;
			QTextLayout *layout = block.layout();
			for(int j = 0; j < layout->lineCount(); j++) {
				QTextLine &line = layout->lineAt(j);
				const QString text = block.text().mid(
					line.textStart(), line.textLength());
				QPointF pos = layout->position() + line.position() +
					QPointF(m_strokeSize, m_strokeSize);
				pos.ry() += line.ascent();
				//appLog() << pos << ": " << text;
				path.addText(pos, block.charFormat().font(), text);
			}

			// Prevent gaps appearing at larger stroke sizes
			quint64 timeA = App->getUsecSinceExec();
			path = path.simplified();
			quint64 timeB = App->getUsecSinceExec();
			timeTotalSimplify += timeB - timeA;

			// Render the path
			QPen pen(m_strokeColor, m_strokeSize * 2);
			pen.setJoinStyle(Qt::RoundJoin);
			p.strokePath(path, pen);
			timeA = App->getUsecSinceExec();
			timeTotalRender += timeA - timeB;

			// Iterate
			block = block.next();
		}

		// Make the final draw take into account the stroke offset
		p.translate(m_strokeSize, m_strokeSize);

		quint64 timeEnd = App->getUsecSinceExec();
		appLog() << "Simplify time = " << timeTotalSimplify << " usec";
		appLog() << "Render time = " << timeTotalRender << " usec";
		appLog() << "Full time = " << (timeEnd - timeStart) << " usec";
#elif STROKE_TECHNIQUE == 3
		// Technique 3: Raster brute-force where for each destination pixel
		// we measure the distance to the closest opaque source pixel
		quint64 timeStart = App->getUsecSinceExec();

		// Get bounding region based on text line bounding rects
		QRegion region;
		QTextBlock &block = m_document.firstBlock();
		int numBlocks = m_document.blockCount();
		for(int i = 0; i < numBlocks; i++) {
			QTextLayout *layout = block.layout();
			for(int j = 0; j < layout->lineCount(); j++) {
				QTextLine &line = layout->lineAt(j);
				const QString text = block.text().mid(
					line.textStart(), line.textLength());
				QRect rect = line.naturalTextRect()
					.translated(layout->position()).toAlignedRect();
				if(rect.isEmpty())
					continue; // Don't add empty rectangles
				rect.adjust(0, 0, 1, 0); // QTextLine is incorrect?
				rect.adjust(
					-m_strokeSize, -m_strokeSize,
					m_strokeSize, m_strokeSize);
				//appLog() << rect;
				region += rect;
			}

			// Iterate
			block = block.next();
		}
		quint64 timeRegion = App->getUsecSinceExec();

#if 0
		// Debug bounding region
		QPainterPath regionPath;
		regionPath.addRegion(region);
		regionPath.setFillRule(Qt::WindingFill);
		p.fillPath(regionPath, QColor(255, 0, 0, 128));
#endif // 0

		// We cannot read and write to the same image at the same time so
		// create a second one. Note that this is not premultiplied.
		QImage imgOut(size, QImage::Format_ARGB32);
		imgOut.fill(Qt::transparent);

		// Do distance calculation. We assume that non-fully transparent
		// pixels are always next to a fully opaque one so if the closest
		// "covered" pixel is not fully opaque then we can use that pixel's
		// opacity to determine the distance to the shape's edge.
		for(int y = 0; y < img.height(); y++) {
			for(int x = 0; x < img.width(); x++) {
				if(!region.contains(QPoint(x, y)))
					continue;
				float dist = getDistance(img, x, y, m_strokeSize);

				// We fake antialiasing by blurring the edge by 1px
				float outEdge = (float)m_strokeSize;
				if(dist >= outEdge)
					continue; // Outside stroke completely
				float opacity = qMin(1.0f, outEdge - dist);
				QColor col = m_strokeColor;
				col.setAlphaF(col.alphaF() * opacity);

				// Blend the stroke so that it appears under the existing
				// pixel data
				QRgb origRgb = img.pixel(x, y);
				QColor origCol(origRgb);
				origCol.setAlpha(qAlpha(origRgb));
				col = blendColors(col, origCol, 1.0f);
				imgOut.setPixel(x, y, col.rgba());
			}
		}
		quint64 timeRender = App->getUsecSinceExec();

		// Swap image data
		p.end();
		img = imgOut;
		p.begin(&img);

		quint64 timeEnd = App->getUsecSinceExec();
		appLog() << "Region time = " << (timeRegion - timeStart) << " usec";
		appLog() << "Render time = " << (timeRender - timeRegion) << " usec";
		appLog() << "Swap time = " << (timeEnd - timeRender) << " usec";
		appLog() << "Full time = " << (timeEnd - timeStart) << " usec";
#endif // STROKE_TECHNIQUE
	}

	// Render text
	m_document.drawContents(&p);

	// Convert the image to a GPU texture
	m_texture = vidgfx_context_new_tex(gfx, img);

	// Preview texture for debugging
	//img.save(App->getDataDirectory().filePath("Preview.png"));
}
Exemple #20
0
void TestDocumentLayout::testNumberedList()
{
    initForNewTest("Base\nListItem1\nListItem2\nListItem3\nListItem4\nListItem5\nListItem6\nListItem6\nListItem7\nListItem8\nListItem9\nListItem10\nListItem11\nListItem12\n");

    KoParagraphStyle style;
    m_styleManager->add(&style);
    QTextBlock block = m_doc->begin();
    style.applyStyle(block);
    block = block.next();

    KoListStyle listStyle;
    KoListLevelProperties llp;
    llp.setStyle(KoListStyle::DecimalItem);
    listStyle.setLevelProperties(llp);
    style.setListStyle(&listStyle);

    QTextList *previous = 0;
    int i;
    for (i = 1; i <= 9; i++) {
        QVERIFY(block.isValid());
        // qDebug() << "->" << block.text();
        style.applyStyle(block);
        QTextList *textList = block.textList();
        QVERIFY(textList);
        if (previous == 0) {
            previous = textList;
        } else {
            QCOMPARE(textList, previous);
        }
        QCOMPARE(textList->format().intProperty(QTextListFormat::ListStyle), (int)(KoListStyle::DecimalItem));
        block = block.next();
    }
    m_layout->layout();
    QTextLayout *blockLayout = m_block.layout();

    QCOMPARE(blockLayout->lineAt(0).x(), 0.0);
    QTextBlock blok = m_doc->begin().next();
    qreal indent = blok.layout()->lineAt(0).x();
    QVERIFY(indent > 0.0);
    for (i = 1; i <= 9; ++i) {
        // qDebug() << "=>" << blok.text();
        QTextList *textList = blok.textList();
        QVERIFY(textList);
        QCOMPARE(blok.layout()->lineAt(0).x(), indent); // all the same indent.
        blok = blok.next();
    }

    // now make number of listitems be more than 10, so we use 2 digits.
    for (i = 9; i <= 12; ++i) {
        QVERIFY(block.isValid());
        style.applyStyle(block);
        // qDebug() << "->" << block.text();
        block = block.next();
    }
    m_layout->layout();
    blockLayout = m_block.layout();

    QCOMPARE(blockLayout->lineAt(0).x(), 0.0);
    blok = m_doc->begin().next();
    qreal indent2 = blok.layout()->lineAt(0).x();
    QVERIFY(indent2 > indent); // since it takes an extra digit
    for (i = 2; i <= 12; ++i) {
        // qDebug() << "=>" << blok.text();
        QCOMPARE(blok.layout()->lineAt(0).x(), indent2); // all the same indent.
        blok = blok.next();
    }

    // now to make sure the text is actually properly set.
    block = m_doc->begin().next();
    i = 1;
    while (block.isValid() && i < 13) {
        KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData());
        QVERIFY(data);
        QCOMPARE(data->counterText(), QString::number(i++));
        block = block.next();
    }

    llp.setListItemSuffix(".");
    llp.setStartValue(4);
    listStyle.setLevelProperties(llp);

    QTextCursor cursor(m_doc);
    cursor.setPosition(10); // listItem1
    QTextBlockFormat format = cursor.blockFormat();
    format.setProperty(KoParagraphStyle::ListStartValue, 4);
    cursor.setBlockFormat(format);

    cursor.setPosition(40); // listItem4
    format = cursor.blockFormat();
    format.setProperty(KoParagraphStyle::ListStartValue, 12);
    cursor.setBlockFormat(format);

    // at this point we start numbering at 4. Have 4, 5, 6, 12, 13, 14, 15 etc
    m_layout->layout();

    // now to make sur the text is actually properly set.
    block = m_doc->begin().next();
    i = 4;
    while (block.isValid() && i < 22) {
        if (i == 7) {
            i = 12;
        }
        KoTextBlockData *data = dynamic_cast<KoTextBlockData *>(block.userData());
        QVERIFY(data);
        QCOMPARE(data->counterText(), QString::number(i++));
        block = block.next();
    }
}
QPainterPath TextEditorOverlay::createSelectionPath(const QTextCursor &begin, const QTextCursor &end,
                                                    const QRect &clip)
{
    if (begin.isNull() || end.isNull() || begin.position() > end.position())
        return QPainterPath();

    QPointF offset = m_editor->contentOffset();
    QRect viewportRect = rect();
    QTextDocument *document = m_editor->document();

    if (m_editor->blockBoundingGeometry(begin.block()).translated(offset).top() > clip.bottom() + 10
        || m_editor->blockBoundingGeometry(end.block()).translated(offset).bottom() < clip.top() - 10
        )
        return QPainterPath(); // nothing of the selection is visible


    QTextBlock block = begin.block();

    if (block.blockNumber() < m_editor->firstVisibleBlock().blockNumber() - 4)
        block = m_editor->document()->findBlockByNumber(m_editor->firstVisibleBlock().blockNumber() - 4);

    bool inSelection = false;

    QVector<QRectF> selection;

    if (begin.position() == end.position()) {
        // special case empty selections
        const QRectF blockGeometry = m_editor->blockBoundingGeometry(block);
        QTextLayout *blockLayout = block.layout();
        int pos = begin.position() - begin.block().position();
        QTextLine line = blockLayout->lineForTextPosition(pos);
        QRectF lineRect = line.naturalTextRect();
        int x = line.cursorToX(pos);
        lineRect.setLeft(x - m_borderWidth);
        lineRect.setRight(x + m_borderWidth);
        selection += lineRect.translated(blockGeometry.topLeft());
    } else {
        for (; block.isValid() && block.blockNumber() <= end.blockNumber(); block = block.next()) {
            if (! block.isVisible())
                continue;

            const QRectF blockGeometry = m_editor->blockBoundingGeometry(block);
            QTextLayout *blockLayout = block.layout();

            QTextLine line = blockLayout->lineAt(0);
            bool firstOrLastBlock = false;

            int beginChar = 0;
            if (!inSelection) {
                if (block == begin.block()) {
                    beginChar = begin.positionInBlock();
                    line = blockLayout->lineForTextPosition(beginChar);
                    firstOrLastBlock = true;
                }
                inSelection = true;
            } else {
//                while (beginChar < block.length() && document->characterAt(block.position() + beginChar).isSpace())
//                    ++beginChar;
//                if (beginChar == block.length())
//                    beginChar = 0;
            }

            int lastLine = blockLayout->lineCount()-1;
            int endChar = -1;
            if (block == end.block()) {
                endChar = end.positionInBlock();
                lastLine = blockLayout->lineForTextPosition(endChar).lineNumber();
                inSelection = false;
                firstOrLastBlock = true;
            } else {
                endChar = block.length();
                while (endChar > beginChar && document->characterAt(block.position() + endChar - 1).isSpace())
                    --endChar;
            }

            QRectF lineRect = line.naturalTextRect();
            if (beginChar < endChar) {
                lineRect.setLeft(line.cursorToX(beginChar));
                if (line.lineNumber() == lastLine)
                    lineRect.setRight(line.cursorToX(endChar));
                selection += lineRect.translated(blockGeometry.topLeft());

                for (int lineIndex = line.lineNumber()+1; lineIndex <= lastLine; ++lineIndex) {
                    line = blockLayout->lineAt(lineIndex);
                    lineRect = line.naturalTextRect();
                    if (lineIndex == lastLine)
                        lineRect.setRight(line.cursorToX(endChar));
                    selection += lineRect.translated(blockGeometry.topLeft());
                }
            } else { // empty lines
                const int emptyLineSelectionSize = 16;
                if (!firstOrLastBlock && !selection.isEmpty()) { // middle
                    lineRect.setLeft(selection.last().left());
                } else if (inSelection) { // first line
                    lineRect.setLeft(line.cursorToX(beginChar));
                } else { // last line
                    if (endChar == 0)
                        break;
                    lineRect.setLeft(line.cursorToX(endChar) - emptyLineSelectionSize);
                }
                lineRect.setRight(lineRect.left() + emptyLineSelectionSize);
                selection += lineRect.translated(blockGeometry.topLeft());
            }

            if (!inSelection)
                break;

            if (blockGeometry.translated(offset).y() > 2*viewportRect.height())
                break;
        }
    }


    if (selection.isEmpty())
        return QPainterPath();

    QVector<QPointF> points;

    const int margin = m_borderWidth/2;
    const int extra = 0;

    const QRectF &firstSelection = selection.at(0);
    points += (firstSelection.topLeft() + firstSelection.topRight()) / 2 + QPointF(0, -margin);
    points += firstSelection.topRight() + QPointF(margin+1, -margin);
    points += firstSelection.bottomRight() + QPointF(margin+1, 0);

    const int count = selection.count();
    for (int i = 1; i < count-1; ++i) {
#define MAX3(a,b,c) qMax(a, qMax(b,c))
        qreal x = MAX3(selection.at(i-1).right(),
                       selection.at(i).right(),
                       selection.at(i+1).right()) + margin;

        points += QPointF(x+1, selection.at(i).top());
        points += QPointF(x+1, selection.at(i).bottom());
    }

    const QRectF &lastSelection = selection.at(count-1);
    points += lastSelection.topRight() + QPointF(margin+1, 0);
    points += lastSelection.bottomRight() + QPointF(margin+1, margin+extra);
    points += lastSelection.bottomLeft() + QPointF(-margin, margin+extra);
    points += lastSelection.topLeft() + QPointF(-margin, 0);

    for (int i = count-2; i > 0; --i) {
#define MIN3(a,b,c) qMin(a, qMin(b,c))
        qreal x = MIN3(selection.at(i-1).left(),
                       selection.at(i).left(),
                       selection.at(i+1).left()) - margin;

        points += QPointF(x, selection.at(i).bottom()+extra);
        points += QPointF(x, selection.at(i).top());
    }

    points += firstSelection.bottomLeft() + QPointF(-margin, extra);
    points += firstSelection.topLeft() + QPointF(-margin, -margin);


    QPainterPath path;
    const int corner = 4;
    path.moveTo(points.at(0));
    points += points.at(0);
    QPointF previous = points.at(0);
    for (int i = 1; i < points.size(); ++i) {
        QPointF point = points.at(i);
        if (point.y() == previous.y() && qAbs(point.x() - previous.x()) > 2*corner) {
            QPointF tmp = QPointF(previous.x() + corner * ((point.x() > previous.x())?1:-1), previous.y());
            path.quadTo(previous, tmp);
            previous = tmp;
            i--;
            continue;
        } else if (point.x() == previous.x() && qAbs(point.y() - previous.y()) > 2*corner) {
            QPointF tmp = QPointF(previous.x(), previous.y() + corner * ((point.y() > previous.y())?1:-1));
            path.quadTo(previous, tmp);
            previous = tmp;
            i--;
            continue;
        }


        QPointF target = (previous + point) / 2;
        path.quadTo(previous, target);
        previous = points.at(i);
    }
    path.closeSubpath();
    path.translate(offset);
    return path;
}
Exemple #22
0
void Text::layout()
      {
#if 0
      QSizeF pageSize(-1.0, 1000000);
      setPos(0.0, 0.0);
      if (parent() && _layoutToParentWidth) {
            pageSize.setWidth(parent()->width());
            if (parent()->type() == HBOX || parent()->type() == VBOX || parent()->type() == TBOX) {
                  Box* box = static_cast<Box*>(parent());
                  rxpos() += box->leftMargin() * DPMM;
                  rypos() += box->topMargin() * DPMM;
                  // pageSize.setHeight(box->height() - (box->topMargin() + box->bottomMargin()) * DPMM);
                  pageSize.setWidth(box->width()   - (box->leftMargin() + box->rightMargin()) * DPMM);
                  }
            }

      QTextOption to = _doc->defaultTextOption();
      to.setUseDesignMetrics(true);
      to.setWrapMode(pageSize.width() <= 0.0 ? QTextOption::NoWrap : QTextOption::WrapAtWordBoundaryOrAnywhere);
      _doc->setDefaultTextOption(to);

      if (pageSize.width() <= 0.0)
            _doc->setTextWidth(_doc->idealWidth());
      else
            _doc->setPageSize(pageSize);

      if (hasFrame()) {
            frame = QRectF();
            for (QTextBlock tb = _doc->begin(); tb.isValid(); tb = tb.next()) {
                  QTextLayout* tl = tb.layout();
                  int n = tl->lineCount();
                  for (int i = 0; i < n; ++i)
                        // frame |= tl->lineAt(0).naturalTextRect().translated(tl->position());
                        frame |= tl->lineAt(0).rect().translated(tl->position());
                  }
            if (circle()) {
                  if (frame.width() > frame.height()) {
                        frame.setY(frame.y() + (frame.width() - frame.height()) * -.5);
                        frame.setHeight(frame.width());
                        }
                  else {
                        frame.setX(frame.x() + (frame.height() - frame.width()) * -.5);
                        frame.setWidth(frame.height());
                        }
                  }
            qreal w = (paddingWidth() + frameWidth() * .5) * DPMM;
            frame.adjust(-w, -w, w, w);
            w = frameWidth() * DPMM;
            _bbox = frame.adjusted(-w, -w, w, w);
            }
      else {
            _bbox = QRectF(QPointF(0.0, 0.0), _doc->size()); //_doc->documentLayout()->frameBoundingRect(_doc->rootFrame());
            }
      _doc->setModified(false);
      style().layout(this);      // process alignment

      if ((style().align() & ALIGN_VCENTER) && (subtype() == TEXT_TEXTLINE)) {
            // special case: vertically centered text with TextLine needs to
            // take into account the line width
            TextLineSegment* tls = (TextLineSegment*)parent();
            TextLine* tl = (TextLine*)(tls->line());
            qreal textlineLineWidth = point(tl->lineWidth());
            rypos() -= textlineLineWidth * .5;
            }

      if (parent() == 0)
            return;
      if (parent()->type() == SEGMENT) {
            Segment* s = static_cast<Segment*>(parent());
            rypos() += s ? s->measure()->system()->staff(staffIdx())->y() : 0.0;
            }
#endif
      Font f = style().font(spatium());
      qreal asc, desc, leading;
      qreal w = textMetrics(f.family(), _text, f.size(), &asc, &desc, &leading);

// printf("text(%s) asc %f desc %f leading %f  w %f\n", qPrintable(_text), asc, desc, leading, w);
      _lineHeight  = asc + desc;
      _lineSpacing = _lineHeight + leading;
      _baseLine    = asc;

      setbbox(QRectF(0.0, -asc, w, _lineHeight));
#if 0
      if (parent() && _layoutToParentWidth) {
            qreal wi = parent()->width();
            qreal ph = parent()->height();
            qreal x;
            qreal y = pos.y();
            if (align() & ALIGN_HCENTER)
                  x = (wi - w) * .5;
            else if (align() & ALIGN_RIGHT)
                  x = wi - w;
            else
                  x = 0.0;
            if (align() & ALIGN_VCENTER)
                  y = (ph - asc) * .5;
            else if (align() & ALIGN_BOTTOM)
                  y = ph - asc;
            else
                  y = asc;
            setPos(x, y + asc);
            }
#endif
      style().layout(this);      // process alignment
      rypos() += asc;

      if (parent() && _layoutToParentWidth) {
            qreal wi = parent()->width();
            if (align() & ALIGN_HCENTER)
                  rxpos() = (wi - w) * .5;
            else if (align() & ALIGN_RIGHT)
                  rxpos() = wi - w;
            }

      if ((style().align() & ALIGN_VCENTER) && (subtype() == TEXT_TEXTLINE)) {
            // special case: vertically centered text with TextLine needs to
            // take into account the line width
            TextLineSegment* tls = (TextLineSegment*)parent();
            TextLine* tl = (TextLine*)(tls->line());
            qreal textlineLineWidth = point(tl->lineWidth());
            rypos() -= textlineLineWidth * .5;
            }

      if (parent() == 0)
            return;
      if (parent()->type() == SEGMENT) {
            Segment* s = static_cast<Segment*>(parent());
            rypos() += s ? s->measure()->system()->staff(staffIdx())->y() : 0.0;
            }
      }
void ListViewDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
	QStyleOptionViewItemV4 opt = option;
	initStyleOption ( &opt, index );
	painter->save();
	painter->setClipRect ( opt.rect );

	opt.features |= QStyleOptionViewItem::WrapText;
	opt.text = index.data().toString();
	opt.textElideMode = Qt::ElideRight;
	opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter;

	QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();

	//const int iconSize =  style->pixelMetric(QStyle::PM_IconViewIconSize);
	const int iconSize = 48;
	QRect iconbox = opt.rect;
	const int textMargin = style->pixelMetric ( QStyle::PM_FocusFrameHMargin, 0, opt.widget ) + 1;
	QRect textRect = opt.rect;
	QRect textHighlightRect = textRect;
	// clip the decoration on top, remove width padding
	textRect.adjust ( textMargin,iconSize + textMargin + 5,-textMargin,0 );
	
	textHighlightRect.adjust ( 0,iconSize + 5,0,0 );

	// draw background
	{
		QSize textSize = viewItemTextSize ( &opt );
		QPalette::ColorGroup cg;
		QStyleOptionViewItemV4 opt2(opt);
		
		if((opt.widget && opt.widget->isEnabled()) || (opt.state & QStyle::State_Enabled))
		{
			if(! ( opt.state & QStyle::State_Active ))
				cg = QPalette::Inactive;
			else
				cg = QPalette::Normal;
		}
		else
		{
			cg = QPalette::Disabled;
		}
		opt2.palette.setCurrentColorGroup(cg);
		
		// fill in background, if any
		if ( opt.backgroundBrush.style() != Qt::NoBrush )
		{
			QPointF oldBO = painter->brushOrigin();
			painter->setBrushOrigin ( opt.rect.topLeft() );
			painter->fillRect ( opt.rect, opt.backgroundBrush );
			painter->setBrushOrigin ( oldBO );
		}
		
		if ( opt.showDecorationSelected )
		{
			drawSelectionRect(painter,opt2, opt.rect);
			drawFocusRect(painter,opt2, opt.rect);
			//painter->fillRect ( opt.rect, opt.palette.brush ( cg, QPalette::Highlight ) );
		}
		else
		{
			
			//if ( opt.state & QStyle::State_Selected )
			{
				//QRect textRect = subElementRect ( QStyle::SE_ItemViewItemText,  opt, opt.widget );
				//painter->fillRect ( textHighlightRect, opt.palette.brush ( cg, QPalette::Highlight ) );
				drawSelectionRect(painter,opt2, textHighlightRect);
				drawFocusRect(painter,opt2, textHighlightRect);
			}
		}
	}

	// draw the icon
	{
		QIcon::Mode mode = QIcon::Normal;
		if ( ! ( opt.state & QStyle::State_Enabled ) )
			mode = QIcon::Disabled;
		else if ( opt.state & QStyle::State_Selected )
			mode = QIcon::Selected;
		QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off;

		iconbox.setHeight ( iconSize );
		opt.icon.paint ( painter, iconbox, Qt::AlignCenter, mode, state );
	}
	// set the text colors
	QPalette::ColorGroup cg = opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
	if ( cg == QPalette::Normal && ! ( opt.state & QStyle::State_Active ) )
		cg = QPalette::Inactive;
	if ( opt.state & QStyle::State_Selected )
	{
		painter->setPen ( opt.palette.color ( cg, QPalette::HighlightedText ) );
	}
	else
	{
		painter->setPen ( opt.palette.color ( cg, QPalette::Text ) );
	}

	// draw the text
	QTextOption textOption;
	textOption.setWrapMode ( QTextOption::WrapAtWordBoundaryOrAnywhere );
	textOption.setTextDirection ( opt.direction );
	textOption.setAlignment ( QStyle::visualAlignment ( opt.direction, opt.displayAlignment ) );
	QTextLayout textLayout;
	textLayout.setTextOption ( textOption );
	textLayout.setFont ( opt.font );
	textLayout.setText ( opt.text );

	qreal width, height;
	viewItemTextLayout ( textLayout, iconbox.width(), height, width );

	const int lineCount = textLayout.lineCount();

	const QRect layoutRect = QStyle::alignedRect ( opt.direction, opt.displayAlignment, QSize ( iconbox.width(), int ( height ) ), textRect );
	const QPointF position = layoutRect.topLeft();
	for ( int i = 0; i < lineCount; ++i )
	{
		const QTextLine line = textLayout.lineAt ( i );
		line.draw ( painter, position );
	}

	painter->restore();
}
Exemple #24
0
void KoTextShapeContainerModel::proposeMove(KoShape *child, QPointF &move)
{
    Relation *relation = d->children.value(child);
    if (relation == 0 || relation->anchor == 0)
        return;

    QPointF newPosition = child->position() + move;
    QRectF parentShapeRect(QPointF(0, 0), child->parent()->size());
//kDebug(32500) <<"proposeMove:" << move <<" |" << newPosition <<" |" << parentShapeRect;

    if (qAbs(newPosition.x()) < 10) // align left
        relation->anchor->setAlignment(KoTextAnchor::Left);
    else if (qAbs(parentShapeRect.width() - newPosition.x()) < 10.0)
        relation->anchor->setAlignment(KoTextAnchor::Right);
    else if (qAbs(parentShapeRect.width() / 2.0 - newPosition.x()) < 10.0)
        relation->anchor->setAlignment(KoTextAnchor::Center);
    /*else {
        relation->anchor->setAlignment(KoTextAnchor::HorizontalOffset);
        // TODO
        //QPointF offset = relation->anchor->offset();
        //offset.setX(offset.x() + move.x());
        //relation->anchor->setOffset(offset);
    } */

    if (qAbs(newPosition.y()) < 10.0) // TopOfFrame
    {
        kDebug(32500) <<"  TopOfFrame";
        relation->anchor->setAlignment(KoTextAnchor::TopOfFrame);
    } else if (qAbs(parentShapeRect.height() - newPosition.y()) < 10.0) {
        kDebug(32500) <<"  BottomOfFrame";
        relation->anchor->setAlignment(KoTextAnchor::BottomOfFrame); // TODO
    } else { // need layout info..
        QTextBlock block = relation->anchor->document()->findBlock(relation->anchor->positionInDocument());
        QTextLayout *layout = block.layout();
        if (layout->lineCount() > 0) {
            KoTextShapeData *data = dynamic_cast<KoTextShapeData*>(child->parent()->userData());
            Q_ASSERT(data);
            QTextLine tl = layout->lineAt(0);
            qreal y = tl.y() - data->documentOffset() - newPosition.y();
            if (y >= 0 && y < 10) {
                kDebug(32500) <<"  TopOfParagraph" << y <<"";
                relation->anchor->setAlignment(KoTextAnchor::TopOfParagraph);
            } else {
                tl = layout->lineAt(layout->lineCount() - 1);
                y = newPosition.y() - tl.y() - data->documentOffset() - tl.ascent();
                if (y >= 0 && y < 10) {
                    kDebug(32500) <<"  BottomOfParagraph" << y;
                    relation->anchor->setAlignment(KoTextAnchor::BottomOfParagraph); // TODO
                } else {
                    tl = layout->lineForTextPosition(relation->anchor->positionInDocument() - block.position());
                    y = tl.y() - data->documentOffset() - newPosition.y();
                    if (y >= 0 && y < 10) {
                        kDebug(32500) <<"  AboveCurrentLine";
                        relation->anchor->setAlignment(KoTextAnchor::AboveCurrentLine);
                    }
                    //else  do VerticalOffset here as well?
                }
            }
        }
    }

    move.setX(0); // let the text layout move it.
    move.setY(0);
}