QSizeF AdjustColumnRowManipulator::textSize(const QString& text, const Style& style) const { QSizeF size; DummyWidget dummyWiget; const QFontMetricsF fontMetrics(style.font(), &dummyWiget); // Set size to correct values according to // if the text is horizontal, vertical or rotated. if (!style.verticalText() && !style.angle()) { // Horizontal text. size = fontMetrics.size(0, text); double offsetFont = 0.0; if ((style.valign() == Style::Bottom) && style.underline()) offsetFont = fontMetrics.underlinePos() + 1; size.setHeight((fontMetrics.ascent() + fontMetrics.descent() + offsetFont) *(text.count('\n') + 1)); } else if (style.angle() != 0) { // Rotated text. const double height = fontMetrics.ascent() + fontMetrics.descent(); const double width = fontMetrics.width(text); size.setHeight(height * ::cos(style.angle() * M_PI / 180) + qAbs(width * ::sin(style.angle() * M_PI / 180))); size.setWidth(qAbs(height * ::sin(style.angle() * M_PI / 180)) + width * ::cos(style.angle() * M_PI / 180)); } else { // Vertical text. qreal width = 0.0; for (int i = 0; i < text.length(); i++) width = qMax(width, fontMetrics.width(text.at(i))); size.setWidth(width); size.setHeight((fontMetrics.ascent() + fontMetrics.descent()) * text.length()); } return size; }
void QgsDecorationTitle::render( const QgsMapSettings &mapSettings, QgsRenderContext &context ) { Q_UNUSED( mapSettings ) if ( !enabled() ) return; context.painter()->save(); context.painter()->setRenderHint( QPainter::Antialiasing, true ); QString displayString = QgsExpression::replaceExpressionText( mLabelText, &context.expressionContext() ); QStringList displayStringList = displayString.split( '\n' ); QFontMetricsF fm( mTextFormat.scaledFont( context ) ); QFontMetricsF textMetrics = QgsTextRenderer::fontMetrics( context, mTextFormat ); double textDescent = textMetrics.descent(); double textWidth = QgsTextRenderer::textWidth( context, mTextFormat, displayStringList, &fm ); double textHeight = QgsTextRenderer::textHeight( context, mTextFormat, displayStringList, QgsTextRenderer::Point, &fm ); QPaintDevice *device = context.painter()->device(); int deviceHeight = device->height() / device->devicePixelRatioF(); int deviceWidth = device->width() / device->devicePixelRatioF(); float xOffset( 0 ), yOffset( 0 ); // Set margin according to selected units switch ( mMarginUnit ) { case QgsUnitTypes::RenderMillimeters: { int pixelsInchX = context.painter()->device()->logicalDpiX();
void TextObject::prepareLineInfos() const { const TextSymbol* text_symbol = reinterpret_cast<const TextSymbol*>(symbol); double scaling = text_symbol->calculateInternalScaling(); QFontMetricsF metrics = text_symbol->getFontMetrics(); double line_spacing = text_symbol->getLineSpacing() * metrics.lineSpacing(); double paragraph_spacing = scaling * text_symbol->getParagraphSpacing() + (text_symbol->hasLineBelow() ? (scaling * (text_symbol->getLineBelowDistance() + text_symbol->getLineBelowWidth())) : 0); double ascent = metrics.ascent(); bool word_wrap = ! hasSingleAnchor(); double box_width = word_wrap ? (scaling * getBoxWidth()) : 0.0; double box_height = word_wrap ? (scaling * getBoxHeight()) : 0.0; int text_end = text.length(); const QLatin1Char line_break('\n'); const QLatin1Char part_break('\t'); const QLatin1Char word_break(' '); line_infos.clear(); // Initialize offsets double line_x = 0.0; if (h_align == TextObject::AlignLeft) line_x -= 0.5 * box_width; else if (h_align == TextObject::AlignRight) line_x += 0.5 * box_width; double line_y = 0.0; if (v_align == TextObject::AlignTop || v_align == TextObject::AlignBaseline) line_y += -0.5 * box_height; if (v_align != TextObject::AlignBaseline) line_y += ascent; // Determine lines and parts //double next_line_x_offset = 0; // to keep indentation after word wrap in a line with tabs int num_paragraphs = 0; int line_num = 0; int line_start = 0; while (line_start <= text_end) { // Initialize input line double line_width = 0.0; int line_end = text.indexOf(line_break, line_start); if (line_end == -1) line_end = text_end; bool paragraph_end = true; std::vector<TextObjectPartInfo> part_infos; int part_start = line_start; double part_x = line_x; while (part_start <= line_end) { // Initialize part (sequence of letters terminated by tab or line break) int part_end = text.indexOf(part_break, part_start); if (part_end == -1) part_end = line_end; else if (part_end > line_end) part_end = line_end; if (part_start > 0 && text[part_start - 1] == part_break) part_x = line_x + text_symbol->getNextTab(part_x - line_x); QString part = text.mid(part_start, part_end - part_start); double part_width = metrics.boundingRect(part).width(); if (word_wrap) { // shrink overflowing part to maximum possible size while (part_x + part_width - line_x > box_width) { // find latest possible break int new_part_end = text.lastIndexOf(word_break, part_end - 1); if (new_part_end <= part_start) { // part won't fit if (part_start > line_start) { // don't put another part on this line part_end = part_start - 1; paragraph_end = false; } break; } paragraph_end = false; // Shrink the part and the line part_end = new_part_end; part = text.mid(part_start, part_end - part_start); part_width = metrics.width(part); line_end = part_end; } } if (part_end < part_start) break; // Add the current part part_infos.push_back( { part, part_start, part_end, part_x, metrics.width(part), metrics } ); // Advance to next part position part_start = part_end + 1; part_x += part_width; } TextObjectPartInfo& last_part_info = part_infos.back(); line_end = last_part_info.end_index; line_width = last_part_info.part_x + last_part_info.width - line_x; // Jump over whitespace after the end of the line and check if it contains a newline character to determine if it is a paragraph end int next_line_start = line_end + 1; /*while (next_line_start < text.size() && (text[next_line_start] == line_break || text[next_line_start] == part_break || text[next_line_start] == word_break)) { if (text[next_line_start - 1] == line_break) { paragraph_end = true; break; } ++next_line_start; }*/ line_infos.push_back( { line_start, line_end, paragraph_end, line_x, line_y, line_width, metrics.ascent(), metrics.descent(), part_infos } ); // Advance to next line line_y += line_spacing; if (paragraph_end) { line_y += paragraph_spacing; num_paragraphs++; } line_num++; line_start = next_line_start; } // Update the line and part offset for every other alignment than top-left or baseline-left double delta_y = 0.0; if (v_align == TextObject::AlignBottom || v_align == TextObject::AlignVCenter) { int num_lines = getNumLines(); double height = ascent + (num_lines - 1) * line_spacing + (num_paragraphs - 1) * paragraph_spacing; if (v_align == TextObject::AlignVCenter) delta_y = -0.5 * height; else if (v_align == TextObject::AlignBottom) delta_y = -height + 0.5 * box_height; } if (delta_y != 0.0 || h_align != TextObject::AlignLeft) { int num_lines = getNumLines(); for (int i = 0; i < num_lines; i++) { TextObjectLineInfo* line_info = &line_infos[i]; double delta_x = 0.0; if (h_align == TextObject::AlignHCenter) delta_x = -0.5 * line_info->width; else if (h_align == TextObject::AlignRight) delta_x -= line_info->width; line_info->line_x += delta_x; line_info->line_y += delta_y; int num_parts = line_info->part_infos.size(); for (int j = 0; j < num_parts; j++) { line_info->part_infos.at(j).part_x += delta_x; } } } }