ultimatepp/uppsrc/RichText/TableCell.cpp
cxl 68c48f897e RichText: Header/Footer now can be defined for NEXT page, without breaking the page
git-svn-id: svn://ultimatepp.org/upp/trunk@10854 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2017-02-15 20:42:19 +00:00

253 lines
7.2 KiB
C++

#include "RichText.h"
namespace Upp {
int LineZoom(Zoom z, int a)
{
return a ? max(1, z * a) : 0;
}
RichCell::Format::Format()
{
margin.left = margin.right = 25;
margin.top = margin.bottom = 15;
border.Clear();
align = ALIGN_CENTER;
color = White;
bordercolor = Black;
keep = round = false;
minheight = 0;
}
void RichCell::ClearText()
{
text.Clear();
RichPara h;
text.Cat(h, RichStyles());
}
void RichCell::ClearText(const RichPara::Format& format, const RichStyles& style)
{
text.Clear();
RichPara h;
h.format = format;
text.Cat(h, style);
}
void RichCell::Clear()
{
format = Format();
vspan = hspan = 0;
ClearText();
}
bool RichCell::Reduce(RichContext& rc) const
{
Rect br = rc.page;
rc.page.top += format.margin.top + format.border.top;
rc.page.bottom -= format.margin.bottom + format.border.bottom;
rc.page.left += format.margin.left + format.border.left;
rc.page.right -= format.margin.right + format.border.right;
if(rc.page.IsEmpty()) {
rc.page = br;
return false;
}
return true;
}
PageY RichCell::GetTop(RichContext rc) const
{
if(!Reduce(rc))
return rc.py;
rc.py.y += format.margin.top + format.border.top;
return text.GetTop(rc);
}
PageY RichCell::GetHeight(RichContext rc) const
{
if(Reduce(rc)) {
PageY py = rc.py;
rc.py.y += format.margin.top + format.border.top;
rc.py = text.GetHeight(rc);
rc.py.y += format.margin.bottom + format.border.bottom;
py.y += format.margin.top + format.border.top +
format.minheight +
format.margin.bottom + format.border.bottom;
return py.y <= rc.page.bottom && py > rc.py ? py : rc.py;
}
else {
rc.py.y += format.margin.top + format.border.top;
rc.py.y += 80;
rc.py.y += format.margin.bottom + format.border.bottom;
if(rc.py.y >= rc.page.bottom) {
rc.Page();
rc.py.y += 80;
}
}
return rc.py;
}
void DrawRoundCorner(Draw& w, int x, int y, int rx1, int ry1, int rx2, int ry2, Color color)
{
if(rx1 == rx2 || ry1 == ry2) {
w.DrawRect(Rect(x + rx1, y + ry1, x, y + ry2).Normalized(), color);
w.DrawRect(Rect(x + rx1, y + ry1, x + rx2, y).Normalized(), color);
return;
}
int steps = max(rx1, ry1, 1000);
Vector<Point> vertex;
for(int i = 0; i <= steps; i++) {
double angle = M_PI / 2 * i / steps;
vertex.Add() = Point(int(rx1 * sin(angle) + x), int(ry1 * cos(angle) + y));
}
for(int i = steps; i >= 0; i--) {
double angle = M_PI / 2 * i / steps;
vertex.Add() = Point(int(rx2 * sin(angle) + x), int(ry2 * cos(angle) + y));
}
w.DrawPolygon(vertex, color);
}
void DrawCellBorder(Draw& w, const Rect& rect, const Rect& border, const Rect& margin,
Color color, bool round)
{
Rect fb = border + margin;
int h = rect.GetHeight() - fb.top - fb.bottom;
int y = rect.top + border.top + margin.top;
int v = rect.GetWidth() - fb.left - fb.right;
int x = rect.left + border.left + margin.left;
if(h > 0 && v > 0 && round) {
DrawRoundCorner(w, rect.left + fb.left, rect.top + fb.top,
-fb.left, -fb.top, -margin.left, -margin.top, color);
DrawRoundCorner(w, rect.right - fb.right, rect.top + fb.top,
fb.right, -fb.top, margin.right, -margin.top, color);
DrawRoundCorner(w, rect.left + fb.left, rect.bottom - fb.bottom,
-fb.left, fb.bottom, -margin.left, margin.bottom, color);
DrawRoundCorner(w, rect.right - fb.right, rect.bottom - fb.bottom,
fb.right, fb.bottom, margin.right, margin.bottom, color);
}
else {
y = rect.top;
x = rect.left;
h = rect.GetHeight();
v = rect.GetWidth();
}
w.DrawRect(rect.left, y, border.left, h, color);
w.DrawRect(rect.right - border.right, y, border.right, h, color);
w.DrawRect(x, rect.top, v, border.top, color);
w.DrawRect(x, rect.bottom - border.bottom, v, border.bottom, color);
}
void RichCell::DrawCell(Draw& w, int l, int r, int y, int yy, const Rect& border, const Rect& margin) const
{
w.DrawRect(l + border.left, y + border.top,
r - l - border.left - border.right, yy - y - border.top - border.bottom,
format.color);
DrawCellBorder(w, Rect(l, y, r, yy), border, margin, format.bordercolor, format.round);
// w.DrawRect(l, y, r - l, border.top, format.bordercolor);
// w.DrawRect(l, y, border.left, yy - y, format.bordercolor);
// w.DrawRect(r - border.right, y, border.right, yy - y, format.bordercolor);
// w.DrawRect(l, yy - border.bottom, r - l, border.bottom, format.bordercolor);
}
PageY RichCell::Align(const RichContext& rc, PageY npy) const
{
PageY y = rc.py;
y.y += format.margin.top + format.border.top;
if(rc.py.page == npy.page) {
int dx = npy.y - text.GetHeight(rc).y
- format.margin.top - format.border.top
- format.margin.bottom - format.border.bottom;
if(format.align == ALIGN_CENTER)
y.y += dx / 2;
else
if(format.align == ALIGN_BOTTOM)
y.y += dx;
}
return y;
}
void RichCell::Paint(PageDraw& pw, RichContext rc, PageY npy,
const Rect& xpg, const Rect& nxpg,
int y, int ny, const PaintInfo& pi, bool select) const
{
if(!Reduce(rc))
return;
Rect border(LineZoom(pi.zoom, format.border.left), LineZoom(pi.zoom, format.border.top),
LineZoom(pi.zoom, format.border.right), LineZoom(pi.zoom, format.border.bottom));
Rect margin(LineZoom(pi.zoom, format.margin.left), LineZoom(pi.zoom, format.margin.top),
LineZoom(pi.zoom, format.margin.right), LineZoom(pi.zoom, format.margin.bottom));
if(rc.py.page == npy.page)
DrawCell(pw.Page(rc.py.page), xpg.left, xpg.right, y, ny, border, margin);
else {
DrawCell(pw.Page(rc.py.page), xpg.left, xpg.right, y, xpg.bottom, border, margin);
for(int i = rc.py.page + 1; i < npy.page; i++)
DrawCell(pw.Page(i), nxpg.left, nxpg.right, nxpg.top, nxpg.bottom, border, margin);
DrawCell(pw.Page(npy.page), nxpg.left, nxpg.right, nxpg.top, ny, border, margin);
}
rc.py = Align(rc, npy);
text.Paint(pw, rc, pi);
if(select) {
int cx = xpg.right - xpg.left;
if(rc.py.page == npy.page)
pw.Page(rc.py.page).DrawRect(xpg.left, y, cx, ny - y, InvertColor);
else {
pw.Page(rc.py.page).DrawRect(xpg.left, y, cx, xpg.bottom - y, InvertColor);
for(int i = rc.py.page + 1; i < npy.page; i++)
pw.Page(i).DrawRect(nxpg.left, nxpg.top, cx, nxpg.Height(), InvertColor);
pw.Page(npy.page).DrawRect(nxpg.left, nxpg.top, cx, ny - nxpg.top, InvertColor);
}
}
}
RichCaret RichCell::GetCaret(int pos, RichContext rc, PageY pyy) const
{
if(!Reduce(rc))
return RichCaret();
rc.py = Align(rc, pyy);
return text.GetCaret(pos, rc);
}
int RichCell::GetPos(int x, PageY y, RichContext rc, PageY pyy) const
{
if(!Reduce(rc))
return 0;
rc.py = Align(rc, pyy);
return text.GetPos(x, y, rc);
}
RichHotPos RichCell::GetHotPos(int x, PageY y, int tolerance, RichContext rc, PageY pyy) const
{
if(!Reduce(rc))
return RichHotPos();
rc.py = Align(rc, pyy);
return text.GetHotPos(x, y, tolerance, rc);
}
void RichCell::GatherValPos(Vector<RichValPos>& f, RichContext rc, PageY pyy, int pos, int type) const
{
if(!Reduce(rc))
return;
rc.py = Align(rc, pyy);
text.GatherValPos(f, rc, pos, type);
}
RichCell::RichCell()
{
vspan = hspan = 0;
Clear();
}
RichCell::RichCell(const RichCell& src, int)
{
format = src.format;
hspan = src.hspan;
vspan = src.vspan;
text <<= src.text;
}
}