// shape functions QRectF Node::outline_rect() const { QFontMetricsF metrics = qApp->fontMetrics(); QRectF outline_rect = metrics.boundingRect(text); outline_rect.adjust(-iWidthPadding, -iHeightPadding, iWidthPadding, iHeightPadding); outline_rect.translate(-outline_rect.center()); return outline_rect; }
QRectF QNodeItem::outlineRect() const { const int Padding = 6; QFontMetricsF metrics = qApp->font(); QRectF rect = metrics.boundingRect(text); rect.adjust(-Padding, -Padding, +Padding, +Padding); rect.translate(-rect.center()); return rect; }
QRectF usecaseclass::outlineRect() const { const int Padding = 60; QFontMetricsF metrics = qApp->font(); QRectF rect = metrics.boundingRect(myText); rect.adjust(-Padding, -Padding, +Padding, +Padding); rect.translate(-rect.center()); return rect; }
void tst_QQuickTextMetrics::functionsWithArguments() { QFETCH(QString, text); QFETCH(Qt::TextElideMode, mode); QFETCH(qreal, width); QQuickTextMetrics metrics; // Ensures that the values actually change. metrics.setText(text + "extra"); metrics.setElideWidth(width + 1); switch (mode) { case Qt::ElideNone: metrics.setElide(Qt::ElideMiddle); break; case Qt::ElideLeft: metrics.setElide(Qt::ElideRight); break; case Qt::ElideMiddle: metrics.setElide(Qt::ElideNone); break; case Qt::ElideRight: metrics.setElide(Qt::ElideLeft); break; } QSignalSpy textSpy(&metrics, SIGNAL(textChanged())); QSignalSpy metricsSpy(&metrics, SIGNAL(metricsChanged())); metrics.setText(text); QCOMPARE(textSpy.count(), 1); QCOMPARE(metricsSpy.count(), 1); QSignalSpy elideSpy(&metrics, SIGNAL(elideChanged())); metrics.setElide(mode); QCOMPARE(elideSpy.count(), 1); QCOMPARE(metricsSpy.count(), 2); QSignalSpy elideWidthSpy(&metrics, SIGNAL(elideWidthChanged())); metrics.setElideWidth(width); QCOMPARE(elideWidthSpy.count(), 1); QCOMPARE(metricsSpy.count(), 3); QFontMetricsF expected = QFontMetricsF(QFont()); QCOMPARE(metrics.elidedText(), expected.elidedText(text, mode, width, 0)); QCOMPARE(metrics.advanceWidth(), expected.width(text)); QCOMPARE(metrics.boundingRect(), expected.boundingRect(text)); QCOMPARE(metrics.width(), expected.boundingRect(text).width()); QCOMPARE(metrics.height(), expected.boundingRect(text).height()); QCOMPARE(metrics.tightBoundingRect(), expected.tightBoundingRect(text)); }
void VerticalViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { QRectF rect = boundingRect(); QString symboldir = QString("%1/images").arg(ConfigParser::getInstance().envMapDir()); QDir dir(symboldir); if (!dir.exists()) return; QPen pen(Qt::black); painter->setPen(pen); QFont font(qApp->font()); font.setPointSize(9); font.setBold(true); painter->setFont(font); QFontMetricsF metrics = qApp->font(); QRectF fontRect; int maxData = 0; if (mode == 0) { maxData = getMaxAlt() * 25; // feet }else { maxData = getMaxAlt(); } qDebug() << maxData; if (mode == 0) { // Altitude // 고도의 max 값을 구한다. if (maxData < 6) { painter->drawText(QPoint(20, 20), "Altitude"); painter->drawText(QPoint(20, 40), " (Feet)"); painter->drawText(QPoint(20, 100), " 6"); painter->drawText(QPoint(20, 190), " 5"); painter->drawText(QPoint(20, 280), " 4"); painter->drawText(QPoint(20, 370), " 3"); painter->drawText(QPoint(20, 460), " 2"); painter->drawText(QPoint(20, 550), " 1"); }else { int size = (int)(maxData / 6); QString t1 = QString("%1").arg(QString("%1").arg(size), -8, ' '); QString t2 = QString("%1").arg(QString("%1").arg(size * 2), -8, ' '); QString t3 = QString("%1").arg(QString("%1").arg(size * 3), -8, ' '); QString t4 = QString("%1").arg(QString("%1").arg(size * 4), -8, ' '); QString t5 = QString("%1").arg(QString("%1").arg(size * 5), -8, ' '); QString t6 = QString("%1").arg(QString("%1").arg(maxData), -8, ' '); painter->drawText(QPoint(20, 20), "Altitude"); painter->drawText(QPoint(20, 40), " (Feet)"); painter->drawText(QPoint(20, 100), t6); painter->drawText(QPoint(20, 190), t5); painter->drawText(QPoint(20, 280), t4); painter->drawText(QPoint(20, 370), t3); painter->drawText(QPoint(20, 460), t2); painter->drawText(QPoint(20, 550), t1); } fontRect = metrics.boundingRect("Altitude "); }else if(mode == 1) { // Speed if (maxData < 6) { painter->drawText(QPoint(20, 20), " Speed"); painter->drawText(QPoint(20, 40), " (NM) "); painter->drawText(QPoint(20, 100), " 6"); painter->drawText(QPoint(20, 190), " 5"); painter->drawText(QPoint(20, 280), " 4"); painter->drawText(QPoint(20, 370), " 3"); painter->drawText(QPoint(20, 460), " 2"); painter->drawText(QPoint(20, 550), " 1"); }else { int size = (int)(maxData / 6); QString t1 = QString("%1").arg(QString("%1").arg(size), -8, ' '); QString t2 = QString("%1").arg(QString("%1").arg(size * 2), -8, ' '); QString t3 = QString("%1").arg(QString("%1").arg(size * 3), -8, ' '); QString t4 = QString("%1").arg(QString("%1").arg(size * 4), -8, ' '); QString t5 = QString("%1").arg(QString("%1").arg(size * 5), -8, ' '); QString t6 = QString("%1").arg(QString("%1").arg(maxData), -8, ' '); painter->drawText(QPoint(20, 20), " Speed"); painter->drawText(QPoint(20, 40), " (NM) "); painter->drawText(QPoint(20, 100), t6); painter->drawText(QPoint(20, 190), t5); painter->drawText(QPoint(20, 280), t4); painter->drawText(QPoint(20, 370), t3); painter->drawText(QPoint(20, 460), t2); painter->drawText(QPoint(20, 550), t1); } fontRect = metrics.boundingRect("Speed "); } // 가로 / 세로 라인 painter->drawLine(QPoint(fontRect.width()+cap, 20), QPoint(fontRect.width()+cap, 640)); painter->drawLine(QPoint(fontRect.width()+cap, 640), QPoint(widthDef+fontRect.width()+cap, 640)); // 고도 라인 pen.setStyle(Qt::DotLine); painter->setPen(pen); painter->drawLine(QPoint(fontRect.width()+cap, 100),QPoint(widthDef+fontRect.width()+cap, 100)); painter->drawLine(QPoint(fontRect.width()+cap, 190),QPoint(widthDef+fontRect.width()+cap, 190)); painter->drawLine(QPoint(fontRect.width()+cap, 280),QPoint(widthDef+fontRect.width()+cap, 280)); painter->drawLine(QPoint(fontRect.width()+cap, 370),QPoint(widthDef+fontRect.width()+cap, 370)); painter->drawLine(QPoint(fontRect.width()+cap, 460),QPoint(widthDef+fontRect.width()+cap, 460)); painter->drawLine(QPoint(fontRect.width()+cap, 550),QPoint(widthDef+fontRect.width()+cap, 550)); // Time 추출 - 타임 라인 int timeCount = timeList.size(); int lineWidth = (int)((widthDef-100)/timeCount); // time pixel per line width int secWidth = (int)(lineWidth/plus); // 1 second per pixel int printWidth = lineWidth; //qDebug() << timeCount; for (int i=0; i<timeCount; i++) { // Time line 출력 painter->drawLine(QPoint(fontRect.width()+cap+printWidth, 20), QPoint(fontRect.width()+cap+printWidth, 640)); painter->drawText(QPoint(fontRect.width()+printWidth, 640+15), timeList[i].toString("hh:mm:ss")); printWidth += lineWidth; } //qDebug() << "secWidth : " << secWidth << ", lineWidth : " << lineWidth; // 고도에 따른 트랙 출력 QTime minTime = timeList.at(0); // 데이터 블록은 서로 겹쳐 보일 수 있으로 출력시 +- 80 으로 해서 지그재그로 보일 수 있도록 한다. int dataBlock = 80; int idx = 0; for (int i=0; i<model.size(); i++) { // TrackDataModel //qDebug() << "dataModel size : " << model[i].dataModel.size(); for (int j=0; j<model[i].dataModel.size(); j++) { //qDebug() << model[i].dataModel[j].occur_dt; if (mode == 0) { // altitude if (model[i].dataModel[j].alt == 0) continue; // alt = 0 에 대해서 처리하지 않는다. }else if(mode == 1) { // speed if (model[i].dataModel[j].spd == 0) continue; // spd = 0 에 대해서 처리하지 않는다. } idx++; QString occur_dt = model[i].dataModel[j].occur_dt; // datetime QString tm = occur_dt.right(8); QTime t = QTime::fromString(tm, "hh:mm:ss"); int sec = minTime.secsTo(t); int secPixel = sec * secWidth; //qDebug() << "sec : " << sec << ", secPixel : " << secPixel; QString fullname; if (model[i].dataModel[j].psr == "0" && model[i].dataModel[j].ssr == "1") { // PSR only fullname = QString("%1%2%3").arg(symboldir).arg(QDir::separator()).arg("psr_only.xpm"); }else if (model[i].dataModel[j].psr == "1" && model[i].dataModel[j].ssr == "0") { // SSR only fullname = QString("%1%2%3").arg(symboldir).arg(QDir::separator()).arg("ssr_only.xpm"); }else if(model[i].dataModel[j].cst == "1") { // Coasting fullname = QString("%1%2%3").arg(symboldir).arg(QDir::separator()).arg("coasting_only.xpm"); }else { fullname = QString("%1%2%3").arg(symboldir).arg(QDir::separator()).arg(model[i].symbol); } //QString fullname = QString("%1%2%3").arg(symboldir).arg(QDir::separator()).arg(model[i].symbol); QPixmap icon2; icon2.load(fullname); QPixmap icon = icon2.scaled(QSize(10, 10)); QPixmap batang(QSize(icon.width()+1, icon.height()+1)); batang.fill(QColor(0, 0, 0)); QPainter pp(&batang); pp.drawPixmap(0, 0, icon); // 고도 int alt = 0; if (mode == 0) { // Altitude alt = model[i].dataModel[j].alt; // unit = FL alt = alt * 25; // 1FL = 25 ft }else if(mode == 1) { // Speed alt = (int)model[i].dataModel[j].spd; // unit = NM } int fixel = 0; if (mode == 0) { // Altitude // max 고도에서 640을 나눈 값을 곱한다. double s = 544.0 / maxData; // 1ft = 0.018 fixel fixel = (int)(s * alt); // 고도 대 픽셀 위치 qDebug() << "s : " << s << ", fixel : " << fixel; }else if(mode == 1) { // Speed double s = 544.0 / maxData; fixel = (int)(s * alt); // 속도 대 픽셀 위치 } painter->drawPixmap(QPoint(fontRect.width()+18+lineWidth+secPixel, 640 - fixel), batang); // Altitude와 Speed가 같다면 계속적으로 데이터 블럭을 표현할 필요가 없다. if (model[i].dataModel[j].alt == model[i].dataModel[j].prev_alt && model[i].dataModel[j].spd == model[i].dataModel[j].prev_spd) { continue; } // 데이터 블럭 출력 옵션에 따라서 출력한다. if (rptOption->blockCount > 0) { if ((j+1) != 1) { // first data //qDebug() << "blockCount : " << rptOption->blockCount; //qDebug() << "myNumber : " << (j+1); //qDebug() << "cal : " << ((j+1) / rptOption->blockCount); if ((j+1) % rptOption->blockCount != 0) { continue; } } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Data block define QPen pen(Qt::black); QColor textColor = Qt::black; painter->setPen(pen); if (idx%2) { dataBlock = -40; }else { dataBlock = +80; } QString msg = ""; ////////////////////////////////////////////////////////////// // 경보 상태가 있다면... ////////////////////////////////////////////////////////////// int found = 0; int tmpHeight = 15; if (rptOption->trackNumber && model[i].dataModel[j].type == 0) { // track data msg += QString("%1").arg(model[i].trackNo); }else { msg += " "; } if (rptOption->ssr && model[i].dataModel[j].type == 0) { // ReportOption check msg += QString("/%1").arg(model[i].ssr)+"\n"; }else { msg += " \n"; } tmpHeight += 15; // 하강, 상승 QString climb; if (model[i].dataModel[j].climb > 0) { // 상승 climb = "^"; }else if(model[i].dataModel[j].climb == 0) { // 수평비행 climb = "-"; }else { climb = "V"; } QString cfl; if (model[i].dataModel[j].cfl == 0) { cfl = ""; }else { cfl = QString("%1").arg(model[i].dataModel[j].cfl); } // 고도 | 상승,하강 | 배정고도 | 속도 found = 0; QString tmp = ""; if (rptOption->modec) { msg += QString("%1 %2 ").arg(model[i].dataModel[j].alt).arg(climb); found = 1; }else { msg += " "; } if (rptOption->assignedFL && model[i].dataModel[j].type == 0) { msg += QString( "%1 ").arg(cfl); found = 1; }else { msg += " "; } if (rptOption->velocity) { msg += QString(" /%1 \n").arg((int)model[i].dataModel[j].spd); found = 1; }else { msg += " / \n"; } tmpHeight += 15; QString callsign = model[i].callsign; if (callsign != "" && rptOption->callsing) { msg += callsign + "/ "; // + QString(" %1").arg(airplane->getTrackData().wt_type); } // // 기종과 목적 공항 // if (!airplane->getTrackData().actp.trimmed().isEmpty() && airplane->getTrackData().type == 0) { // if (airplane->getReportOption()->trackNumber || callsign != "" && airplane->getReportOption()->callsing || found == 1) { // msg += "\n"; // } // msg += QString("%1 %2").arg(airplane->getTrackData().actp).arg(airplane->getTrackData().arr_ad); // found = 2; // tmpHeight += 15; // } tmpHeight += 5; QRectF rect( QPointF(fontRect.width()+18+lineWidth+secPixel - 45, 640 - fixel - 50+dataBlock), QSizeF(100, tmpHeight)); painter->drawRect(rect); painter->setPen(textColor); painter->drawText(rect, Qt::AlignCenter, msg); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Line int dim1 = 5; int dim2 = -10; painter->setPen(pen); if (idx%2) { painter->drawLine(QLineF(QPointF(fontRect.width()+18+lineWidth+secPixel+dim1, 640 - fixel - 50+dataBlock + 50), QPointF(fontRect.width()+18+lineWidth+secPixel+dim1, 640 - fixel - dim2))); }else { painter->drawLine(QLineF(QPointF(fontRect.width()+18+lineWidth+secPixel+dim1, 640 - fixel - 50+dataBlock ), QPointF(fontRect.width()+18+lineWidth+secPixel+dim1, 640 - fixel - dim2))); } } } }
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; } } } }