void TextContent::setShapeEditing(bool enabled) { if (enabled) { // shape editor on if (!m_shapeEditor->isVisible()) { m_shapeEditor->show(); emit notifyShapeEditing(true); } // begin new shape if (!hasShape()) { // use caching only when drawing shaped [disabled because updates are wrong when cached!] //setCacheMode(enabled ? QGraphicsItem::DeviceCoordinateCache : QGraphicsItem::NoCache); // use new shape setShapePath(m_shapeEditor->shape()); emit notifyHasShape(true); } } else { // shape editor off if (m_shapeEditor->isVisible()) { m_shapeEditor->hide(); emit notifyShapeEditing(false); } } }
void SelectedItem::updateGeometry(int, int) { if (hasShape()) { getShape()->setInnerSize(selectedItem_->width(), selectedItem_->height()); QPointF pos = QPointF( getShape()->contentLeft(), getShape()->contentTop() ); setPos(selectedItem_->mapToScene(0,0) - pos); } }
void TextContent::toXml(QDomElement & contentElement, const QDir & baseDir) const { AbstractContent::toXml(contentElement, baseDir); contentElement.setTagName("text"); // save text properties QDomDocument doc = contentElement.ownerDocument(); QDomElement domElement; QDomText text; // save text (in html) domElement = doc.createElement("html-text"); contentElement.appendChild(domElement); text = doc.createTextNode(m_text->toHtml()); domElement.appendChild(text); // save default font domElement = doc.createElement("default-font"); domElement.setAttribute("font-family", m_text->defaultFont().family()); domElement.setAttribute("font-size", m_text->defaultFont().pointSize()); contentElement.appendChild(domElement); // save shape and control points QDomElement shapeElement = doc.createElement("shape"); shapeElement.setAttribute("enabled", hasShape()); contentElement.appendChild(shapeElement); if (hasShape()) { QList<QPointF> cp = m_shapeEditor->controlPoints(); domElement = doc.createElement("control-points"); shapeElement.appendChild(domElement); domElement.setAttribute("one", QString::number(cp[0].x()) + " " + QString::number(cp[0].y())); domElement.setAttribute("two", QString::number(cp[1].x()) + " " + QString::number(cp[1].y())); domElement.setAttribute("three", QString::number(cp[2].x()) + " " + QString::number(cp[2].y())); domElement.setAttribute("four", QString::number(cp[3].x()) + " " + QString::number(cp[3].y())); } }
void CursorShapeItem::updateGeometry(int, int) { if (hasShape()) { getShape()->setInnerSize(size_.width(), size_.height()); if (useCenter_) { QPointF pos = QPointF( getShape()->contentLeft(), getShape()->contentTop() ); setPos(center_ - pos); } else setPos(topLeft_); } }
vec2 SpriteDef::calculateSizeFromShapeData () const { if (_shapeSizeCalculated) return _cachedShapeSize; if (!hasShape()) { _cachedShapeSize = vec2_zero; _shapeSizeCalculated = true; return _cachedShapeSize; } const vec2 mins = getMins(); const vec2 maxs = getMaxs(); _cachedShapeSize = vec2(maxs.x - mins.x, maxs.y - mins.y); _shapeSizeCalculated = true; return _cachedShapeSize; }
QWidget * TextContent::createPropertyWidget(ContentProperties * __p) { TextProperties * tp = __p ? (TextProperties *)__p : new TextProperties; AbstractContent::createPropertyWidget(tp); // remove for 0.9 ### put this back for 1.0 delete tp->tShakeLess; delete tp->tShakeMore; // properties link new PE_AbstractButton(tp->tEditShape, this, "shapeEditing", tp); tp->tClearShape->setVisible(hasShape()); // link "hasShape" in a custom way connect(this, SIGNAL(notifyHasShape(bool)), tp->tClearShape, SLOT(setVisible(bool))); connect(tp->tClearShape, SIGNAL(clicked()), this, SLOT(clearShape())); return tp; }
void Layout::setInnerSize(int width_, int height_) { if (isEmpty() && !style()->drawShapeWhenEmpty()) setSize(0,0); else { if ( hasShape() ) { getShape()->setOffset(style()->leftMargin(), style()->topMargin()); getShape()->setInnerSize(width_, height_); setWidth(width() + style()->rightMargin()); setHeight(height() + style()->bottomMargin()); } else { setWidth(width_ + style()->leftMargin() + style()->rightMargin()); setHeight(height_ + style()->topMargin() + style()->bottomMargin()); } } }
void ControlFlowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Item::paint(painter, option, widget); int xOffset = 0; int yOffset = 0; if (hasShape()) { xOffset = getShape()->contentLeft(); yOffset = getShape()->contentTop(); } painter->setPen( style()->pin()); painter->translate( xOffset + style()->pin().width()/2.0, yOffset + style()->pin().width()/2.0); for(int i = 0; i < connectors_.size(); ++i) { painter->drawPath( connector(connectors_.at(i), arrowEndings_.at(i)) ); } }
int Layout::yOffset() const { if ( hasShape() ) return getShape()->contentTop(); else return style()->topMargin(); }
int Layout::xOffset() const { if ( hasShape() ) return getShape()->contentLeft(); else return style()->leftMargin(); }
void TextContent::updateTextConstraints() { // 1. actual content stretch double prevXScale = 1.0; double prevYScale = 1.0; /* if (m_textRect.width() > 0 && m_textRect.height() > 0) { QRect cRect = contentRect(); prevXScale = (qreal)cRect.width() / (qreal)m_textRect.width(); prevYScale = (qreal)cRect.height() / (qreal)m_textRect.height(); }*/ // 2. LAYOUT TEXT. find out Block rects and Document rect int minCharSide = 0; m_blockRects.clear(); m_textRect = QRect(0, 0, 0, 0); for (QTextBlock tb = m_text->begin(); tb.isValid(); tb = tb.next()) { if (!tb.isVisible()) continue; // 2.1.A. calc the Block size uniting Fragments bounding rects QRect blockRect(0, 0, 0, 0); for (QTextBlock::iterator tbIt = tb.begin(); !(tbIt.atEnd()); ++tbIt) { QTextFragment frag = tbIt.fragment(); if (!frag.isValid()) continue; QString text = frag.text(); if (text.trimmed().isEmpty()) continue; QFontMetrics metrics(frag.charFormat().font()); if (!minCharSide || metrics.height() > minCharSide) minCharSide = metrics.height(); // TODO: implement superscript / subscript (it's in charFormat's alignment) // it must be implemented in paint too QRect textRect = metrics.boundingRect(text); if (textRect.left() > 9999) continue; if (textRect.top() < blockRect.top()) blockRect.setTop(textRect.top()); if (textRect.bottom() > blockRect.bottom()) blockRect.setBottom(textRect.bottom()); int textWidth = metrics.width(text); blockRect.setWidth(blockRect.width() + textWidth); } // 2.1.B. calc the Block size of blank lines if (tb.begin() == tb.end()) { QFontMetrics metrics(tb.charFormat().font()); int textHeight = metrics.height(); blockRect.setWidth(1); blockRect.setHeight(textHeight); } // 2.2. add the Block's margins QTextBlockFormat tbFormat = tb.blockFormat(); blockRect.adjust(-tbFormat.leftMargin(), -tbFormat.topMargin(), tbFormat.rightMargin(), tbFormat.bottomMargin()); // 2.3. store the original block rect m_blockRects.append(blockRect); // 2.4. enlarge the Document rect (uniting the Block rect) blockRect.translate(0, m_textRect.bottom() - blockRect.top() + 1); if (blockRect.left() < m_textRect.left()) m_textRect.setLeft(blockRect.left()); if (blockRect.right() > m_textRect.right()) m_textRect.setRight(blockRect.right()); if (blockRect.top() < m_textRect.top()) m_textRect.setTop(blockRect.top()); if (blockRect.bottom() > m_textRect.bottom()) m_textRect.setBottom(blockRect.bottom()); } m_textRect.adjust(-m_textMargin, -m_textMargin, m_textMargin, m_textMargin); // 3. use shape-based rendering if (hasShape()) { #if 1 // more precise, but too close to the path m_shapeRect = m_shapePath.boundingRect().toRect(); #else // faster, but less precise (as it uses the controls points to determine // the path rect, instead of the path itself) m_shapeRect = m_shapePath.controlPointRect().toRect(); #endif minCharSide = qBound(10, minCharSide, 500); m_shapeRect.adjust(-minCharSide, -minCharSide, minCharSide, minCharSide); // FIXME: layout, save layouting and calc the exact size! //int w = m_shapeRect.width(); //int h = m_shapeRect.height(); //resizeContents(QRect(-w / 2, -h / 2, w, h)); resizeContents(m_shapeRect); // moveBy(m_shapeRect.left(), m_shapeRect.top()); // m_shapePath.translate(-m_shapeRect.left(), -m_shapeRect.top()); //setPos(m_shapeRect.center()); return; } // 4. resize content keeping stretch int w = (int)(prevXScale * (qreal)m_textRect.width()); int h = (int)(prevYScale * (qreal)m_textRect.height()); resizeContents(QRect(-w / 2, -h / 2, w, h)); }
void TextContent::drawContent(QPainter * painter, const QRect & targetRect, Qt::AspectRatioMode ratio) { Q_UNUSED(ratio) // check whether we're drawing shaped const bool shapedPaint = hasShape() && !m_shapeRect.isEmpty(); QPointF shapeOffset = m_shapeRect.topLeft(); // scale painter for adapting the Text Rect to the Contents Rect QRect sourceRect = shapedPaint ? m_shapeRect : m_textRect; painter->save(); painter->translate(targetRect.topLeft()); if (sourceRect.width() > 0 && sourceRect.height() > 0) { qreal xScale = (qreal)targetRect.width() / (qreal)sourceRect.width(); qreal yScale = (qreal)targetRect.height() / (qreal)sourceRect.height(); if (!qFuzzyCompare(xScale, (qreal)1.0) || !qFuzzyCompare(yScale, (qreal)1.0)) painter->scale(xScale, yScale); } // shape //const bool drawHovering = RenderOpts::HQRendering ? false : isSelected(); if (shapedPaint) painter->translate(-shapeOffset); //if (shapedPaint && drawHovering) // painter->strokePath(m_shapePath, QPen(Qt::red, 0)); // TEMP - for PDF exporting - standard rich text document drawing if (RenderOpts::PDFExporting) { if (shapedPaint) QMessageBox::information(0, tr("PDF Export Warning"), tr("Shaped text could not be exported in PDF"), QMessageBox::Ok); QAbstractTextDocumentLayout::PaintContext pCtx; m_text->documentLayout()->draw(painter, pCtx); } else { // manual drawing QPointF blockPos = shapedPaint ? QPointF(0, 0) : -m_textRect.topLeft(); // 1. for each Text Block int blockRectIdx = 0; for (QTextBlock tb = m_text->begin(); tb.isValid(); tb = tb.next()) { if (!tb.isVisible() || blockRectIdx > m_blockRects.size()) continue; // 1.1. compute text insertion position const QRect & blockRect = m_blockRects[blockRectIdx++]; QPointF iPos = shapedPaint ? blockPos : blockPos - blockRect.topLeft(); blockPos += QPointF(0, blockRect.height()); qreal curLen = 8; // 1.2. iterate over text fragments for (QTextBlock::iterator tbIt = tb.begin(); !(tbIt.atEnd()); ++tbIt) { QTextFragment frag = tbIt.fragment(); if (!frag.isValid()) continue; // 1.2.1. setup painter and metrics for text fragment QTextCharFormat format = frag.charFormat(); QFont font = format.font(); painter->setFont(font); painter->setPen(format.foreground().color()); painter->setBrush(Qt::NoBrush); QFontMetrics metrics(font); // 1.2.2. draw each character QString text = frag.text(); foreach (const QChar & textChar, text) { const qreal charWidth = metrics.width(textChar); if (shapedPaint) { // find point on shape and angle qreal t = m_shapePath.percentAtLength(curLen); QPointF pt = m_shapePath.pointAtPercent(t); qreal angle = -m_shapePath.angleAtPercent(t); if (m_shakeRadius > 0) pt += QPointF(1 + (qrand() % m_shakeRadius) - m_shakeRadius/2, 1 + (qrand() % (2*m_shakeRadius)) - m_shakeRadius); // draw rotated letter painter->save(); painter->translate(pt); painter->rotate(angle); painter->drawText(iPos, textChar); painter->restore(); curLen += charWidth; } else { painter->drawText(iPos, textChar); iPos += QPointF(charWidth, 0); } } } } } painter->restore(); }
void PanelBorderLayout::updateGeometry(int, int) { //TODO: Find a generic way of doing this and consider performance //Set Styles if (top_) top_->setStyle(&style()->topStyle()); if (left_) left_->setStyle(&style()->leftStyle()); if (right_) right_->setStyle(&style()->rightStyle()); if (bottom_) bottom_->setStyle(&style()->bottomStyle()); // Get content size int contentWidth = content_ ? content_->width() : 0; int contentHeight = content_ ? content_->height() : 0; // Compute middle sizes int middleWidth = contentWidth + style()->leftInnerMargin() + style()->rightInnerMargin(); if ( left_ && !style()->isLeftProtrusionFixed()) middleWidth += left_->width() / 2; if ( right_ ) middleWidth += right_->width() / 2; if (style()->isLeftProtrusionFixed()) { int extra = (left_ ? left_->width() : 0) - style()->leftProtrusion(); if (extra > 0) middleWidth += extra; } int maxMiddleWidth = middleWidth; if ( top_ && top_->width() > maxMiddleWidth ) maxMiddleWidth = top_->width(); if ( bottom_ && bottom_->width() > maxMiddleWidth ) maxMiddleWidth = bottom_->width(); if ( left_ && left_->height() > contentHeight ) contentHeight = left_->height(); if ( right_ && right_->height() > contentHeight ) contentHeight = right_->height(); //Adjust the size of the content if necessary if (content_ && content_->sizeDependsOnParent()) content_->changeGeometry(contentWidth + (maxMiddleWidth - middleWidth), contentHeight); //Adjust panels and/or the inner size if ( maxMiddleWidth > middleWidth ) contentWidth += maxMiddleWidth - middleWidth; if ( top_ && maxMiddleWidth > top_->width() ) top_->changeGeometry(maxMiddleWidth, 0); if ( bottom_ && maxMiddleWidth > bottom_->width() ) bottom_->changeGeometry(maxMiddleWidth, 0); if ( left_ && contentHeight > left_->height() ) left_->changeGeometry(0, contentHeight); if ( right_ && contentHeight > right_->height() ) right_->changeGeometry(0, contentHeight); // Compute outter sizes int outterWidth = contentWidth + style()->leftInnerMargin() + style()->rightInnerMargin(); int extraLeft = 0; if ( style()->isLeftProtrusionFixed() && style()->leftProtrusion() > 0) extraLeft = style()->leftProtrusion(); if ( left_ && left_->width() > extraLeft) extraLeft = left_->width(); outterWidth += extraLeft; if ( right_ ) outterWidth += right_->width(); int outterHeight = contentHeight + style()->topInnerMargin() + style()->bottomInnerMargin(); if ( top_ ) outterHeight += top_->height(); if ( bottom_ ) outterHeight += bottom_->height(); if (hasShape() && style()->shapeOnlyOnContent()) { // If the shape must cover only the content manually set the way it should look. // Set shape position int x = style()->leftMargin(); if (style()->isLeftProtrusionFixed()) { if (style()->leftProtrusion() > 0) x += style()->leftProtrusion(); } else x += left_ ? left_->width() / 2 : 0; int y = style()->topMargin() + (top_ ? top_->height() / 2 : 0); getShape()->setOffset(x, y); // Set shape size int middleHeight = outterHeight - y - (bottom_? (bottom_->height()/2) :0); getShape()->setOutterSize(maxMiddleWidth, middleHeight); // Set Layout size setWidth(outterWidth + style()->leftMargin() + style()->rightMargin()); setHeight(outterHeight + style()->topMargin() + style()->bottomMargin()); } else setInnerSize(outterWidth, outterHeight); // Use the default method when the shape must cover the entire layout. // Determine the right offset to use. int xOffset = style()->leftMargin(); int yOffset = style()->rightMargin(); if (hasShape() && !style()->shapeOnlyOnContent()) { xOffset = getShape()->contentLeft(); yOffset = getShape()->contentTop(); } // Set positions int xLeft = xOffset; int xTop = xLeft; int xContent; int xRight; if (style()->isLeftProtrusionFixed()) { if ( style()->leftProtrusion() < 0) xLeft -= style()->leftProtrusion(); else xTop += style()->leftProtrusion(); xContent = xLeft + (left_ ? left_->width() : 0) + style()->leftInnerMargin(); if (xContent < xOffset + style()->leftProtrusion() + style()->leftInnerMargin()) xContent = xOffset + style()->leftProtrusion() + style()->leftInnerMargin(); } else { xTop = xLeft + (left_ ? left_->width() / 2 : 0); xContent = xLeft + (left_ ? left_->width() : 0) + style()->leftInnerMargin(); } xRight = xContent + (content_ ? content_->width() : 0) + style()->rightInnerMargin(); int yTop = yOffset; int yContent = yTop + (top_ ? top_->height() : 0) + style()->topInnerMargin(); int yBottom = yContent + contentHeight + style()->bottomInnerMargin(); if ( top_ ) top_->setPos(xTop, yTop); if ( left_ ) left_->setPos(xLeft, yContent); if ( content_ ) content_->setPos(xContent, yContent); if ( right_ ) right_->setPos(xRight, yContent); if ( bottom_ ) bottom_->setPos(xTop, yBottom); }