#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& 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& c = cell.DoIndex(i); int n = c.GetCount(); if(n <= j) { c.SetCount(j + 1); Array& 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& 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& 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 *yl) const { Line ln; const Array& 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& 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 *yl) const { const Array& 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, Vector *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) 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 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; Vector *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; 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& vr) const { const Array& 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, Vector& 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& 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; 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& 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