mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 22:02:49 -06:00
537 lines
14 KiB
C++
537 lines
14 KiB
C++
#include "DocTypes.h"
|
|
|
|
NAMESPACE_UPP
|
|
|
|
TableCell& TableCell::NewPar() {
|
|
par.Add();
|
|
par.Top().CopyStyle(par[par.GetCount() - 2]);
|
|
return *this;
|
|
}
|
|
|
|
int TableCell::GetHeight(int zoom, int cx) const {
|
|
cx -= DocZoom(zoom, style.leftwidth) + DocZoomLn(zoom, style.rightwidth) +
|
|
DocZoom(zoom, style.leftspace) + DocZoom(zoom, style.rightspace);
|
|
int cy = DocZoom(zoom, style.topwidth) + DocZoomLn(zoom, style.bottomwidth) +
|
|
DocZoom(zoom, style.topspace) + DocZoom(zoom, style.bottomspace);
|
|
for(int i = 0; i < par.GetCount(); i++) {
|
|
const Paragraph& p = par[i];
|
|
cy += p.GetHeight(zoom, cx) +
|
|
DocZoom(zoom, p.GetBefore()) + DocZoom(zoom, p.GetAfter());
|
|
}
|
|
return paintrect ? max(cy, paintrect.RatioSize(cx, 0).cy) : cy;
|
|
}
|
|
|
|
int TableCell::GetWidth(int zoom) const {
|
|
int cx = 0;
|
|
for(int i = 0; i < par.GetCount(); i++)
|
|
cx = max(cx, par[i].GetWidth(zoom));
|
|
cx += DocZoom(zoom, style.leftwidth) + DocZoomLn(zoom, style.rightwidth) +
|
|
DocZoom(zoom, style.leftspace) + DocZoom(zoom, style.rightspace);
|
|
return cx;
|
|
}
|
|
|
|
bool TableCell::Paint(int zoom, Draw& w, int x, int y, int cx, int cy, int pcy, Color color,
|
|
PaintInfo& pi) const {
|
|
if(pcy > cy) pcy = cy;
|
|
w.DrawRect(x, y, cx, cy, style.paper);
|
|
int lw = DocZoom(zoom, style.leftwidth);
|
|
int tw = DocZoom(zoom, style.topwidth);
|
|
int rw = DocZoomLn(zoom, style.rightwidth);
|
|
int bw = DocZoomLn(zoom, style.bottomwidth);
|
|
int ls = DocZoom(zoom, style.leftspace);
|
|
int ts = DocZoom(zoom, style.topspace);
|
|
int rs = DocZoom(zoom, style.rightspace);
|
|
int bs = DocZoom(zoom, style.bottomspace);
|
|
Rect r(x + lw + ls, y + tw + ts, x + cx - rw - rs, y + cy - bw - bs);
|
|
if(paintrect) {
|
|
w.Clip(r);
|
|
paintrect.Paint(w, r, color, style.paper);
|
|
w.End();
|
|
}
|
|
w.DrawRect(x, y, lw, cy, color);
|
|
w.DrawRect(x, y, cx, tw, color);
|
|
w.DrawRect(x + cx - rw, y, rw, cy, color);
|
|
w.DrawRect(x, y + cy - bw, cx, bw, color);
|
|
x = r.left;
|
|
cx = r.Width();
|
|
switch(style.align) {
|
|
case ALIGN_TOP:
|
|
y = y + tw + ts;
|
|
break;
|
|
case ALIGN_CENTER:
|
|
y = y + (cy - pcy) / 2 + tw + ts;
|
|
break;
|
|
case ALIGN_BOTTOM:
|
|
y = y + cy - pcy - bw - bs;
|
|
break;
|
|
}
|
|
int ymax = y + cy - bw - bs;
|
|
int ypos = 0;
|
|
for(int i = 0; i < par.GetCount(); i++) {
|
|
const Paragraph& p = par[i];
|
|
int bef = DocZoom(zoom, p.GetBefore());
|
|
int aft = DocZoom(zoom, p.GetAfter());
|
|
if(ypos + bef - pi.yl + y > ymax) {
|
|
pi.yl = ypos;
|
|
return true;
|
|
}
|
|
ypos += bef;
|
|
Paragraph::PaintInfo ppi;
|
|
if(ypos >= pi.yl) {
|
|
int py = y + ypos - pi.yl;
|
|
if(p.Paint(zoom, w, x, py, cx, ymax, ppi, style.paper)) {
|
|
pi.yl = ypos + ppi.yl;
|
|
return true;
|
|
}
|
|
ypos += ppi.ypos - py;
|
|
}
|
|
else {
|
|
int h = ypos < pi.yl ? p.GetHeight(zoom, cx) : 0;
|
|
if(ypos + h > pi.yl) {
|
|
ppi.yl = pi.yl - ypos;
|
|
if(p.Paint(zoom, w, x, y, cx, ymax, ppi, style.paper)) {
|
|
pi.yl = ypos + ppi.yl;
|
|
return true;
|
|
}
|
|
}
|
|
ypos += h;
|
|
}
|
|
ypos += aft;
|
|
if(ypos - pi.yl + y > ymax) {
|
|
pi.yl = ypos;
|
|
return true;
|
|
}
|
|
}
|
|
pi.yl = ypos;
|
|
return false;
|
|
}
|
|
|
|
void TableCell::GetValueRects(int zoom, Draw& w, int x, int y, int cx, int cy, int pcy,
|
|
Vector<ValueRect>& vr)
|
|
const {
|
|
if(pcy > cy) pcy = cy;
|
|
int lm = DocZoom(zoom, style.leftwidth) + DocZoom(zoom, style.leftspace);
|
|
x += lm;
|
|
cx -= lm + DocZoomLn(zoom, style.rightwidth) + DocZoom(zoom, style.rightspace);
|
|
int tm = DocZoom(zoom, style.topwidth) + DocZoom(zoom, style.topspace);
|
|
switch(style.align) {
|
|
case ALIGN_TOP:
|
|
y += tm;
|
|
break;
|
|
case ALIGN_CENTER:
|
|
y += (cy - pcy) / 2 + tm;
|
|
break;
|
|
case ALIGN_BOTTOM:
|
|
y += cy - pcy - DocZoomLn(zoom, style.bottomwidth) - DocZoom(zoom, style.bottomspace);
|
|
break;
|
|
}
|
|
for(int i = 0; i < par.GetCount(); i++) {
|
|
const Paragraph& p = par[i];
|
|
y += DocZoom(zoom, p.GetBefore());
|
|
p.GetValueRects(zoom, w, x, y, cx, vr);
|
|
y += DocZoom(zoom, p.GetAfter());
|
|
}
|
|
}
|
|
|
|
void TableCell::Qtf(const char *s) {
|
|
QtfParser parser;
|
|
par.Clear();
|
|
parser.Set(s);
|
|
while(parser.Parse() == QtfParser::PARAGRAPH)
|
|
par.Add() = parser.PickParagraph();
|
|
if(par.IsEmpty())
|
|
par.Add();
|
|
}
|
|
|
|
TableCell::TableCell(const TableCell& c, int) : par(c.par, 1) {
|
|
CopyStyle(c);
|
|
keep = c.keep;
|
|
paintrect = c.paintrect;
|
|
}
|
|
|
|
void TableCell::Style::Init() {
|
|
ratio = 1;
|
|
leftwidth = topwidth = rightwidth = bottomwidth = 5;
|
|
leftspace = rightspace = 20;
|
|
topspace = bottomspace = 10;
|
|
align = ALIGN_CENTER;
|
|
paper = White;
|
|
}
|
|
|
|
TableCell::TableCell() {
|
|
style.Init();
|
|
par.Add();
|
|
keep = false;
|
|
span = 1;
|
|
}
|
|
|
|
TableCell& Table::operator()(int i, int j) {
|
|
Array<TableCell>& c = cell.DoIndex(i);
|
|
int n = c.GetCount();
|
|
if(n <= j) {
|
|
c.SetCount(j + 1);
|
|
Array<TableCell>& row0 = cell[0];
|
|
if(i != 0) {
|
|
int l = min(row0.GetCount(), c.GetCount());
|
|
for(int j = n; j < l; j++)
|
|
c[j].Ratio(row0[j].GetRatio()).CopyStyle(row0[j].Par());
|
|
}
|
|
}
|
|
return c[j];
|
|
}
|
|
|
|
Table& Table::AddRow() {
|
|
cell.DoIndex(cell.GetCount());
|
|
return *this;
|
|
}
|
|
|
|
TableCell& Table::AddCell(bool inheritstyle) {
|
|
int j = cell.Top().GetCount();
|
|
TableCell& cl = cell.Top().Add();
|
|
if(inheritstyle)
|
|
if(cell.GetCount() > 1) {
|
|
Array<TableCell>& row0 = cell[0];
|
|
if(row0.GetCount() > j) {
|
|
cl.CopyStyle(row0[j]);
|
|
cl.CopyStyle(row0[j].Par());
|
|
}
|
|
}
|
|
else
|
|
if(cell[0].GetCount() > 1) {
|
|
TableCell& cc = cell[0][cell[0].GetCount() - 2];
|
|
cl.CopyStyle(cc);
|
|
cl.CopyStyle(cc.Par());
|
|
cl.Ratio(1);
|
|
}
|
|
return cl;
|
|
}
|
|
|
|
Table::Table(const Table& tab, int) : cell(tab.cell, 1) {
|
|
style = tab.style;
|
|
}
|
|
|
|
void Table::Style::Init() {
|
|
framewidth = 5;
|
|
framecolor = Black;
|
|
before = after = 0;
|
|
lm = rm = 0;
|
|
headerrows = 1;
|
|
breakcy = 800;
|
|
breakpgcy = 400;
|
|
}
|
|
|
|
Table::Table() {
|
|
style.Init();
|
|
}
|
|
|
|
int GetTotalRatio(const Array<TableCell>& row) {
|
|
int tr = 0;
|
|
for(int i = 0; i < row.GetCount(); i++)
|
|
tr += row[i].GetRatio();
|
|
return tr;
|
|
}
|
|
|
|
Table::Line Table::GetLine(int zoom, int i, int tcx, const Vector<int> *yl) const {
|
|
Line ln;
|
|
const Array<TableCell>& row = cell[i];
|
|
int rcx = GetTotalRatio(row);
|
|
ln.cell.SetCount(row.GetCount());
|
|
ln.keep = false;
|
|
ln.height = 0;
|
|
ln.span = 0;
|
|
int cx = 0;
|
|
int rt = 0;
|
|
int j;
|
|
for(j = 0; j < row.GetCount(); j++) {
|
|
Size& sz = ln.cell[j].size;
|
|
const TableCell& cell = row[j];
|
|
int span = ln.cell[j].span = cell.GetSpan() > 1 ? cell.GetSpan() : 0;
|
|
ln.span = max(ln.span, span);
|
|
if(j == row.GetCount() - 1)
|
|
sz.cx = tcx - cx;
|
|
else {
|
|
rt += cell.GetRatio();
|
|
sz.cx = tcx * rt / rcx - cx;
|
|
cx += sz.cx;
|
|
}
|
|
}
|
|
for(j = 0; j < row.GetCount(); j++) {
|
|
Size& sz = ln.cell[j].size;
|
|
const TableCell& cell = row[j];
|
|
sz.cy = cell.GetHeight(zoom, sz.cx);
|
|
if(yl && !ln.span && j < yl->GetCount())
|
|
sz.cy -= (*yl)[j];
|
|
ln.height = max(ln.height, ln.cell[j].span ? 0 : sz.cy);
|
|
ln.cell[j].spanh = sz.cy;
|
|
ln.cell[j].paint = true;
|
|
if(cell.IsKeep()) ln.keep = true;
|
|
}
|
|
return ln;
|
|
}
|
|
|
|
bool Table::KeepLine(int i) const {
|
|
const Array<TableCell>& row = cell[i];
|
|
for(i = 0; i < row.GetCount(); i++)
|
|
if(row[i].IsKeep()) return true;
|
|
return false;
|
|
}
|
|
|
|
void Table::DrawLine(int zoom, Draw& w, int x, int y, int i, const Line& ln,
|
|
int ymax, Vector<int> *yl) const {
|
|
const Array<TableCell>& row = cell[i];
|
|
x += DocZoom(zoom, GetLm()) + DocZoomLn(zoom, GetFrameWidth());
|
|
if(yl) yl->SetCount(row.GetCount(), 0);
|
|
for(int j = 0; j < row.GetCount(); j++) {
|
|
const TableCell& cell = row[j];
|
|
const Cell& cl = ln.cell[j];
|
|
Size sz = cl.size;
|
|
if(cl.paint) {
|
|
TableCell::PaintInfo pi;
|
|
int h = cl.span ? cl.spanh : ln.height;
|
|
if(yl) {
|
|
pi.yl = (*yl)[j];
|
|
if(ymax - y >= 0)
|
|
h = min(ymax - y, h);
|
|
}
|
|
cell.Paint(zoom, w, x, y, sz.cx, h, sz.cy, GetFrameColor(), pi);
|
|
if(yl) (*yl)[j] = pi.yl;
|
|
}
|
|
x += sz.cx;
|
|
}
|
|
}
|
|
|
|
void Table::PaintLines(int zoom, Draw& w, int x, int& y, int i, const Vector<Line>& line,
|
|
Vector<int> *yl) const {
|
|
for(int j = line.GetCount() - 1; j >= 0; j--) {
|
|
y -= line[j].height;
|
|
DrawLine(zoom, w, x, y, i + j, line[j], INT_MAX, j == 0 ? yl : NULL);
|
|
}
|
|
}
|
|
|
|
void Table::FrameTab(int zoom, Draw& w, bool was, int x, int y, int yp, int cx) const {
|
|
if(!was) return;
|
|
DrawFatFrame(w, x + DocZoom(zoom, GetLm()), yp,
|
|
cx - DocZoom(zoom, GetLm()) - DocZoom(zoom, GetRm()) -
|
|
(zoom < 1024) * DocZoom(zoom, GetFrameWidth()),
|
|
y - yp + (zoom >= 1024) * DocZoom(zoom, GetFrameWidth()),
|
|
GetFrameColor(), DocZoomLn(zoom, GetFrameWidth()));
|
|
}
|
|
|
|
int Table::Span(Vector<Line>& line) const {
|
|
int hg = 0;
|
|
for(int i = 0; i < line.GetCount(); i++) {
|
|
Line& ln = line[i];
|
|
int x = 0;
|
|
for(int j = 0; j < ln.cell.GetCount(); j++) {
|
|
Cell& cell = ln.cell[j];
|
|
if(cell.span) {
|
|
int k;
|
|
int h = 0;
|
|
int m = min(cell.span + i, line.GetCount());
|
|
for(k = i; k < m; k++) {
|
|
Line& ln = line[k];
|
|
h += ln.height;
|
|
}
|
|
if(h > cell.spanh)
|
|
cell.spanh = h;
|
|
else
|
|
line[m - 1].height += cell.spanh - h;
|
|
for(k = i + 1; k < m; k++) {
|
|
int xx = 0;
|
|
Line& ln = line[k];
|
|
for(int j = 0; j < ln.cell.GetCount() && xx <= x; j++) {
|
|
Cell& cll = ln.cell[j];
|
|
if(xx == x && cell.size.cx == cll.size.cx)
|
|
cll.paint = false;
|
|
xx += cll.size.cx;
|
|
}
|
|
}
|
|
cell.paint = true;
|
|
}
|
|
x += cell.size.cx;
|
|
}
|
|
hg += ln.height;
|
|
}
|
|
return hg;
|
|
}
|
|
|
|
bool Table::Paint(int zoom, Draw& w, int x, int y, int cx, int ymax, PaintInfo& pi) const {
|
|
int j;
|
|
Vector<Line> header;
|
|
int zfw = DocZoomLn(zoom, GetFrameWidth());
|
|
int tcx = cx - 2 * zfw - DocZoom(zoom, GetLm()) - DocZoom(zoom, GetRm());
|
|
bool breakpage = pi.line != pi.oline;
|
|
int pgcy = ymax - y;
|
|
pi.oline = pi.line;
|
|
if(pi.line) {
|
|
int m = min(GetHeaderRows(), cell.GetCount());
|
|
for(j = 0; j < m; j++)
|
|
header.Add() = GetLine(zoom, j, tcx, NULL);
|
|
}
|
|
int hdrcy = Span(header);
|
|
if(hdrcy > ymax - y) {
|
|
header.Clear();
|
|
hdrcy = 0;
|
|
}
|
|
int hg = hdrcy;
|
|
int yp = y;
|
|
y += zfw;
|
|
bool was = false;
|
|
if(y >= ymax) {
|
|
pi.ypos = y;
|
|
return true;
|
|
}
|
|
while(pi.line < GetRows() && y < ymax) {
|
|
Vector<Line> line;
|
|
Vector<int> *yl = &pi.yl;
|
|
int span = 0;
|
|
bool nospan = true;
|
|
for(;;) {
|
|
int k = pi.line + line.GetCount();
|
|
if(k >= GetRows() || line.GetCount() && !KeepLine(k) && span <= 0)
|
|
break;
|
|
span = max((line.Add() = GetLine(zoom, k, tcx, yl)).span, span);
|
|
if(span) nospan = false;
|
|
yl = NULL;
|
|
span--;
|
|
}
|
|
hg += Span(line);
|
|
int lhg = line.Top().height;
|
|
if(hg + y + zfw > ymax) {
|
|
if((!breakpage ||
|
|
lhg > style.breakcy && ymax - (y + hg - lhg) - zfw > style.breakpgcy)
|
|
&& nospan && line.GetCount() && hg + y + zfw - lhg <= ymax) {
|
|
int yy = y + hdrcy;
|
|
PaintLines(zoom, w, x, yy, 0, header, 0);
|
|
yy = y + hdrcy;
|
|
int i;
|
|
for(i = 0; i < line.GetCount() - 1; i++) {
|
|
DrawLine(zoom, w, x, yy, pi.line++, line[i], ymax, NULL);
|
|
yy += line[i].height;
|
|
}
|
|
DrawLine(zoom, w, x, yy, pi.line, line[i], ymax, &pi.yl);
|
|
breakpage = was = true;
|
|
y = ymax;
|
|
}
|
|
if(breakpage) {
|
|
FrameTab(zoom, w, was, x, y, yp, cx);
|
|
pi.ypos = y;
|
|
return true;
|
|
}
|
|
}
|
|
y += hg;
|
|
int yy = y;
|
|
PaintLines(zoom, w, x, yy, pi.line, line, &pi.yl);
|
|
PaintLines(zoom, w, x, yy, 0, header, 0);
|
|
pi.yl.Clear();
|
|
header.Clear();
|
|
hg = 0;
|
|
breakpage = was = true;
|
|
pi.line += line.GetCount();
|
|
}
|
|
FrameTab(zoom, w, was, x, y, yp, cx);
|
|
pi.ypos = y + zfw;
|
|
return false;
|
|
}
|
|
|
|
int Table::Paint(int zoom, Draw& w, int x, int y, int cx) const {
|
|
PaintInfo pi;
|
|
Paint(zoom, w, x, y, cx, INT_MAX, pi);
|
|
return pi.ypos;
|
|
}
|
|
|
|
bool Table::Paint(Draw& w, int x, int y, int cx, int ymax, PaintInfo& pi) const {
|
|
return Paint(1024, w, x, y, cx, ymax, pi);
|
|
}
|
|
|
|
int Table::Paint(Draw& w, int x, int y, int cx) const {
|
|
return Paint(1024, w, x, y, cx);
|
|
}
|
|
|
|
int Table::GetHeight(int zoom, int cx) const {
|
|
int cy = 0;
|
|
int ln = 0;
|
|
cx -= DocZoomLn(zoom, GetFrameWidth()) + DocZoomLn(zoom, GetFrameWidth()) +
|
|
DocZoom(zoom, GetLm()) + DocZoom(zoom, GetRm());
|
|
cy += 2 * DocZoomLn(zoom, GetFrameWidth());
|
|
while(ln < GetRows()) {
|
|
Vector<Line> line;
|
|
int span = 0;
|
|
for(;;) {
|
|
int k = ln + line.GetCount();
|
|
if(ln + line.GetCount() >= GetRows() ||
|
|
line.GetCount() && !KeepLine(k) && span <= 0)
|
|
break;
|
|
span = max((line.Add() = GetLine(zoom, k, cx, NULL)).span, span);
|
|
span--;
|
|
}
|
|
cy += Span(line);
|
|
ln += line.GetCount();
|
|
}
|
|
return cy;
|
|
}
|
|
|
|
void Table::RectLine(int zoom, Draw& w, int x, int y, int i, const Line& ln,
|
|
Vector<ValueRect>& vr) const {
|
|
const Array<TableCell>& row = cell[i];
|
|
x += DocZoom(zoom, GetLm()) + DocZoomLn(zoom, GetFrameWidth());
|
|
for(int j = 0; j < row.GetCount(); j++) {
|
|
const TableCell& cell = row[j];
|
|
const Cell& cl = ln.cell[j];
|
|
Size sz = cl.size;
|
|
if(cl.paint) {
|
|
int h = cl.span ? cl.spanh : ln.height;
|
|
cell.GetValueRects(zoom, w, x, y, sz.cx, h, sz.cy, vr);
|
|
}
|
|
x += sz.cx;
|
|
}
|
|
}
|
|
|
|
void Table::RectLines(int zoom, Draw& w, int x, int y, int i, const Vector<Line>& line,
|
|
Vector<ValueRect>& vr) const {
|
|
for(int j = line.GetCount() - 1; j >= 0; j--) {
|
|
y -= line[j].height;
|
|
RectLine(zoom, w, x, y, i + j, line[j], vr);
|
|
}
|
|
}
|
|
|
|
void Table::GetValueRects(int zoom, Draw& w, int x, int& y, int cx, Vector<ValueRect>& vr)
|
|
const {
|
|
int zfw = DocZoomLn(zoom, GetFrameWidth());
|
|
int li = 0;
|
|
cx -= 2 * zfw + DocZoom(zoom, GetLm()) + DocZoom(zoom, GetRm());
|
|
y += zfw;
|
|
while(li < GetRows()) {
|
|
Vector<Line> line;
|
|
int span = 0;
|
|
for(;;) {
|
|
int k = li + line.GetCount();
|
|
if(k >= GetRows() || line.GetCount() && !KeepLine(k) && span <= 0)
|
|
break;
|
|
span = max((line.Add() = GetLine(zoom, k, cx, NULL)).span, span);
|
|
span--;
|
|
}
|
|
y += Span(line);
|
|
RectLines(zoom, w, x, y, li, line, vr);
|
|
li += line.GetCount();
|
|
}
|
|
y += zfw;
|
|
}
|
|
|
|
int Table::GetHeight(int cx) const {
|
|
return GetHeight(1024, cx);
|
|
}
|
|
|
|
int Table::GetWidth(int zoom) const {
|
|
int cx = 0;
|
|
for(int i = 0; i < GetRows(); i++) {
|
|
const Array<TableCell>& row = cell[i];
|
|
int x = 0;
|
|
for(int j = 0; j < row.GetCount(); j++)
|
|
x = max(x, row[j].GetWidth(zoom) / row[j].GetRatio());
|
|
cx = max(cx, x * GetTotalRatio(row));
|
|
}
|
|
return cx + 2 * GetFrameWidth();
|
|
}
|
|
|
|
END_UPP_NAMESPACE
|