Exemple #1
0
void CodeEditor::paintEvent(QPaintEvent* event)
{
    QPlainTextEdit::paintEvent(event);

    QPainter painter(viewport());
    painter.setPen(Qt::darkGray);

    QTextBlock block = firstVisibleBlock();

    QRectF rect;

    do {

        if (!block.isVisible())
            continue;

        rect = blockBoundingGeometry(block).translated(contentOffset());

        QTextLine line = block.layout()->lineAt(0);

        if (config->whitespaces) {
            QString txt = block.text();

            for (int i = 0; i < txt.length(); i++) {
                // rect.x() <- учитывая горизонтальный скролинг
                QPoint point(rect.x() + line.cursorToX(i), rect.y() + line.ascent());

                if (txt[i] == ' ')
                    painter.drawText(point, QChar(0x00b7));
                else if (txt[i] == '\t')
                    painter.drawText(point, QChar(0x21b9));
            }
        }

        int state = block.userState();

        if (!(state & Error) && state & Folded) {
            QRect collapseRect(rect.x() + line.rect().x() + line.naturalTextWidth() + FONTWIDTH * 2,
                               rect.y() + 2, FONTWIDTH * 6, line.height() - 4);

            painter.drawText(collapseRect, Qt::AlignCenter, state & Comment ? "...;" : "...)");
            painter.drawRoundedRect(collapseRect, 4, 6);
        }

    } while ((block = block.next()).isValid() && rect.y() < viewport()->height());
}
Exemple #2
0
void QSvgText::draw(QPainter *p, QSvgExtraStates &states)
{
    applyStyle(p, states);
    qreal oldOpacity = p->opacity();
    p->setOpacity(oldOpacity * states.fillOpacity);

    // Force the font to have a size of 100 pixels to avoid truncation problems
    // when the font is very small.
    qreal scale = 100.0 / p->font().pointSizeF();
    Qt::Alignment alignment = states.textAnchor;

    QTransform oldTransform = p->worldTransform();
    p->scale(1 / scale, 1 / scale);

    qreal y = 0;
    bool initial = true;
    qreal px = m_coord.x() * scale;
    qreal py = m_coord.y() * scale;
    QSizeF scaledSize = m_size * scale;

    if (m_type == TEXTAREA) {
        if (alignment == Qt::AlignHCenter)
            px += scaledSize.width() / 2;
        else if (alignment == Qt::AlignRight)
            px += scaledSize.width();
    }

    QRectF bounds;
    if (m_size.height() != 0)
        bounds = QRectF(0, py, 1, scaledSize.height()); // x and width are not used.

    bool appendSpace = false;
    QVector<QString> paragraphs;
    QStack<QTextCharFormat> formats;
    QVector<QList<QTextLayout::FormatRange> > formatRanges;
    paragraphs.push_back(QString());
    formatRanges.push_back(QList<QTextLayout::FormatRange>());

    for (int i = 0; i < m_tspans.size(); ++i) {
        if (m_tspans[i] == LINEBREAK) {
            if (m_type == TEXTAREA) {
                if (paragraphs.back().isEmpty()) {
                    QFont font = p->font();
                    font.setPixelSize(font.pointSizeF() * scale);

                    QTextLayout::FormatRange range;
                    range.start = 0;
                    range.length = 1;
                    range.format.setFont(font);
                    formatRanges.back().append(range);

                    paragraphs.back().append(QLatin1Char(' '));;
                }
                appendSpace = false;
                paragraphs.push_back(QString());
                formatRanges.push_back(QList<QTextLayout::FormatRange>());
            }
        } else {
            WhitespaceMode mode = m_tspans[i]->whitespaceMode();
            m_tspans[i]->applyStyle(p, states);

            QFont font = p->font();
            font.setPixelSize(font.pointSizeF() * scale);

            QString newText(m_tspans[i]->text());
            newText.replace(QLatin1Char('\t'), QLatin1Char(' '));
            newText.replace(QLatin1Char('\n'), QLatin1Char(' '));

            bool prependSpace = !appendSpace && !m_tspans[i]->isTspan() && (mode == Default) && !paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' '));
            if (appendSpace || prependSpace)
                paragraphs.back().append(QLatin1Char(' '));

            bool appendSpaceNext = (!m_tspans[i]->isTspan() && (mode == Default) && newText.endsWith(QLatin1Char(' ')));

            if (mode == Default) {
                newText = newText.simplified();
                if (newText.isEmpty())
                    appendSpaceNext = false;
            }

            QTextLayout::FormatRange range;
            range.start = paragraphs.back().length();
            range.length = newText.length();
            range.format.setFont(font);
            range.format.setTextOutline(p->pen());
            range.format.setForeground(p->brush());

            if (appendSpace) {
                Q_ASSERT(!formatRanges.back().isEmpty());
                ++formatRanges.back().back().length;
            } else if (prependSpace) {
                --range.start;
                ++range.length;
            }
            formatRanges.back().append(range);

            appendSpace = appendSpaceNext;
            paragraphs.back() += newText;

            m_tspans[i]->revertStyle(p, states);
        }
    }

    if (states.svgFont) {
        // SVG fonts not fully supported...
        QString text = paragraphs.front();
        for (int i = 1; i < paragraphs.size(); ++i) {
            text.append(QLatin1Char('\n'));
            text.append(paragraphs[i]);
        }
        states.svgFont->draw(p, m_coord * scale, text, p->font().pointSizeF() * scale, states.textAnchor);
    } else {
        for (int i = 0; i < paragraphs.size(); ++i) {
            QTextLayout tl(paragraphs[i]);
            QTextOption op = tl.textOption();
            op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
            tl.setTextOption(op);
            tl.setAdditionalFormats(formatRanges[i]);
            tl.beginLayout();

            forever {
                QTextLine line = tl.createLine();
                if (!line.isValid())
                    break;
                if (m_size.width() != 0)
                    line.setLineWidth(scaledSize.width());
            }
            tl.endLayout();

            bool endOfBoundsReached = false;
            for (int i = 0; i < tl.lineCount(); ++i) {
                QTextLine line = tl.lineAt(i);

                qreal x = 0;
                if (alignment == Qt::AlignHCenter)
                    x -= 0.5 * line.naturalTextWidth();
                else if (alignment == Qt::AlignRight)
                    x -= line.naturalTextWidth();

                if (initial && m_type == TEXT)
                    y -= line.ascent();
                initial = false;

                line.setPosition(QPointF(x, y));

                // Check if the current line fits into the bounding rectangle.
                if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width())
                    || (m_size.height() != 0 && y + line.height() > scaledSize.height())) {
                    // I need to set the bounds height to 'y-epsilon' to avoid drawing the current
                    // line. Since the font is scaled to 100 units, 1 should be a safe epsilon.
                    bounds.setHeight(y - 1);
                    endOfBoundsReached = true;
                    break;
                }

                y += 1.1 * line.height();
            }
            tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds);

            if (endOfBoundsReached)
                break;
        }
    }

    p->setWorldTransform(oldTransform, false);
    p->setOpacity(oldOpacity);
    revertStyle(p, states);
}
// FIXME: we need to figure out a way to derive from Fm::FolderItemDelegate to avoid code duplication.
void DesktopItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
  Q_ASSERT(index.isValid());
  QStyleOptionViewItemV4 opt = option;
  initStyleOption(&opt, index);

  painter->save();
  painter->setClipRect(option.rect);

  opt.decorationAlignment = Qt::AlignHCenter | Qt::AlignTop;
  opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter;

  // draw the icon
  QIcon::Mode iconMode;
  if(opt.state & QStyle::State_Enabled) {
    if(opt.state & QStyle::State_Selected)
      iconMode = QIcon::Selected;
    else {
      iconMode = QIcon::Normal;
    }
  }
  else
    iconMode = QIcon::Disabled;
  QPoint iconPos(opt.rect.x() + (opt.rect.width() - opt.decorationSize.width()) / 2, opt.rect.y());
  QPixmap pixmap = opt.icon.pixmap(opt.decorationSize, iconMode);
  painter->drawPixmap(iconPos, pixmap);

  // draw some emblems for the item if needed
  // we only support symlink emblem at the moment
  FmFileInfo* file = static_cast<FmFileInfo*>(index.data(Fm::FolderModel::FileInfoRole).value<void*>());
  if(file) {
    if(fm_file_info_is_symlink(file)) {
      painter->drawPixmap(iconPos, symlinkIcon_.pixmap(opt.decorationSize / 2, iconMode));
    }
  }

  // draw text
  QRectF textRect(opt.rect.x(), opt.rect.y() + opt.decorationSize.height(), opt.rect.width(), opt.rect.height() - opt.decorationSize.height());
  QTextLayout layout(opt.text, opt.font);

  QTextOption textOption;
  textOption.setAlignment(opt.displayAlignment);
  textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
  textOption.setTextDirection(opt.direction);
  layout.setTextOption(textOption);
  qreal height = 0;
  qreal width = 0;
  int visibleLines = 0;
  layout.beginLayout();
  QString elidedText;

  for(;;) {
    QTextLine line = layout.createLine();
    if(!line.isValid())
      break;
    line.setLineWidth(textRect.width());
    height += opt.fontMetrics.leading();
    line.setPosition(QPointF(0, height));
    if((height + line.height() + textRect.y()) > textRect.bottom()) {
      // if part of this line falls outside the textRect, ignore it and quit.
      QTextLine lastLine = layout.lineAt(visibleLines - 1);
      elidedText = opt.text.mid(lastLine.textStart());
      elidedText = opt.fontMetrics.elidedText(elidedText, opt.textElideMode, textRect.width());
      break;
    }
    height += line.height();
    width = qMax(width, line.naturalTextWidth());
    ++ visibleLines;
  }
  layout.endLayout();
  QRectF boundRect = layout.boundingRect();
  boundRect.setWidth(width);
  boundRect.moveTo(textRect.x() + (textRect.width() - width)/2, textRect.y());
  if((opt.state & QStyle::State_Selected) && opt.widget) {
    QPalette palette = opt.widget->palette();
    // qDebug("w: %f, h:%f, m:%f", boundRect.width(), boundRect.height(), layout.minimumWidth());
    painter->fillRect(boundRect, palette.highlight());
  }
  else { // only draw shadow for non-selected items
    // draw shadow, FIXME: is it possible to use QGraphicsDropShadowEffect here?
    QPen prevPen = painter->pen();
    painter->setPen(QPen(shadowColor_));
    for(int i = 0; i < visibleLines; ++i) {
      QTextLine line = layout.lineAt(i);
      if(i == (visibleLines - 1) && !elidedText.isEmpty()) { // the last line, draw elided text
        QPointF pos(textRect.x() + line.position().x() + 1, textRect.y() + line.y() + line.ascent() + 1);
        painter->drawText(pos, elidedText);
      }
      else {
        line.draw(painter, textRect.topLeft() + QPointF(1, 1));
      }
    }
    painter->setPen(prevPen);
  }

  // draw text
  for(int i = 0; i < visibleLines; ++i) {
    QTextLine line = layout.lineAt(i);
    if(i == (visibleLines - 1) && !elidedText.isEmpty()) { // the last line, draw elided text
      QPointF pos(textRect.x() + line.position().x(), textRect.y() + line.y() + line.ascent());
      painter->drawText(pos, elidedText);
    }
    else {
      line.draw(painter, textRect.topLeft());
    }
  }

  if(opt.state & QStyle::State_HasFocus) {
    // FIXME: draw focus rect
  }
  painter->restore();
}
// if painter is nullptr, the method calculate the bounding rectangle of the text and save it to textRect
void FolderItemDelegate::drawText(QPainter* painter, QStyleOptionViewItemV4& opt, QRectF& textRect) const {
  QTextLayout layout(opt.text, opt.font);
  QTextOption textOption;
  textOption.setAlignment(opt.displayAlignment);
  textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
  textOption.setTextDirection(opt.direction);
  layout.setTextOption(textOption);
  qreal height = 0;
  qreal width = 0;
  int visibleLines = 0;
  layout.beginLayout();
  QString elidedText;
  for(;;) {
    QTextLine line = layout.createLine();
    if(!line.isValid())
      break;
    line.setLineWidth(textRect.width());
    height += opt.fontMetrics.leading();
    line.setPosition(QPointF(0, height));
    if((height + line.height() + textRect.y()) > textRect.bottom()) {
      // if part of this line falls outside the textRect, ignore it and quit.
      QTextLine lastLine = layout.lineAt(visibleLines - 1);
      elidedText = opt.text.mid(lastLine.textStart());
      elidedText = opt.fontMetrics.elidedText(elidedText, opt.textElideMode, textRect.width());
      if(visibleLines == 1) // this is the only visible line
        width = textRect.width();
      break;
    }
    height += line.height();
    width = qMax(width, line.naturalTextWidth());
    ++ visibleLines;
  }
  layout.endLayout();

  // draw background for selected item
  QRectF boundRect = layout.boundingRect();
  //qDebug() << "bound rect: " << boundRect << "width: " << width;
  boundRect.setWidth(width);
  boundRect.moveTo(textRect.x() + (textRect.width() - width)/2, textRect.y());

  if(!painter) { // no painter, calculate the bounding rect only
    textRect = boundRect;
    return;
  }

  QPalette::ColorGroup cg = opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
  if(opt.state & QStyle::State_Selected) {
    painter->fillRect(boundRect, opt.palette.highlight());
    painter->setPen(opt.palette.color(cg, QPalette::HighlightedText));
  }
  else
    painter->setPen(opt.palette.color(cg, QPalette::Text));

  // draw text
  for(int i = 0; i < visibleLines; ++i) {
    QTextLine line = layout.lineAt(i);
    if(i == (visibleLines - 1) && !elidedText.isEmpty()) { // the last line, draw elided text
      QPointF pos(textRect.x() + line.position().x(), textRect.y() + line.y() + line.ascent());
      painter->drawText(pos, elidedText);
    }
    else {
      line.draw(painter, textRect.topLeft());
    }
  }

  if(opt.state & QStyle::State_HasFocus) {
    // draw focus rect
    QStyleOptionFocusRect o;
    o.QStyleOption::operator=(opt);
    o.rect = boundRect.toRect(); // subElementRect(SE_ItemViewItemFocusRect, vopt, widget);
    o.state |= QStyle::State_KeyboardFocusChange;
    o.state |= QStyle::State_Item;
    QPalette::ColorGroup cg = (opt.state & QStyle::State_Enabled)
                  ? QPalette::Normal : QPalette::Disabled;
    o.backgroundColor = opt.palette.color(cg, (opt.state & QStyle::State_Selected)
                                  ? QPalette::Highlight : QPalette::Window);
    if (const QWidget* widget = opt.widget) {
      QStyle* style = widget->style() ? widget->style() : qApp->style();
      style->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter, widget);
    }
  }
}
Exemple #5
0
void QSvgText::draw(QPainter *p, QSvgExtraStates &states)
{
    applyStyle(p, states);

    QSvgFontStyle *fontStyle = static_cast<QSvgFontStyle*>(
        styleProperty(QSvgStyleProperty::FONT));
    if (fontStyle && fontStyle->svgFont()) {
        // SVG fonts not fully supported...
        QString text = m_paragraphs.front();
        for (int i = 1; i < m_paragraphs.size(); ++i) {
            text.append(QLatin1Char('\n'));
            text.append(m_paragraphs[i]);
        }
        fontStyle->svgFont()->draw(p, m_coord, text, fontStyle->pointSize(), m_textAlignment);
        revertStyle(p, states);
        return;
    }

    // Scale the font to its correct size.
    QTransform oldTransform = p->worldTransform();
    p->scale(1 / m_scale, 1 / m_scale);

    qreal y = 0;
    bool initial = true;
    qreal px = m_coord.x() * m_scale;
    qreal py = m_coord.y() * m_scale;
    QSizeF scaledSize = m_size * m_scale;

    if (m_type == TEXTAREA) {
        if (m_textAlignment == Qt::AlignHCenter)
            px += scaledSize.width() / 2;
        else if (m_textAlignment == Qt::AlignRight)
            px += scaledSize.width();
    }

    QRectF bounds;
    if (m_size.height() != 0)
        bounds = QRectF(0, 0, 1, scaledSize.height());

    for (int i = 0; i < m_paragraphs.size(); ++i) {
        QTextLayout tl(m_paragraphs[i]);
        QTextOption op = tl.textOption();
        op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
        tl.setTextOption(op);
        tl.setAdditionalFormats(m_formatRanges[i]);
        tl.beginLayout();
        forever {
            QTextLine line = tl.createLine();
            if (!line.isValid())
                break;

            if (m_size.width() != 0)
                line.setLineWidth(scaledSize.width());
        }
        tl.endLayout();

        bool endOfBoundsReached = false;
        for (int i = 0; i < tl.lineCount(); ++i) {
            QTextLine line = tl.lineAt(i);

            qreal x = 0;
            if (m_textAlignment == Qt::AlignHCenter)
                x -= line.naturalTextWidth() / 2;
            else if (m_textAlignment == Qt::AlignRight)
                x -= line.naturalTextWidth();

            if (initial && m_type == TEXT)
                y -= line.ascent();
            initial = false;

            line.setPosition(QPointF(x, y));
            if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width())
                || (m_size.height() != 0 && y + line.height() > scaledSize.height())) {
                bounds.setHeight(y);
                endOfBoundsReached = true;
                break;
            }

            y += 1.1 * line.height();
        }
        tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds);

        if (endOfBoundsReached)
            break;
    }

    p->setWorldTransform(oldTransform, false);
    revertStyle(p, states);
}
Exemple #6
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);
}