📄 qtextdocumentlayout.cpp
字号:
painter->setRenderHint(QPainter::Antialiasing); if (selectionFormat) { painter->setPen(QPen(selectionFormat->foreground(), 0)); painter->fillRect(r, selectionFormat->background()); } else { QBrush fg = charFormat.foreground(); if (fg == Qt::NoBrush) fg = context.palette.text(); painter->setPen(QPen(fg, 0)); } QBrush brush = context.palette.brush(QPalette::Text); switch (style) { case QTextListFormat::ListDecimal: case QTextListFormat::ListLowerAlpha: case QTextListFormat::ListUpperAlpha: { QTextLayout layout(itemText, font, q->paintDevice()); layout.setCacheEnabled(true); QTextOption option(Qt::AlignLeft | Qt::AlignAbsolute); option.setTextDirection(dir); layout.setTextOption(option); layout.beginLayout(); layout.createLine(); layout.endLayout(); layout.draw(painter, QPointF(r.left(), pos.y())); break; } case QTextListFormat::ListSquare: painter->fillRect(r, brush); break; case QTextListFormat::ListCircle: painter->drawEllipse(r); break; case QTextListFormat::ListDisc: painter->setBrush(brush); painter->drawEllipse(r); painter->setBrush(Qt::NoBrush); break; case QTextListFormat::ListStyleUndefined: break; default: break; } painter->restore();}static bool isFrameInCell(const QTextTableCell &cell, QTextFrame *frame){ const int cellStart = cell.firstPosition(); const int cellEnd = cell.lastPosition(); const int frameStart = frame->firstPosition(); const int frameEnd = frame->lastPosition(); return cellStart <= frameStart && cellStart <= frameEnd && cellEnd >= frameStart && cellEnd >= frameEnd;}QLayoutStruct QTextDocumentLayoutPrivate::layoutCell(QTextTable *t, const QTextTableCell &cell, qreal width, int layoutFrom, int layoutTo){ LDEBUG << "layoutCell"; QLayoutStruct layoutStruct; layoutStruct.frame = t; layoutStruct.minimumWidth = 0; layoutStruct.maximumWidth = INT_MAX; layoutStruct.y = 0; layoutStruct.x_left = 0; layoutStruct.x_right = width; // we get called with different widths all the time (for example for figuring // out the min/max widths), so we always have to do the full layout ;( // also when for example in a table layoutFrom/layoutTo affect only one cell, // making that one cell grow the available width of the other cells may change // (shrink) and therefore when layoutCell gets called for them they have to // be relayouted, even if layoutFrom/layoutTo is not in their range. Hence // this line: layoutStruct.fullLayout = true; QList<QTextFrame *> floats; // ### speed up // layout out child frames in that cell first for (int i = 0; i < t->childFrames().size(); ++i){ QTextFrame *frame = t->childFrames().at(i); if (isFrameInCell(cell, frame)) { QTextFrameData *cd = data(frame); cd->sizeDirty = true; layoutFrame(frame, frame->firstPosition(), frame->lastPosition(), width, -1); layoutStruct.minimumWidth = qMax(layoutStruct.minimumWidth, cd->minimumWidth); layoutStruct.maximumWidth = qMin(layoutStruct.maximumWidth, cd->maximumWidth); if (cd->flow_position != QTextFrameFormat::InFlow) floats.append(frame); } } qreal floatMinWidth = layoutStruct.minimumWidth; layoutFlow(cell.begin(), &layoutStruct, layoutFrom, layoutTo); // floats that are located inside the text (like inline images) aren't taken into account by // layoutFlow with regards to the cell height (layoutStruct->y), so for a safety measure we // do that here. For example with <td><img align="right" src="..." />blah</td> // when the image happens to be higher than the text for (int i = 0; i < floats.size(); ++i) layoutStruct.y = qMax(layoutStruct.y, data(floats.at(i))->size.height()); // constraint the maximumWidth by the minimum width of the fixed size floats, to // keep them visible layoutStruct.maximumWidth = qMax(layoutStruct.maximumWidth, floatMinWidth); // as floats in cells get added to the table's float list but must not affect // floats in other cells we must clear the list here. data(t)->floats.clear();// qDebug() << "layoutCell done"; return layoutStruct;}QRectF QTextDocumentLayoutPrivate::layoutTable(QTextTable *table, int layoutFrom, int layoutTo){ LDEBUG << "layoutTable"; QTextTableData *td = static_cast<QTextTableData *>(data(table)); Q_ASSERT(td->sizeDirty); const int rows = table->rows(); const int columns = table->columns(); const QTextTableFormat fmt = table->format(); QVector<QTextLength> columnWidthConstraints = fmt.columnWidthConstraints(); if (columnWidthConstraints.size() != columns) columnWidthConstraints.resize(columns); Q_ASSERT(columnWidthConstraints.count() == columns); const qreal cellSpacing = td->cellSpacing = fmt.cellSpacing(); td->cellPadding = fmt.cellPadding(); const qreal margin = td->margin + td->border + td->padding; qreal totalWidth = fmt.width().value(td->contentsWidth); // two (vertical) borders per cell per column totalWidth -= columns * 2 * td->border; // inter-cell spacing totalWidth -= (columns - 1) * cellSpacing; // cell spacing at the left and right hand side totalWidth -= 2 * cellSpacing; // remember the width used to distribute to percentaged columns qreal initialTotalWidth = totalWidth; td->widths.resize(columns); td->widths.fill(0); td->minWidths.resize(columns); // start with a minimum width of 0. totally empty // cells of default created tables are invisible otherwise // and therefore hardly editable td->minWidths.fill(1); td->maxWidths.resize(columns); td->maxWidths.fill(INT_MAX); td->rowPageBreaks.clear(); // calculate minimum and maximum sizes of the columns for (int i = 0; i < columns; ++i) { for (int row = 0; row < rows; ++row) { const QTextTableCell cell = table->cellAt(row, i); const int cspan = cell.columnSpan(); if (cspan > 1 && i != cell.column()) continue; // to figure out the min and the max width lay out the cell at // maximum width. otherwise the maxwidth calculation sometimes // returns wrong values QLayoutStruct layoutStruct = layoutCell(table, cell, INT_MAX, layoutFrom, layoutTo); // distribute the minimum width over all columns the cell spans qreal widthToDistribute = layoutStruct.minimumWidth + 2 * td->cellPadding; for (int n = 0; n < cspan; ++n) { const int col = i + n; qreal w = widthToDistribute / (cspan - n); td->minWidths[col] = qMax(td->minWidths.at(col), w); widthToDistribute -= td->minWidths.at(col); if (widthToDistribute <= 0) break; } // ### colspans qreal maxW = td->maxWidths.at(i); if (layoutStruct.maximumWidth != INT_MAX) { if (maxW == INT_MAX) maxW = layoutStruct.maximumWidth + 2 * td->cellPadding; else maxW = qMax(maxW, layoutStruct.maximumWidth + 2 * td->cellPadding); } td->maxWidths[i] = qMax(td->minWidths.at(i), maxW); } } // set fixed values, figure out total percentages used and number of // variable length cells. Also assign the minimum width for variable columns. qreal totalPercentage = 0; int variableCols = 0; for (int i = 0; i < columns; ++i) { const QTextLength &length = columnWidthConstraints.at(i); if (length.type() == QTextLength::FixedLength) { td->widths[i] = qMax(length.rawValue(), td->minWidths.at(i)); totalWidth -= td->widths.at(i); } else if (length.type() == QTextLength::PercentageLength) { totalPercentage += length.rawValue(); } else if (length.type() == QTextLength::VariableLength) { variableCols++; td->widths[i] = td->minWidths.at(i); totalWidth -= td->minWidths.at(i); } } // set percentage values { const qreal totalPercentagedWidth = initialTotalWidth * totalPercentage / 100; for (int i = 0; i < columns; ++i) if (columnWidthConstraints.at(i).type() == QTextLength::PercentageLength) { const qreal percentWidth = totalPercentagedWidth * columnWidthConstraints.at(i).rawValue() / totalPercentage; td->widths[i] = qMax(percentWidth, td->minWidths.at(i)); totalWidth -= td->widths.at(i); } } // for variable columns distribute the remaining space if (variableCols > 0 && totalWidth > 0) { QVarLengthArray<int> columnsWithProperMaxSize; for (int i = 0; i < columns; ++i) if (columnWidthConstraints.at(i).type() == QTextLength::VariableLength && td->maxWidths.at(i) != INT_MAX) columnsWithProperMaxSize.append(i); qreal lastTotalWidth = totalWidth; while (totalWidth > 0) { for (int k = 0; k < columnsWithProperMaxSize.count(); ++k) { const int col = columnsWithProperMaxSize[k]; const int colsLeft = columnsWithProperMaxSize.count() - k; const qreal w = qMin(td->maxWidths.at(col) - td->widths.at(col), totalWidth / colsLeft); td->widths[col] += w; totalWidth -= w; } if (totalWidth == lastTotalWidth) break; lastTotalWidth = totalWidth; } if (totalWidth > 0 // don't unnecessarily grow variable length sized tables && fmt.width().type() != QTextLength::VariableLength) { const qreal widthPerAnySizedCol = totalWidth / variableCols; for (int col = 0; col < columns; ++col) { if (columnWidthConstraints.at(col).type() == QTextLength::VariableLength) td->widths[col] += widthPerAnySizedCol; } } } td->columnPositions.resize(columns); td->columnPositions[0] = margin /*includes table border*/ + cellSpacing + td->border; for (int i = 1; i < columns; ++i) td->columnPositions[i] = td->columnPositions.at(i-1) + td->widths.at(i-1) + td->border + cellSpacing + td->border; td->heights.resize(rows); td->heights.fill(0); td->rowPositions.resize(rows); td->rowPositions[0] = margin /*includes table border*/ + cellSpacing + td->border; bool haveRowSpannedCells = false; // now that we have the column widths we can lay out all cells with the right // width, to calculate the row heights. we have to use two passes though, cells // which span more than one row have to be processed later to avoid them enlarging // other calls too much // // ### this could be made faster by iterating over the cells array of QTextTable for (int r = 0; r < rows; ++r) { td->calcRowPosition(r); for (int c = 0; c < columns; ++c) { QTextTableCell cell = table->cellAt(r, c); const int rspan = cell.rowSpan(); const int cspan = cell.columnSpan(); if (cspan > 1 && cell.column() != c) continue; if (rspan > 1) { haveRowSpannedCells = true; continue; } const qreal width = td->cellWidth(c, cspan);// qDebug() << "layoutCell for cell at row" << r << "col" << c; QLayoutStruct layoutStruct = layoutCell(table, cell, width, layoutFrom, layoutTo); td->heights[r] = qMax(td->heights.at(r), layoutStruct.y + 2 * td->cellPadding); } } if (haveRowSpannedCells) { for (int r = 0; r < rows; ++r) { td->calcRowPosition(r); for (int c = 0; c < columns; ++c) { QTextTableCell cell = table->cellAt(r, c); const int rspan = cell.rowSpan(); const int cspan = cell.columnSpan(); if (cspan > 1 && cell.column() != c) continue; if (rspan == 1) continue; if (cell.row() != r) continue; const qreal width = td->cellWidth(c, cspan); QLayoutStruct layoutStruct = layoutCell(table, cell, width, layoutFrom, layoutTo); // the last row gets all the remaining space qreal heightToDistribute = layoutStruct.y + 2 * td->cellPadding; for (int n = 0; n < rspan - 1; ++n) { const int row = r + n; heightToDistribute -= td->heights.at(row) + td->border + cellSpacing + td->border; if (heightToDistribute <= 0) break; } if (heightToDistribute > 0) { const int lastRow = r + rspan - 1; td->heights[lastRow] = qMax(td->heights.at(lastRow), heightToDistribute); } } } } // - margin to compensate the + margin in columnPositions[0]// td->contentsWidth = qMax(td->contentsWidth,// td->columnPositions.last() + td->widths.last() + td->padding + td->border + cellSpacing - margin); td->contentsWidth = td->columnPositions.last() + td->widths.last() + td->padding + td->border + cellSpacing - margin; td->minimumWidth = td->columnPositions.at(0); for (int i = 0; i < columns; ++i) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -