Rev 22507 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
Copyright (C) 2011 Elvis Stansvik <elvstone@gmail.com>
For general Scribus (>=1.3.2) copyright and licensing information please refer
to the COPYING file provided with the program. Following this notice may exist
a copyright and/or license notice that predates the release of Scribus 1.3.2
for which a new license (GPL+exception) is in place.
*/
#include <QColor>
#include <QLineF>
#include <QRectF>
#include "scpainter.h"
#include "tablecell.h"
#include "pageitem_table.h"
#include "prefsmanager.h"
#include "scribusdoc.h"
#include "tableborder.h"
#include "tableutils.h"
#include "collapsedtablepainter.h"
using namespace TableUtils;
void CollapsedTablePainter::paintTable(ScPainter* p)
{
p->save();
p->translate(table()->gridOffset());
// Paint table fill.
paintTableFill(p);
/*
* We paint the table in five passes:
*
* 1) Cell fills.
* 2) Vertical borders.
* 3) Horizontal borders
* 4) Decorative grid lines.
* 5) Cell content.
*/
// Pass 1: Paint cell fills.
for (int row = 0; row < table()->rows(); ++row)
{
int colSpan = 0;
for (int col = 0; col < table()->columns(); col += colSpan)
{
TableCell cell = table()->cellAt(row, col);
if (row == cell.row())
paintCellFill(cell, p);
colSpan = cell.columnSpan();
}
}
// Pass 2: Paint vertical borders.
for (int row = 0; row < table()->rows(); ++row)
{
int colSpan = 0;
for (int col = 0; col < table()->columns(); col += colSpan)
{
TableCell cell = table()->cellAt(row, col);
if (row == cell.row())
{
paintCellRightBorders(cell, p);
if (col == 0)
paintCellLeftBorders(cell, p);
}
colSpan = cell.columnSpan();
}
}
// Pass 3: Paint horizontal borders.
for (int row = 0; row < table()->rows(); ++row)
{
int colSpan = 0;
for (int col = 0; col < table()->columns(); col += colSpan)
{
TableCell cell = table()->cellAt(row, col);
if (row == cell.row())
{
paintCellBottomBorders(cell, p);
if (row == 0)
paintCellTopBorders(cell, p);
}
colSpan = cell.columnSpan();
}
}
// Pass 4: Paint grid lines.
if (table()->m_Doc->guidesPrefs().framesShown)
{
for (int row = 0; row < table()->rows(); ++row)
{
int colSpan = 0;
for (int col = 0; col < table()->columns(); col += colSpan)
{
TableCell cell = table()->cellAt(row, col);
if (row == cell.row())
{
int endCol = col + cell.columnSpan() - 1;
int endRow = row + cell.rowSpan() - 1;
double left = table()->columnPosition(col);
double right = table()->columnPosition(endCol) + table()->columnWidth(endCol);
double top = table()->rowPosition(row);
double bottom = table()->rowPosition(endRow) + table()->rowHeight(endRow);
// Paint right and bottom grid line.
paintGridLine(QPointF(right, top), QPointF(right, bottom), p);
paintGridLine(QPointF(left, bottom), QPointF(right, bottom), p);
// Paint left and top grid line.
if (col == 0)
paintGridLine(QPointF(left, top), QPointF(left, bottom), p);
if (row == 0)
paintGridLine(QPointF(left, top), QPointF(right, top), p);
}
colSpan = cell.columnSpan();
}
}
}
// Pass 5: Paint cell content.
for (int row = 0; row < table()->rows(); ++row)
{
for (int col = 0; col < table()->columns(); col ++)
{
TableCell cell = table()->cellAt(row, col);
if (cell.row() == row && cell.column() == col)
{
PageItem* textFrame = cell.textFrame();
textFrame->DrawObj(p, QRectF());
textFrame->DrawObj_Decoration(p);
}
}
}
p->restore();
}
void CollapsedTablePainter::paintTableFill(ScPainter* p) const
{
QString colorName = table()->fillColor();
if (colorName == CommonStrings::None)
return;
p->save();
int lastCol = table()->columns() - 1;
int lastRow = table()->rows() - 1;
double x = table()->columnPosition(0);
double y = table()->rowPosition(0);
double width = table()->columnPosition(lastCol) + table()->columnWidth(lastCol) - x;
double height = table()->rowPosition(lastRow) + table()->rowHeight(lastRow) - y;
QColor color;
table()->SetQColor(&color, colorName, table()->fillShade());
p->setBrush(color);
p->setFillMode(ScPainter::Solid);
p->setStrokeMode(ScPainter::None);
p->drawRect(x, y, width, height);
p->restore();
}
void CollapsedTablePainter::paintCellLeftBorders(const TableCell& cell, ScPainter* p) const
{
/*
* We are going to paint the border marked # in the following setup.
*
* +----------------------+----------------------+
* | | |
* | | |
* | topLeftCell top topRightCell |
* | | |
* | | |
* +--------topLeft-------+-------topRight-------+
* | # |
* | # |
* | leftCell border cell |
* | # |
* | # |
* +-------bottomLeft-----+------bottomRight-----+
* | | |
* | | |
* | bottomLeftCell bottom bottomRightCell |
* | | |
* | | |
* +----------------------+----------------------+
*/
// The cell ends in this row.
const int lastRow = cell.row() + cell.rowSpan() - 1;
// The cell starts in this column.
const int firstCol = cell.column();
// The X position of the border segments to paint.
const double borderX = table()->columnPosition(firstCol);
// The start point of the border segment currently being painted.
QPointF start(borderX, 0.0);
// The end point of the border segment currently being painted.
QPointF end(borderX, 0.0);
// The start and end offset factors for the border segment currently being painted.
QPointF startOffsetFactors, endOffsetFactors;
// Start and end row of border segment currently being painted.
int startRow, endRow;
for (int row = cell.row(); row <= lastRow; row += endRow - startRow + 1)
{
// Get the neighboring cell to the left and determine border segment row interval.
TableCell leftCell = table()->cellAt(row, firstCol - 1);
startRow = qMax(cell.row(), leftCell.row());
endRow = qMin(lastRow, leftCell.isValid() ? leftCell.row() + leftCell.rowSpan() - 1 : lastRow);
// Get the remaining neighboring cells.
TableCell topLeftCell = table()->cellAt(startRow - 1, firstCol - 1);
TableCell topRightCell = table()->cellAt(startRow - 1, firstCol);
TableCell bottomRightCell = table()->cellAt(lastRow + 1, firstCol);
TableCell bottomLeftCell = table()->cellAt(lastRow + 1, firstCol - 1);
// Resolve borders between neighboring cells.
TableBorder topLeft, top, topRight, border, bottomLeft, bottom, bottomRight;
resolveBordersVertical(topLeftCell, topRightCell, leftCell, cell, bottomLeftCell, bottomRightCell, &topLeft, &top, &topRight, &border, &bottomLeft, &bottom, &bottomRight, table());
if (border.isNull())
continue; // Quit early if the border to paint is null.
// Set initial coordinates.
start.setY(table()->rowPosition(startRow));
end.setY(table()->rowPosition(endRow) + table()->rowHeight(endRow));
// Adjust coordinates for joining.
joinVertical(border, topLeft, top, topRight, bottomLeft, bottom, bottomRight,
&start, &end, &startOffsetFactors, &endOffsetFactors);
// Paint the border segment.
paintBorder(border, start, end, startOffsetFactors, endOffsetFactors, p);
}
}
void CollapsedTablePainter::paintCellRightBorders(const TableCell& cell, ScPainter* p) const
{
/*
* We are going to paint the border marked # in the following setup.
*
* +----------------------+----------------------+
* | | |
* | | |
* | topLeftCell top topRightCell |
* | | |
* | | |
* +--------topLeft-------+-------topRight-------+
* | # |
* | # |
* | cell border rightCell |
* | # |
* | # |
* +-------bottomLeft-----+------bottomRight-----+
* | | |
* | | |
* | bottomLeftCell bottom bottomRightCell |
* | | |
* | | |
* +----------------------+----------------------+
*/
// The cell ends in this row.
const int lastRow = cell.row() + cell.rowSpan() - 1;
// The cell ends in this column.
const int lastCol = cell.column() + cell.columnSpan() - 1;
// The X position of the border segments to paint.
const double borderX = table()->columnPosition(lastCol) + table()->columnWidth(lastCol);
// The start point of the border segment currently being painted.
QPointF start(borderX, 0.0);
// The end point of the border segment currently being painted.
QPointF end(borderX, 0.0);
// The start and end offset factors for the border segment currently being painted.
QPointF startOffsetFactors, endOffsetFactors;
// The start and end row of border segment currently being painted.
int startRow, endRow;
for (int row = cell.row(); row <= lastRow; row += endRow - startRow + 1)
{
// Get the neighboring cell to the right and determine border segment row interval.
TableCell rightCell = table()->cellAt(row, lastCol + 1);
startRow = qMax(cell.row(), rightCell.row());
endRow = qMin(lastRow, rightCell.isValid() ? rightCell.row() + rightCell.rowSpan() - 1 : lastRow);
// Get the remaining neighboring cells surrounding the segment.
TableCell topLeftCell = table()->cellAt(startRow - 1, lastCol);
TableCell topRightCell = table()->cellAt(startRow - 1, lastCol + 1);
TableCell bottomRightCell = table()->cellAt(endRow + 1, lastCol + 1);
TableCell bottomLeftCell = table()->cellAt(endRow + 1, lastCol);
// Resolve borders between neighboring cells.
TableBorder topLeft, top, topRight, border, bottomLeft, bottom, bottomRight;
resolveBordersVertical(topLeftCell, topRightCell, cell, rightCell, bottomLeftCell, bottomRightCell, &topLeft, &top, &topRight, &border, &bottomLeft, &bottom, &bottomRight, table());
if (border.isNull())
continue; // Quit early if the border to paint is null.
// Set initial coordinates.
start.setY(table()->rowPosition(startRow));
end.setY(table()->rowPosition(endRow) + table()->rowHeight(endRow));
// Adjust coordinates for joining.
joinVertical(border, topLeft, top, topRight, bottomLeft, bottom, bottomRight,
&start, &end, &startOffsetFactors, &endOffsetFactors);
// Paint the border.
paintBorder(border, start, end, startOffsetFactors, endOffsetFactors, p);
}
}
void CollapsedTablePainter::paintCellTopBorders(const TableCell& cell, ScPainter* p) const
{
/*
* We are going to paint the border marked # in the following setup.
*
* +--------------------------+--------------------------+--------------------------+
* | | | |
* | | | |
* | topLeftCell topLeft topCell topRight topRightCell |
* | | | |
* | | | |
* +----------left------------+######### border-#########+----------right-----------+
* | | | |
* | | | |
* | bottomLeftCell bottomLeft cell bottomRight bottomRightCell |
* | | | |
* | | | |
* +--------------------------+--------------------------+--------------------------+
*/
// The cell starts in this row.
const int firstRow = cell.row();
// The cell ends in this column.
const int lastCol = cell.column() + cell.columnSpan() - 1;
// The Y position of the border segments to paint.
const double borderY = table()->rowPosition(firstRow);
// The start point of the border segment currently being painted.
QPointF start(0.0, borderY);
// The end point of the border segment currently being painted.
QPointF end(0.0, borderY);
// The start and end offset factors for the border segment currently being painted.
QPointF startOffsetFactors, endOffsetFactors;
// Start and end column of border segment currently being painted.
int startCol, endCol;
for (int col = cell.column(); col <= lastCol; col += endCol - startCol + 1)
{
// Get the neighboring cell above and determine border segment column interval.
TableCell topCell = table()->cellAt(firstRow - 1, col);
startCol = qMax(cell.column(), topCell.column());
endCol = qMin(lastCol, topCell.isValid() ? topCell.column() + topCell.columnSpan() - 1 : lastCol);
// Get the remaining neighboring cells.
TableCell topLeftCell = table()->cellAt(firstRow - 1, startCol - 1);
TableCell topRightCell = table()->cellAt(firstRow - 1, endCol + 1);
TableCell bottomRightCell = table()->cellAt(firstRow, endCol + 1);
TableCell bottomLeftCell = table()->cellAt(firstRow, startCol - 1);
// Resolve borders between neighboring cells.
TableBorder topLeft, left, bottomLeft, border, topRight, right, bottomRight;
resolveBordersHorizontal(topLeftCell, topCell, topRightCell, bottomLeftCell, cell, bottomRightCell, &topLeft, &left, &bottomLeft, &border, &topRight, &right, &bottomRight, table());
if (border.isNull())
continue; // Quit early if the border is null.
// Set initial coordinates.
start.setX(table()->columnPosition(startCol));
end.setX(table()->columnPosition(endCol) + table()->columnWidth(endCol));
// Adjust coordinates for joining.
joinHorizontal(border, topLeft, left, bottomLeft, topRight, right, bottomRight,
&start, &end, &startOffsetFactors, &endOffsetFactors);
// Paint the border segment.
paintBorder(border, start, end, startOffsetFactors, endOffsetFactors, p);
}
}
void CollapsedTablePainter::paintCellBottomBorders(const TableCell& cell, ScPainter* p) const
{
/*
* We are going to paint the border marked # in the following setup.
*
* +--------------------------+--------------------------+--------------------------+
* | | | |
* | | | |
* | topLeftCell topLeft cell topRight topRightCell |
* | | | |
* | | | |
* +----------left------------+######### border-#########+----------right-----------+
* | | | |
* | | | |
* | bottomLeftCell bottomLeft bottomCell bottomRight bottomRightCell |
* | | | |
* | | | |
* +--------------------------+--------------------------+--------------------------+
*/
// The cell ends in this row.
const int lastRow = cell.row() + cell.rowSpan() - 1;
// The cell ends in this column.
const int lastCol = cell.column() + cell.columnSpan() - 1;
// The Y position of the border segments to paint.
const double borderY = table()->rowPosition(lastRow) + table()->rowHeight(lastRow);
// The start point of the border segment currently being painted.
QPointF start(0.0, borderY);
// The end point of the border segment currently being painted.
QPointF end(0.0, borderY);
// The start and end offset factors for the border segment currently being painted.
QPointF startOffsetFactors, endOffsetFactors;
// Start and end column of border segment currently being painted.
int startCol, endCol;
for (int col = cell.column(); col <= lastCol; col += endCol - startCol + 1)
{
// Get the neighboring cell below and determine border segment column interval.
TableCell bottomCell = table()->cellAt(lastRow + 1, col);
startCol = qMax(cell.column(), bottomCell.column());
endCol = qMin(lastCol, bottomCell.isValid() ? bottomCell.column() + bottomCell.columnSpan() - 1 : lastCol);
// Get the remaining neighboring cells.
TableCell topLeftCell = table()->cellAt(lastRow, startCol - 1);
TableCell topRightCell = table()->cellAt(lastRow, endCol + 1);
TableCell bottomRightCell = table()->cellAt(lastRow + 1, endCol + 1);
TableCell bottomLeftCell = table()->cellAt(lastRow + 1, startCol - 1);
// Resolve borders between neighboring cells.
TableBorder topLeft, left, bottomLeft, border, topRight, right, bottomRight;
resolveBordersHorizontal(topLeftCell, cell, topRightCell, bottomLeftCell, bottomCell, bottomRightCell, &topLeft, &left, &bottomLeft, &border, &topRight, &right, &bottomRight, table());
if (border.isNull())
continue; // Quit early if the border is null.
// Set initial coordinates.
start.setX(table()->columnPosition(startCol));
end.setX(table()->columnPosition(endCol) + table()->columnWidth(endCol));
// Adjust coordinates for joining.
joinHorizontal(border, topLeft, left, bottomLeft, topRight, right, bottomRight,
&start, &end, &startOffsetFactors, &endOffsetFactors);
// Paint the border segment.
paintBorder(border, start, end, startOffsetFactors, endOffsetFactors, p);
}
}
void CollapsedTablePainter::paintCellFill(const TableCell& cell, ScPainter* p) const
{
QString colorName = cell.fillColor();
if (colorName == CommonStrings::None)
return;
p->save();
QColor color;
table()->SetQColor(&color, colorName, cell.fillShade());
p->setBrush(color);
p->setFillMode(ScPainter::Solid);
p->setStrokeMode(ScPainter::None);
int row = cell.row();
int col = cell.column();
int lastRow = row + cell.rowSpan() - 1;
int lastCol = col + cell.columnSpan() - 1;
double x = table()->columnPosition(col);
double y = table()->rowPosition(row);
double width = table()->columnPosition(lastCol) + table()->columnWidth(lastCol) - x;
double height = table()->rowPosition(lastRow) + table()->rowHeight(lastRow) - y;
p->drawRect(x, y, width, height);
p->restore();
}
void CollapsedTablePainter::paintBorder(const TableBorder& border, const QPointF& start, const QPointF& end,
const QPointF& startOffsetFactors, const QPointF& endOffsetFactors,
ScPainter *p) const
{
p->save();
p->setStrokeMode(ScPainter::Solid);
p->setFillMode(ScPainter::None);
QColor lineColor;
QPointF lineStart, lineEnd;
for (const TableBorderLine& line : border.borderLines())
{
// Adjust line start and ends by line width multiplied by offset factors.
lineStart.setX(start.x() + line.width() * startOffsetFactors.x());
lineStart.setY(start.y() + line.width() * startOffsetFactors.y());
lineEnd.setX(end.x() + line.width() * endOffsetFactors.x());
lineEnd.setY(end.y() + line.width() * endOffsetFactors.y());
// Set line color.
if (line.color() == CommonStrings::None)
continue;
table()->SetQColor(&lineColor, line.color(), line.shade());
// Draw line.
p->setPen(lineColor, line.width(), line.style(), Qt::FlatCap, Qt::MiterJoin);
p->drawLine(lineStart, lineEnd);
}
p->restore();
}
void CollapsedTablePainter::paintGridLine(const QPointF& start, const QPointF& end, ScPainter *p) const
{
p->save();
p->setPen(PrefsManager::instance().appPrefs.displayPrefs.frameNormColor,
0.2 / qMax(p->zoomFactor(), 1.0), Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
p->setStrokeMode(ScPainter::Solid);
p->drawLine(start, end);
p->restore();
}