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
This commit is contained in:
cxl 2017-02-15 20:42:19 +00:00
parent 7f73bb3714
commit beab1177bd
11 changed files with 493 additions and 417 deletions

View file

@ -29,10 +29,15 @@ RichText& GetHeaderFooterText(RichText *text, int page, int pagecount)
return *text;
}
void RichContext::NewHeaderFooter(RichText *header_, RichText *footer_)
RichContext::RichContext(const RichStyles& styles, const RichText *text)
: text(text), styles(&styles)
{
header_cy = footer_cy = 0;
current_header_cy = current_footer_cy = 0;
}
void RichContext::HeaderFooter(RichText *header_, RichText *footer_)
{
page.top -= header_cy;
page.bottom += footer_cy;
header = header_;
footer = footer_;
int cx = page.GetWidth();
@ -43,8 +48,36 @@ void RichContext::NewHeaderFooter(RichText *header_, RichText *footer_)
maxcy = maxcy * 4 / 5;
if(header_cy + footer_cy > maxcy)
header_cy = footer_cy = 0;
page.top += header_cy;
page.bottom -= footer_cy;
}
void RichContext::AdjustPage()
{
page.top += header_cy - current_header_cy;
page.bottom -= footer_cy - current_footer_cy;
current_header_cy = header_cy;
current_footer_cy = footer_cy;
}
void RichContext::Set(PageY p0, const Rect& first_page, const Rect& next_page, PageY p)
{ // table layout helper, real hdr/ftr is irrelevant, need correct page.top / page.bottom
current_header_cy = current_footer_cy = 0;
if(p.page != p0.page) { // we are already on next page
page = next_page;
header_cy = footer_cy = 0;
}
else {
page = first_page;
header_cy = next_page.top - page.top;
footer_cy = page.bottom - next_page.bottom;
}
py = p;
}
void RichContext::Page()
{
py.page++;
AdjustPage();
py.y = page.top;
}
RichContext RichText::Context(const Rect& page, PageY py, RichText *header, RichText *footer) const
@ -52,7 +85,8 @@ RichContext RichText::Context(const Rect& page, PageY py, RichText *header, Rich
RichContext rc(style, this);
rc.page = page;
rc.py = py;
rc.NewHeaderFooter(header, footer);
rc.HeaderFooter(header, footer);
rc.AdjustPage();
if(rc.py.y < rc.page.top)
rc.py.y = rc.page.top;
return rc;

View file

@ -265,11 +265,11 @@ struct RichPara {
void GetRichPos(RichPos& rp, int pos) const;
Lines FormatLines(int cx) const;
void Paint(PageDraw& pw, const Rect& page, PageY py, const PaintInfo& pi, const Number& n, const Bits& spellerror, bool baselevel) const;
RichCaret GetCaret(int pos, const Rect& page, PageY py) const;
int GetPos(int x, PageY y, const Rect& page, PageY py) const;
void GatherLabels(Vector<RichValPos>& info, const Rect& page, PageY py, int pos) const;
void GatherIndexes(Vector<RichValPos>& info, const Rect& page, PageY py, int pos) const;
void Paint(PageDraw& pw, RichContext rc, const PaintInfo& pi, const Number& n, const Bits& spellerror, bool baselevel) const;
RichCaret GetCaret(int pos, RichContext rc) const;
int GetPos(int x, PageY y, RichContext rc) const;
void GatherLabels(Vector<RichValPos>& info, RichContext rc, int pos) const;
void GatherIndexes(Vector<RichValPos>& info, RichContext rc, int pos) const;
int GetVertMove(int pos, int gx, const Rect& page, int dir) const;
WString GetText() const;
@ -296,8 +296,8 @@ struct RichPara {
private:
Tab GetNextTab(int pos, int cx) const;
void Smh(Lines& lines, HeightInfo *th, int cx) const;
Lines Begin(const Rect& page, PageY& py) const;
bool BreaksPage(PageY py, const Lines& pl, int i, const Rect& page) const;
Lines Begin(RichContext& rc) const;
bool BreaksPage(const RichContext& rc, const Lines& pl, int i) const;
void PackParts(Stream& out, const CharFormat& chrstyle,
const Array<Part>& part, CharFormat& cf,
Array<RichObject>& obj) const;

View file

@ -4,28 +4,12 @@ namespace Upp {
#define IMAGECLASS RichTextImg
#define IMAGEFILE <RichText/RichText.iml>
#include <Draw/iml.h>
#include <Draw/iml_source.h>
RichPara::Lines RichPara::Begin(const Rect& page, PageY& py) const
RichPara::Lines RichPara::Begin(RichContext& rc) const
{
Lines pl = FormatLines(page.Width());
#if 0 // pagination logic moved to RichTxt
int cy = format.ruler + format.before;
if(format.keep || format.keepnext)
cy += pl.BodyHeight();
else
cy += pl[0].Sum();
int after = format.after;
if(!format.keepnext)
nbefore = nline = after = 0;
if(page.Height() < 32000 &&
(format.newpage || py.y + cy + after + nbefore + nline > page.bottom && cy < page.Height() ||
format.header_qtf.GetCount() + format.footer_qtf.GetCount()/* && rc.level == 0*/)) {
py.page++;
py.y = page.top;
}
#endif
py.y += format.before + format.ruler;
Lines pl = FormatLines(rc.page.Width());
rc.py.y += format.before + format.ruler;
pl.Justify(format);
return pl;
}
@ -122,14 +106,14 @@ void RichPara::Flush(Draw& draw, const PaintInfo& pi, wchar *text,
}
}
bool RichPara::BreaksPage(PageY py, const Lines& pl, int i, const Rect& page) const
bool RichPara::BreaksPage(const RichContext& rc, const Lines& pl, int i) const
{
int linecy = pl[i].Sum();
if(linecy >= page.Height()) return false;
if(linecy + py.y > page.bottom)
if(linecy >= rc.page.Height()) return false;
if(linecy + rc.py.y > rc.page.bottom)
return true;
if(format.orphan || pl.GetCount() < 2) return false;
if((i == 0 || i == pl.GetCount() - 2) && py.y + linecy + pl[i + 1].Sum() > page.bottom)
if((i == 0 || i == pl.GetCount() - 2) && rc.py.y + linecy + pl[i + 1].Sum() > rc.page.bottom)
return true;
return false;
}
@ -157,11 +141,6 @@ String RichObjectImageMaker::Key() const
Image RichObjectImageMaker::Make() const
{
return object.ToImage(sz, context);
/* ImageDraw iw(sz);
iw.DrawRect(sz, SColorPaper());
object.Paint(iw, sz, context);
return iw;
*/
}
void RichPara::DrawRuler(Draw& w, int x, int y, int cx, int cy, Color ink, int style)
@ -183,67 +162,69 @@ void RichPara::DrawRuler(Draw& w, int x, int y, int cx, int cy, Color ink, int s
}
}
void RichPara::Paint(PageDraw& pw, const Rect& page, PageY py, const PaintInfo& pi,
void RichPara::Paint(PageDraw& pw, RichContext rc, const PaintInfo& pi,
const Number& n, const Bits& spellerror, bool baselevel) const
{
Zoom z = pi.zoom;
PageY opy = py;
Lines pl = Begin(page, py);
PageY opy = rc.py;
Lines pl = Begin(rc);
if(pw.tracer) {
PageY h = py;
PageY h = rc.py;
h.y -= format.before + format.ruler;
pw.tracer->Paragraph(page, h, *this);
pw.tracer->Paragraph(rc.page, h, *this);
}
bool highlight = pi.highlightpara >= 0 && pi.highlightpara < pl.len;
int hy = py.y - format.before - format.ruler;
int phy = py.page;
if(format.ruler && hy >= 0 && hy + format.ruler < page.bottom)
DrawRuler(pw.Page(phy), z * page.left + z * format.lm, z * hy,
z * page.right - z * page.left - z * format.rm - z * format.lm,
int hy = rc.py.y - format.before - format.ruler;
int phy = rc.py.page;
if(format.ruler && hy >= 0 && hy + format.ruler < rc.page.bottom)
DrawRuler(pw.Page(phy), z * rc.page.left + z * format.lm, z * hy,
z * rc.page.right - z * rc.page.left - z * format.rm - z * format.lm,
max(1, z * format.ruler), format.rulerink, format.rulerstyle);
if(pi.sell < 0 && pi.selh > 0)
for(int p = opy.page; p <= py.page; p++) {
int top = z * (p == opy.page ? opy.y : page.top);
int bottom = z * (p == py.page ? py.y : page.bottom);
pw.Page(p).DrawRect(z * page.left, top, z * page.right - z * page.left,
for(int p = opy.page; p <= rc.py.page; p++) {
int top = z * (p == opy.page ? opy.y : rc.page.top);
int bottom = z * (p == rc.py.page ? rc.py.y : rc.page.bottom);
pw.Page(p).DrawRect(z * rc.page.left, top, z * rc.page.right - z * rc.page.left,
bottom - top, InvertColor);
}
opy = py;
opy = rc.py;
int oi = 0;
int x = 0;
int y0 = 0;
int lineascent = 0;
PageY mpy;
int mla = Null;
for(int lni = 0; lni < pl.GetCount(); lni++) {
const Line& li = pl[lni];
int linecy = li.Sum();
lineascent = li.ascent;
if(BreaksPage(py, pl, lni, page)) {
if(BreaksPage(rc, pl, lni)) {
if(li.ppos > pi.sell && li.ppos < pi.selh) {
int y = z * py.y;
pw.Page(py.page).DrawRect(z * page.left, y, z * page.right - z * page.left,
z * page.bottom - y, InvertColor);
int y = z * rc.py.y;
pw.Page(rc.py.page).DrawRect(z * rc.page.left, y, z * rc.page.right - z * rc.page.left,
z * rc.page.bottom - y, InvertColor);
}
py.y = page.top;
py.page++;
rc.Page();
}
if(py > pi.bottom)
if(rc.py > pi.bottom)
break;
if(lni == 0 && format.label.GetCount() && !IsNull(pi.showcodes) && pi.showlabels)
pw.Page(py.page).DrawImage(z * page.left - 12, z * (py.y + (lineascent - 7) / 2),
RichTextImg::Label(), pi.showcodes);
if(lni == 0) {
mpy = rc.py;
mla = lineascent;
}
const CharFormat **cf = pl.format + li.pos;
const CharFormat **i = cf;
const CharFormat **ilim = i + li.len;
const HeightInfo *hg = pl.height + li.pos;
if(py + linecy >= pi.top) {
Draw& draw = pw.Page(py.page);
if(rc.py + linecy >= pi.top) {
Draw& draw = pw.Page(rc.py.page);
#ifdef _DEBUG
int cloff = draw.GetCloffLevel();
#endif
Buffer<int> wd(li.len);
int x0 = li.xpos + page.left;
int x0 = li.xpos + rc.page.left;
x = x0;
int *w = pl.width + li.pos;
int *wl = w + li.len;
@ -255,17 +236,17 @@ void RichPara::Paint(PageDraw& pw, const Rect& page, PageY py, const PaintInfo&
}
if(highlight)
draw.DrawRect(z * page.left, z * py.y, z * page.Width(),
z * (py.y + linecy) - z * py.y,
draw.DrawRect(z * rc.page.left, z * rc.py.y, z * rc.page.Width(),
z * (rc.py.y + linecy) - z * rc.py.y,
pi.highlight);
const CharFormat **i0 = i;
wchar *text = pl.text + li.pos;
x = x0;
w = pl.width + li.pos;
y0 = py.y + li.ascent;
y0 = rc.py.y + li.ascent;
int pp = li.pos;
int l = page.right;
int l = rc.page.right;
int h = -1;
while(i < ilim) {
@ -275,7 +256,7 @@ void RichPara::Paint(PageDraw& pw, const Rect& page, PageY py, const PaintInfo&
h = x;
pp++;
if(*i0 != *i || hg->object) {
Flush(draw, pi, text, i0, wd, (int)(i0 - cf),(int)( i - i0), x0, x, y0, py.y, linecy,
Flush(draw, pi, text, i0, wd, (int)(i0 - cf), (int)(i - i0), x0, x, y0, rc.py.y, linecy,
lineascent, z, highlight);
i0 = i;
x0 = x;
@ -285,9 +266,9 @@ void RichPara::Paint(PageDraw& pw, const Rect& page, PageY py, const PaintInfo&
if(o) {
Size sz = z * o.GetSize();
int ix = z * x;
if(pi.shrink_oversized_objects && sz.cx + ix > page.right)
sz.cx = page.right - ix;
draw.DrawRect(ix, z * py.y, sz.cx, z * linecy, (*i)->paper);
if(pi.shrink_oversized_objects && sz.cx + ix > rc.page.right)
sz.cx = rc.page.right - ix;
draw.DrawRect(ix, z * rc.py.y, sz.cx, z * linecy, (*i)->paper);
draw.Clipoff(ix, z * (y0 - hg->ascent), sz.cx, sz.cy);
if(pi.sizetracking)
draw.DrawRect(sz, SColorFace);
@ -316,13 +297,13 @@ void RichPara::Paint(PageDraw& pw, const Rect& page, PageY py, const PaintInfo&
}
}
if(i > i0)
Flush(draw, pi, text, i0, wd, (int)(i0 - cf), (int)(i - i0), x0, x, y0, py.y, linecy,
Flush(draw, pi, text, i0, wd, (int)(i0 - cf), (int)(i - i0), x0, x, y0, rc.py.y, linecy,
lineascent, z, highlight);
if(lni == 0) {
Rect r;
r.left = page.left + format.lm;
r.left = rc.page.left + format.lm;
int q = li.ascent / 2;
r.top = py.y + 4 * (li.ascent - q) / 5;
r.top = rc.py.y + 4 * (li.ascent - q) / 5;
r.right = r.left + q;
r.bottom = r.top + q;
q = z * (r.Width() / 4);
@ -360,11 +341,11 @@ void RichPara::Paint(PageDraw& pw, const Rect& page, PageY py, const PaintInfo&
}
int zlcy = z * linecy;
if(pi.spellingchecker && zlcy > 3) {
int x = z * (li.xpos + page.left);
int x = z * (li.xpos + rc.page.left);
w = wd;
wl = w + li.len;
int i = li.pos;
int q = z * (py.y + linecy);
int q = z * (rc.py.y + linecy);
while(w < wl) {
if(spellerror[pl.pos[i++]]) {
if(zlcy > 16)
@ -380,12 +361,12 @@ void RichPara::Paint(PageDraw& pw, const Rect& page, PageY py, const PaintInfo&
if(pi.sell == li.ppos + li.plen)
l = x;
if(pi.sell < li.ppos)
l = page.left;
l = rc.page.left;
if(pi.selh > li.ppos + li.plen)
h = page.right;
h = rc.page.right;
if(pi.sell < pi.selh && pi.selh > li.ppos)
draw.DrawRect(z * l, z * py.y, z * h - z * l,
z * (py.y + linecy) - z * py.y, InvertColor);
draw.DrawRect(z * l, z * rc.py.y, z * h - z * l,
z * (rc.py.y + linecy) - z * rc.py.y, InvertColor);
ASSERT(draw.GetCloffLevel() == cloff);
}
else
@ -395,28 +376,42 @@ void RichPara::Paint(PageDraw& pw, const Rect& page, PageY py, const PaintInfo&
i++;
hg++;
}
py.y += linecy;
rc.py.y += linecy;
}
Size sz = RichTextImg::EndParaChar().GetSize();
if(sz.cy < z * lineascent && !IsNull(pi.showcodes))
pw.Page(py.page).DrawImage(z * x, z * y0 - sz.cy,
RichTextImg::EndParaChar(),
format.indexentry.GetCount() ? pi.indexentry : pi.showcodes);
if((format.newpage || format.newhdrftr && baselevel) && !IsNull(pi.showcodes)) {
pw.Page(rc.py.page).DrawImage(z * x, z * y0 - sz.cy,
RichTextImg::EndParaChar(),
format.indexentry.GetCount() ? pi.indexentry : pi.showcodes);
if(format.newpage && !IsNull(pi.showcodes)) {
Draw& w = pw.Page(opy.page);
int wd = z * page.right - z * page.left;
int wd = z * rc.page.right - z * rc.page.left;
int step = w.Pixels() ? 8 : 50;
int y = z * opy.y;
for(int x = 0; x < wd; x += step)
w.DrawRect(z * page.left + x, y, step >> 1, step >> 3, pi.showcodes);
w.DrawRect(z * rc.page.left + x, y, step >> 1, step >> 3, pi.showcodes);
}
if(pl.len >= pi.sell && pl.len < pi.selh && py < pi.bottom) {
int top = z * py.y;
pw.Page(py.page).DrawRect(z * page.left, top, z * page.right - z * page.left,
z * min(py.y + format.after, page.bottom) - top, InvertColor);
if(pl.len >= pi.sell && pl.len < pi.selh && rc.py < pi.bottom) {
int top = z * rc.py.y;
pw.Page(rc.py.page).DrawRect(z * rc.page.left, top, z * rc.page.right - z * rc.page.left,
z * min(rc.py.y + format.after, rc.page.bottom) - top, InvertColor);
}
if(!IsNull(mla) && !IsNull(pi.showcodes) && pi.showlabels) {
bool b = format.label.GetCount();
Image img = RichTextImg::Label();
for(int pass = 0;;pass++) {
Size isz = img.GetSize();
if(b)
pw.Page(mpy.page).DrawImage(-7 - isz.cx, z * mpy.y + (z * mla - isz.cy) / 2,
img, pi.showcodes);
if(pass)
break;
b = format.newhdrftr && baselevel;
img = RichTextImg::HdrFtr();
}
}
if(pw.tracer)
pw.tracer->EndParagraph(py);
pw.tracer->EndParagraph(rc.py);
}
void RichPara::GetRichPos(RichPos& rp, int pos) const
@ -445,9 +440,9 @@ void RichPara::GetRichPos(RichPos& rp, int pos) const
rp.chr = '\n';
}
RichCaret RichPara::GetCaret(int pos, const Rect& page, PageY py) const
RichCaret RichPara::GetCaret(int pos, RichContext rc) const
{
Lines pl = Begin(page, py);
Lines pl = Begin(rc);
RichCaret pr;
FontInfo fi = format.Info();
pr.caretascent = fi.GetAscent();
@ -455,13 +450,11 @@ RichCaret RichPara::GetCaret(int pos, const Rect& page, PageY py) const
for(int lni = 0; lni < pl.GetCount(); lni++) {
Line& li = pl[lni];
int linecy = li.Sum();
if(BreaksPage(py, pl, lni, page)) {
py.y = page.top;
py.page++;
}
pr.page = py.page;
pr.top = py.y;
pr.bottom = py.y + linecy;
if(BreaksPage(rc, pl, lni))
rc.Page();
pr.page = rc.py.page;
pr.top = rc.py.y;
pr.bottom = rc.py.y + linecy;
pr.lineascent = li.ascent;
pr.line = lni;
if(pos < li.ppos + li.plen) {
@ -469,7 +462,7 @@ RichCaret RichPara::GetCaret(int pos, const Rect& page, PageY py) const
int *p = pl.pos + li.pos;
const CharFormat **i = pl.format + li.pos;
const HeightInfo *h = pl.height + li.pos;
int x = li.xpos + page.left;
int x = li.xpos + rc.page.left;
if(li.len && *i) {
pr.caretascent = h->ascent;
pr.caretdescent = h->descent;
@ -491,11 +484,11 @@ RichCaret RichPara::GetCaret(int pos, const Rect& page, PageY py) const
pr.caretdescent = min(pr.caretdescent, pr.Height() - pr.lineascent);
return pr;
}
py.y += linecy;
rc.py.y += linecy;
}
const Line& li = pl.line.Top();
pr.left = li.cx + li.xpos + page.left;
pr.right = page.right;
pr.left = li.cx + li.xpos + rc.page.left;
pr.right = rc.page.right;
pr.caretdescent = min(pr.caretdescent, pr.Height() - pr.lineascent);
return pr;
}
@ -514,20 +507,18 @@ int RichPara::PosInLine(int x, const Rect& page, const Lines& pl, int lni) const
return pos < pl.clen ? pl.pos[pos] : pl.len;
}
int RichPara::GetPos(int x, PageY y, const Rect& page, PageY py) const
int RichPara::GetPos(int x, PageY y, RichContext rc) const
{
Lines pl = Begin(page, py);
Lines pl = Begin(rc);
if(pl.len)
for(int lni = 0; lni < pl.GetCount(); lni++) {
const Line& li = pl[lni];
int linecy = li.Sum();
if(BreaksPage(py, pl, lni, page)) {
py.y = page.top;
py.page++;
}
py.y += linecy;
if(y < py || lni == pl.GetCount() - 1)
return PosInLine(x, page, pl, lni);
if(BreaksPage(rc, pl, lni))
rc.Page();
rc.py.y += linecy;
if(y < rc.py || lni == pl.GetCount() - 1)
return PosInLine(x, rc.page, pl, lni);
}
return pl.len;
}
@ -551,35 +542,31 @@ int RichPara::GetVertMove(int pos, int gx, const Rect& page, int dir) const
return PosInLine(gx, page, pl, lni);
}
void RichPara::GatherLabels(Vector<RichValPos>& info, const Rect& page, PageY py, int pos) const
void RichPara::GatherLabels(Vector<RichValPos>& info, RichContext rc, int pos) const
{
Lines pl = Begin(page, py);
Lines pl = Begin(rc);
WString ie;
if(!pl.GetCount())
return;
if(BreaksPage(py, pl, 0, page)) {
py.y = page.top;
py.page++;
}
if(BreaksPage(rc, pl, 0))
rc.Page();
if(format.label.IsEmpty())
return;
RichValPos& f = info.Add();
f.py = py;
f.py = rc.py;
f.pos = pos;
f.data = format.label.ToWString();
}
void RichPara::GatherIndexes(Vector<RichValPos>& info, const Rect& page, PageY py, int pos) const
void RichPara::GatherIndexes(Vector<RichValPos>& info, RichContext rc, int pos) const
{
Lines pl = Begin(page, py);
Lines pl = Begin(rc);
WString ie;
for(int lni = 0; lni < pl.GetCount(); lni++) {
Line& li = pl[lni];
int linecy = li.Sum();
if(BreaksPage(py, pl, lni, page)) {
py.y = page.top;
py.page++;
}
if(BreaksPage(rc, pl, lni))
rc.Page();
const CharFormat **i0 = pl.format + li.pos;
const CharFormat **i = i0;
const CharFormat **ilim = i + li.len;
@ -588,14 +575,14 @@ void RichPara::GatherIndexes(Vector<RichValPos>& info, const Rect& page, PageY
ie = (*i)->indexentry;
if(!ie.IsEmpty()) {
RichValPos& f = info.Add();
f.py = py;
f.py = rc.py;
f.pos = (int)(i - i0) + pos;
f.data = ie;
}
}
i++;
}
py.y += linecy;
rc.py.y += linecy;
}
}

View file

@ -6,6 +6,10 @@
namespace Upp {
#define IMAGECLASS RichTextImg
#define IMAGEFILE <RichText/RichText.iml>
#include <Draw/iml_header.h>
INITIALIZE(RichImage)
class PasteClip;
@ -288,6 +292,28 @@ struct PaintInfo {
int LineZoom(Zoom z, int a);
class RichTable;
class RichText;
struct RichStyle;
typedef ArrayMap<Uuid, RichStyle> RichStyles;
struct RichContext {
const RichText *text;
const RichStyles *styles;
RichText *header, *footer;
int header_cy, footer_cy; // next page header/footer size
int current_header_cy, current_footer_cy; // current header/footer size
Rect page;
PageY py;
void HeaderFooter(RichText *header, RichText *footer_qtf);
void AdjustPage();
void Page();
void Set(PageY p0, const Rect& first_page, const Rect& next_page, PageY p);
RichContext(const RichStyles& styles, const RichText *text);
RichContext() {}
};
#include "Para.h"
@ -357,28 +383,11 @@ struct RichStyle {
RichStyle() { next = GetDefaultId(); }
};
typedef ArrayMap<Uuid, RichStyle> RichStyles;
const RichStyle& GetStyle(const RichStyles& s, const Uuid& id);
int FindStyleWithName(const RichStyles& style, const String& name);
class RichText;
struct RichContext {
const RichText *text;
const RichStyles *styles;
RichText *header, *footer;
int header_cy, footer_cy;
Rect page;
PageY py;
void NewHeaderFooter(RichText *header, RichText *footer_qtf);
void Page() { py.page++; py.y = page.top; }
RichContext(const RichStyles& styles, const RichText *text) : text(text), styles(&styles) { header_cy = footer_cy = 0; }
RichContext() {}
};
struct RichCellPos;
enum {

View file

@ -1,13 +1,14 @@
PREMULTIPLIED
IMAGE_ID(Label)
IMAGE_ID(HdrFtr)
IMAGE_ID(EndParaChar)
IMAGE_ID(TabChar)
IMAGE_ID(SpaceChar)
IMAGE_ID(HardSpaceChar)
IMAGE_BEGIN_DATA
IMAGE_DATA(120,156,149,80,81,10,192,80,8,146,177,183,237,86,221,255,84,173,159,199,42,172,152,208,71,34,42,98,225,134,131,218)
IMAGE_DATA(9,34,148,240,74,120,77,55,233,178,95,204,93,120,208,64,127,114,146,74,237,159,21,205,165,189,110,67,2,119,89,221)
IMAGE_DATA(166,104,94,212,7,250,0,182,32,211,115,255,195,106,52,65,204,244,195,57,207,93,25,85,255,28,90,224,5,200,43,63)
IMAGE_DATA(111,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
IMAGE_END_DATA(128, 5)
IMAGE_DATA(120,156,189,82,91,10,192,48,8,11,99,237,118,43,239,127,42,231,79,153,74,172,251,90,32,148,6,73,210,7,6,46)
IMAGE_DATA(56,168,81,16,161,68,87,162,107,98,55,151,253,98,238,196,205,74,48,130,172,127,128,101,115,142,120,152,202,232,171,38)
IMAGE_DATA(41,116,237,187,34,121,110,65,130,54,173,238,166,104,254,30,62,208,7,176,87,98,243,220,255,176,26,155,32,102,250,226)
IMAGE_DATA(236,175,187,50,170,246,125,104,129,7,42,71,81,107,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
IMAGE_END_DATA(128, 6)

View file

@ -29,7 +29,8 @@ private:
PageY GetTop(RichContext rc) const;
PageY GetHeight(RichContext rc) const;
void Paint(PageDraw& pw, RichContext rc, PageY npy,
const Rect& xpg, int y, int ny, const PaintInfo& pi,
const Rect& xpg, const Rect& nxpg,
int y, int ny, const PaintInfo& pi,
bool select) const;
RichCaret GetCaret(int pos, RichContext rc, PageY pyy) const;
int GetPos(int x, PageY y, RichContext rc, PageY pyy) const;
@ -78,28 +79,30 @@ private:
mutable One<RichText> header, footer;
struct PaintCell : Moveable<PaintCell> {
int left;
int right;
Rect page;
PageY hy;
bool top;
bool bottom;
int left; // left pos with grid
int right; // right pos with grid
int page_left; // left pos without grid (if any)
int page_right; // right pos without grid (if any)
PageY hy; // end of cell
bool top; // this is top cell of vspan (or single cell without vspan)
bool bottom; // this is bottom cell of vspan (or single cell without vspan)
RichContext MakeRichContext(RichContext rc) const;
PaintCell() { top = true; }
};
struct PaintRow : Moveable<PaintRow> {
PageY gpy;
PageY py, pyy;
PageY gpy; // position of grid line (if not first)
PageY py, pyy; //start, end of line
Buffer<PaintCell> cell;
bool first;
bool first; // first row on the page
PaintCell& operator[](int i) { return cell[i]; }
const PaintCell& operator[](int i) const { return cell[i]; }
};
struct Layout {
Buffer<Rect> col;
Buffer<PaintRow> row;
int frame;
int grid;
@ -112,32 +115,36 @@ private:
struct TabLayout : Layout {
bool hasheader;
Layout header;
Rect page;
int page0;
Size sz;
PageY py;
Rect first_page0;
Rect next_page0;
Rect first_page;
Rect next_page;
Rect header_page;
rval_default(TabLayout);
TabLayout() {}
};
mutable TabLayout clayout; // TODO: MT?
mutable Rect cpage;
mutable PageY cpy;
mutable TabLayout clayout;
Buffer< Buffer<CellInfo> > ci;
int r_row, r_column; // r_ - refresh info
Rect r_page;
Rect r_first_page, r_next_page, r_header_page;
PageY r_py, r_pyy;
void Invalidate();
void InvalidateRefresh(int i, int j);
void InvalidateRefresh(Point p) { InvalidateRefresh(p.y, p.x); }
bool Reduce(RichContext& rc) const;
Layout Realize(RichContext rc, int ny) const;
bool RowPaint(PageDraw& pw, const RichStyles& st, const Layout& tab,
int i, int ny, const Rect& pg, VectorMap<int, Rect>& frr,
PaintInfo& pi, int pd, bool sel) const;
bool Reduce(Rect& r) const;
Rect GetPageRect(PageY py) const;
void NextPage(PageY& py, bool header = false) const;
RichContext MakeRichContext(RichContext rc, PageY py, bool header = false) const;
Layout Realize(PageY py, RichContext arc, int ny, bool header) const;
bool RowPaint(PageDraw& pw, RichContext rc, const Layout& tab, bool header,
int i, int ny, Rect pg, Rect npg, VectorMap<int, Rect>& frr,
PaintInfo& pi, int pd, bool sel) const;
const TabLayout& Realize(RichContext rc) const;
@ -185,7 +192,7 @@ private:
PageY GetHeight(RichContext rc) const;
PageY GetTop(RichContext rc) const;
void Paint(PageDraw& pw, RichContext rc, const PaintInfo& pi) const;
void Paint(PageDraw& pw, RichContext rc, const PaintInfo& pi, bool baselevel) const;
RichCaret GetCaret(int pos, RichContext rc) const;
int GetPos(int x, PageY y, RichContext rc) const;
int GetVertMove(int pos, int gx, RichContext rc, int dir) const;

View file

@ -48,9 +48,11 @@ bool RichCell::Reduce(RichContext& rc) const
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())
if(rc.page.IsEmpty()) {
rc.page = br;
return !rc.page.IsEmpty();
return false;
}
return true;
}
PageY RichCell::GetTop(RichContext rc) const
@ -168,7 +170,8 @@ PageY RichCell::Align(const RichContext& rc, PageY npy) const
}
void RichCell::Paint(PageDraw& pw, RichContext rc, PageY npy,
const Rect& xpg, int y, int ny, const PaintInfo& pi, bool select) const
const Rect& xpg, const Rect& nxpg,
int y, int ny, const PaintInfo& pi, bool select) const
{
if(!Reduce(rc))
return;
@ -181,8 +184,8 @@ void RichCell::Paint(PageDraw& pw, RichContext rc, PageY npy,
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), xpg.left, xpg.right, xpg.top, xpg.bottom, border, margin);
DrawCell(pw.Page(npy.page), xpg.left, xpg.right, xpg.top, ny, border, margin);
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);
@ -195,8 +198,8 @@ void RichCell::Paint(PageDraw& pw, RichContext rc, PageY npy,
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(xpg.left, xpg.top, cx, xpg.Height(), InvertColor);
pw.Page(npy.page).DrawRect(xpg.left, xpg.top, cx, ny - xpg.top, InvertColor);
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);
}
}
}
@ -209,7 +212,7 @@ RichCaret RichCell::GetCaret(int pos, RichContext rc, PageY pyy) const
return text.GetCaret(pos, rc);
}
int RichCell::GetPos(int x, PageY y, RichContext rc, PageY pyy) const
int RichCell::GetPos(int x, PageY y, RichContext rc, PageY pyy) const
{
if(!Reduce(rc))
return 0;

View file

@ -4,7 +4,7 @@ namespace Upp {
void RichTable::Invalidate()
{
cpy.page = -1;
clayout.py.page = -1;
length = tabcount = -1;
}
@ -17,9 +17,10 @@ void RichTable::InvalidateRefresh(int i, int j)
if(r_row == -2 && clayout.sz == GetSize()) {
r_row = i;
r_column = j;
r_py = cpy;
r_py = clayout.py;
r_pyy = clayout[min(GetRows() - 1, i + cell[i][j].vspan)].pyy;
r_page = cpage;
r_first_page = clayout.first_page0;
r_next_page = clayout.next_page0;
}
else
r_row = -1;
@ -27,6 +28,24 @@ void RichTable::InvalidateRefresh(int i, int j)
Invalidate();
}
int RichTable::GetInvalid(PageY& top, PageY& bottom, RichContext rc) const
{
if(r_row == -2)
return -1;
const TabLayout& tab = Realize(rc);
RichContext rc2 = rc;
rc2.Page();
if(r_row >= 0 && r_first_page == rc.page && r_next_page == rc2.page
&& r_py == rc.py && tab[min(GetRows() - 1, r_row + cell[r_row][r_column].vspan)].pyy == r_pyy) {
const PaintRow& pr = tab[r_row];
const RichCell& cl = cell[r_row][r_column];
top = pr.py;
bottom = tab[min(cell.GetCount() - 1, r_row + cl.vspan)].pyy;
return 0;
}
return 1;
}
void RichTable::Normalize0()
{
int nx = format.column.GetCount();
@ -245,22 +264,6 @@ void RichTable::Validate()
r_row = -2;
}
int RichTable::GetInvalid(PageY& top, PageY& bottom, RichContext rc) const
{
if(r_row == -2)
return -1;
const TabLayout& tab = Realize(rc);
if(r_row >= 0 && r_page == rc.page
&& r_py == rc.py && tab[min(GetRows() - 1, r_row + cell[r_row][r_column].vspan)].pyy == r_pyy) {
const PaintRow& pr = tab[r_row];
const RichCell& cl = cell[r_row][r_column];
top = pr.py;
bottom = tab[min(cell.GetCount() - 1, r_row + cl.vspan)].pyy;
return 0;
}
return 1;
}
void RichTable::AddColumn(int cx)
{
format.column.Add(cx);
@ -583,7 +586,7 @@ RichTable::RichTable(const RichTable& src, int)
RichTable::RichTable()
{
cpy.page = -1;
clayout.py.page = -1;
r_row = -1;
Invalidate();
}

View file

@ -2,105 +2,135 @@
namespace Upp {
bool RichTable::Reduce(RichContext& rc) const
bool RichTable::Reduce(Rect& r) const
{
Rect br = rc.page;
rc.page.left += format.lm;
rc.page.right -= format.rm;
rc.page.Deflate(format.frame);
if(rc.page.IsEmpty())
rc.page = br;
return !rc.page.IsEmpty();
Rect br = r;
r.left += format.lm;
r.right -= format.rm;
r.Deflate(format.frame);
if(r.IsEmpty()) {
r = br;
return false;
}
return true;
}
Rect RichTable::GetPageRect(PageY py) const
{
return py.page == clayout.py.page ? clayout.first_page : clayout.next_page;
}
void RichTable::NextPage(PageY& py, bool header) const
{
py.y = header ? clayout.header_page.top : clayout.next_page.top;
py.page++;
}
RichContext RichTable::MakeRichContext(RichContext rc, PageY py, bool header) const
{
if(header)
rc.Set(py, clayout.header_page, clayout.header_page, py);
else
rc.Set(clayout.py, clayout.first_page, clayout.next_page, py);
return rc;
}
const RichTable::TabLayout& RichTable::Realize(RichContext rc) const
{ // Create page layout with header
if(rc.py != cpy || rc.page != cpage) {
rc.py.y += format.before;
if(rc.py.y > rc.page.bottom) {
// TODO: header/footer adjustment here
rc.py.y = rc.page.top;
rc.py.page++;
}
cpage = rc.page;
cpy = rc.py;
Reduce(rc);
clayout.page = rc.page;
clayout.hasheader = false;
RichContext rc2 = rc;
rc2.Page();
if(rc.py != clayout.py || rc.page != clayout.first_page0 || rc2.page != clayout.next_page0) {
clayout.sz = GetSize();
clayout.py = rc.py;
clayout.first_page = clayout.first_page0 = rc.page;
clayout.next_page = clayout.next_page0 = rc2.page;
Reduce(clayout.first_page);
Reduce(clayout.next_page);
clayout.header_page = clayout.next_page;
PageY py = rc.py;
py.y += format.before;
if(py.y > clayout.first_page.bottom)
NextPage(py, false);
clayout.hasheader = false;
if(format.header && cell.GetCount()) {
RichContext nextpage_rc = rc;
PageY hpy(0, clayout.next_page.top); // RowPaint will need page zero here to add real page
nextpage_rc.Set(hpy, clayout.next_page, clayout.next_page, hpy);
int hy = min(format.header, cell.GetCount());
RichContext nrc = rc;
nrc.py.page = 0;
nrc.py.y = clayout.page.top;
clayout.header = Realize(nrc, hy); // realize header as if first on page
clayout.header = Realize(hpy, nextpage_rc, hy, true); // realize header as if first on next page
if(clayout.header[0].py.page == clayout.header[hy - 1].pyy.page) { // header fits single page
Layout x = Realize(rc, cell.GetCount());
if(cell.GetCount() > hy && rc.py.page != x[hy].py.page) { // first header would break the end of page
// TODO: header/footer adjustment here
rc.py.page++;
rc.py.y = rc.page.top;
}
Layout x = Realize(py, MakeRichContext(rc, py, false), cell.GetCount(), false); // TODO: check this
if(cell.GetCount() > hy && py.page != x[hy].py.page) // first header would break the end of page
NextPage(py, false);
clayout.hasheader = true; // if it fits, we repeat header on each new page
rc.page.top = clayout.page.top = clayout.header[hy - 1].pyy.y + format.grid; // so have to reduce the page size for nonheader rows
clayout.header_page.bottom = clayout.header[hy - 1].pyy.y;
clayout.next_page.top = clayout.header_page.bottom + format.grid ;// so have to reduce the page size for nonheader rows
}
}
clayout.page0 = rc.py.page;
(Layout&)clayout = Realize(rc, cell.GetCount());
(Layout&)clayout = Realize(py, MakeRichContext(rc, py, false), cell.GetCount(), false);
if(format.keep && cell.GetCount()) {
if(clayout[0].py.page != clayout[cell.GetCount() - 1].pyy.page) {
rc.py.page++;
rc.py.y = rc.page.top;
}
clayout.page0 = rc.py.page;
(Layout&)clayout = Realize(rc, cell.GetCount());
if(clayout[0].py.page != clayout[cell.GetCount() - 1].pyy.page)
NextPage(py, false);
(Layout&)clayout = Realize(py, MakeRichContext(rc, py, false), cell.GetCount(), false);
}
}
return clayout;
}
RichTable::Layout RichTable::Realize(RichContext rc, int ny) const
RichContext RichTable::PaintCell::MakeRichContext(RichContext rc) const
{
rc.page.left = page_left;
rc.page.right = page_right;
return rc;
}
RichTable::Layout RichTable::Realize(PageY py, RichContext arc, int ny, bool header) const
{ // create layout for first ny rows
Layout tab;
int nx = format.column.GetCount();
tab.row.Alloc(ny);
for(int i = 0; i < ny; i++)
tab[i].cell.Alloc(nx);
tab.col.Alloc(nx);
int sum = 0;
for(int i = 0; i < nx; i++)
sum += format.column[i];
Buffer<int> column_left, column_right;
column_left.Alloc(nx);
column_right.Alloc(nx);
int x = 0;
int xx = rc.page.left;
int dcx = rc.page.Width();
int xx = arc.page.left;
int dcx = arc.page.Width();
for(int i = 0; i < nx; i++) {
Rect& cp = tab.col[i];
cp = rc.page;
cp.left = xx;
column_left[i] = xx;
x += format.column[i];
xx = cp.right = x * dcx / sum + rc.page.left;
xx = column_right[i] = x * dcx / sum + arc.page.left;
}
int f2 = format.grid / 2;
int ff2 = format.grid - f2;
rc.py.y += format.frame;
py.y += format.frame;
for(int i = 0; i < ny; i++) {
const Array<RichCell>& row = cell[i];
PaintRow& pr = tab[i];
pr.first = i == 0;
pr.gpy = rc.py;
pr.gpy = py;
if(i)
rc.py.y += format.grid;
py.y += format.grid;
for(int j = 0; j < nx;) {
PaintCell& pc = pr[j];
const RichCell& cell = row[j];
if(pc.top) {
pc.page = tab.col[j];
pc.page.right = tab.col[min(nx - 1, j + cell.hspan)].right;
pc.page_left = pc.left = column_left[j];
pc.page_right = pc.right = column_right[min(nx - 1, j + cell.hspan)];
if(j)
pc.page_left += f2;
if(j + cell.hspan < nx - 1)
pc.page_right -= ff2;
pc.bottom = false;
int ms = min(ny - 1, i + cell.vspan);
for(int k = i + 1; k <= ms; k++) {
@ -108,12 +138,6 @@ RichTable::Layout RichTable::Realize(RichContext rc, int ny) const
pc.top = pc.bottom = false;
}
tab[ms][j].bottom = true;
pc.left = pc.page.left;
pc.right = pc.page.right;
if(j)
pc.page.left += f2;
if(j + cell.hspan < nx - 1)
pc.page.right -= ff2;
}
j += cell.hspan + 1;
}
@ -135,41 +159,40 @@ RichTable::Layout RichTable::Realize(RichContext rc, int ny) const
}
j += cell.hspan + 1;
}
if(!span)
if(!span) // check whether we should break page before this row
for(int j = 0; j < nx;) {
const RichCell& cell = row[j];
PaintCell& pc = pr[j];
if(pc.top) {
rc.page = pc.page;
PageY ty = cell.GetTop(rc);
PageY ky = rc.py;
RichContext trc = pc.MakeRichContext(MakeRichContext(arc, py, header));
PageY ty = cell.GetTop(trc);
PageY ky = py;
if(keep)
ky = cell.GetHeight(rc);
if(ty.page != rc.py.page || ky.page != rc.py.page) {
rc.Page();
pr.gpy = rc.py;
ky = cell.GetHeight(trc);
if(ty.page != py.page || ky.page != py.page) {
NextPage(py, header);
pr.gpy = py;
pr.first = true;
break;
}
}
j += cell.hspan + 1;
}
pr.py = rc.py;
pr.py = py;
for(int j = 0; j < nx;) {
const RichCell& cell = row[j];
PaintCell& pc = pr[j];
rc.page = pc.page;
if(pc.top)
tab[min(ny - 1, i + cell.vspan)][j].hy = cell.GetHeight(rc);
tab[min(ny - 1, i + cell.vspan)][j].hy = cell.GetHeight(pc.MakeRichContext(MakeRichContext(arc, py, header)));
j += cell.hspan + 1;
}
for(int j = 0; j < nx;) {
const RichCell& cell = row[j];
if(pr[j].bottom)
rc.py = max(pr[j].hy, rc.py);
py = max(pr[j].hy, py);
j += cell.hspan + 1;
}
tab.pyy = pr.pyy = rc.py;
tab.pyy = pr.pyy = py;
}
return tab;
}

View file

@ -24,17 +24,15 @@ void RichTable::ExpandFrr(VectorMap<int, Rect>& frr, int pi, int l, int r, int t
fr.bottom = max(fr.bottom, b);
}
bool RichTable::RowPaint(PageDraw& pw, const RichStyles& st, const Layout& tab,
int i, int ny, const Rect& pg, VectorMap<int, Rect>& frr,
bool RichTable::RowPaint(PageDraw& pw, RichContext rc, const Layout& tab, bool header,
int i, int ny, Rect pg, Rect npg,
VectorMap<int, Rect>& frr,
PaintInfo& pi, int pd, bool sel) const
{
RichContext rc(st, NULL);
const Array<RichCell>& row = cell[i];
const PaintRow& pr = tab[i];
rc.py = pr.py;
rc.py.page += pd;
if(pw.tracer)
pw.tracer->TableRow(pg, rc.py, i, *this);
pw.tracer->TableRow(GetPageRect(pr.py), rc.py, i, *this);
int gridln = LineZoom(pi.zoom, format.grid);
int ff2ln = gridln - gridln / 2;
Color gc = format.gridcolor;
@ -42,53 +40,59 @@ bool RichTable::RowPaint(PageDraw& pw, const RichStyles& st, const Layout& tab,
gridln = 1;
gc = pi.showcodes;
}
PageY py = pr.py;
py.page += pd;
if(py.page != clayout.py.page) // We are on the next page already
pg = npg;
for(int j = 0; j < format.column.GetCount();) {
const RichCell& cell = row[j];
const PaintCell& pc = pr[j];
if(pc.top) {
PageY pyy = tab[min(ny - 1, i + cell.vspan)].pyy;
pyy.page += pd;
pyy.page += pd; // move header line
bool paint = pyy > pi.top;
rc.page = pr[j].page;
Rect xpg = pg;
Rect xpg = pg; // on first page
Rect nxpg = npg; // on next page
int y;
int ny = pi.zoom * pyy.y;
y = pi.zoom * pr.gpy.y;
if(j) {
xpg.left = pi.zoom * pc.left - ff2ln;
if(pyy.page == rc.py.page)
pw.Page(rc.py.page).DrawRect(xpg.left, y, gridln, ny - y, gc);
nxpg.left = xpg.left = pi.zoom * pc.left;
xpg.right = pi.zoom * pc.right;
if(j) { // need to draw vertical grid line on the left
nxpg.left = xpg.left = xpg.left - ff2ln; // move half of vertical grid width left
if(py.page == pyy.page)
pw.Page(py.page).DrawRect(xpg.left, y, gridln, ny - y, gc);
else {
pw.Page(rc.py.page).DrawRect(xpg.left, y, gridln, pg.bottom - y, gc);
for(int i = rc.py.page + 1; i < pyy.page; i++)
pw.Page(i).DrawRect(xpg.left, pg.top, gridln, pg.bottom - pg.top, gc);
pw.Page(pyy.page).DrawRect(xpg.left, pg.top, gridln, ny - pg.top, gc);
pw.Page(py.page).DrawRect(xpg.left, y, gridln, pg.bottom - y, gc);
for(int i = py.page + 1; i < pyy.page; i++)
pw.Page(i).DrawRect(nxpg.left, npg.top, gridln, npg.bottom - npg.top, gc);
pw.Page(pyy.page).DrawRect(nxpg.left, npg.top, gridln, ny - npg.top, gc);
}
xpg.left += gridln;
nxpg.left = xpg.left = xpg.left + gridln;
}
if(j + cell.hspan < format.column.GetCount() - 1)
xpg.right = pi.zoom * pc.right - ff2ln;
if(!pr.first) {
y += gridln;
xpg.right = pi.zoom * pc.right - ff2ln; // make place for the next grid line
if(!pr.first) { // Draw horizontal grid line
if(paint)
pw.Page(rc.py.page).DrawRect(xpg.left, y - gridln, xpg.Width(), gridln, gc);
pw.Page(py.page).DrawRect(xpg.left, y, xpg.Width(), gridln, gc);
y += gridln;
}
if(paint) {
if(pw.tracer)
pw.tracer->TableCell(rc.page, rc.py, i, j, *this, pyy);
row[j].Paint(pw, rc, pyy, xpg, y, ny, pi,
row[j].Paint(pw, pc.MakeRichContext(MakeRichContext(rc, py, header)), pyy, xpg, nxpg, y, ny, pi,
sel && j >= pi.cells.left && i >= pi.cells.top &&
j + cell.hspan <= pi.cells.right && i + cell.vspan <= pi.cells.bottom);
if(pw.tracer)
pw.tracer->EndTableCell(pyy);
}
if(pyy.page == rc.py.page)
ExpandFrr(frr, pyy.page, xpg.left, xpg.right, y, ny);
if(pyy.page == py.page)
ExpandFrr(frr, py.page, xpg.left, xpg.right, y, ny);
else {
ExpandFrr(frr, rc.py.page, xpg.left, xpg.right, y, xpg.bottom);
for(int i = rc.py.page + 1; i < pyy.page; i++)
ExpandFrr(frr, i, xpg.left, xpg.right, xpg.top, xpg.bottom);
ExpandFrr(frr, pyy.page, xpg.left, xpg.right, xpg.top, ny);
ExpandFrr(frr, py.page, xpg.left, xpg.right, y, xpg.bottom);
for(int i = py.page + 1; i < pyy.page; i++)
ExpandFrr(frr, i, nxpg.left, nxpg.right, nxpg.top, nxpg.bottom);
ExpandFrr(frr, pyy.page, nxpg.left, nxpg.right, nxpg.top, ny);
}
int l = cell.text.GetLength() + 1;
pi.sell -= l;
@ -102,70 +106,86 @@ bool RichTable::RowPaint(PageDraw& pw, const RichStyles& st, const Layout& tab,
return rc.py >= pi.bottom;
}
void RichTable::Paint(PageDraw& pw, RichContext rc, const PaintInfo& _pi) const
void RichTable::Paint(PageDraw& pw, RichContext rc, const PaintInfo& _pi, bool baselevel) const
{
if(pw.tracer)
pw.tracer->Table(rc.page, rc.py, *this);
const TabLayout& tab = Realize(rc);
if(!tab.page.IsEmpty()) {
PaintInfo pi = _pi;
int frameln = LineZoom(pi.zoom, format.frame);
int gridln = LineZoom(pi.zoom, format.grid);
Rect pg = rc.page;
pg.left += format.lm;
pg.right -= format.rm;
pg.left = pi.zoom * pg.left;
pg.right = pi.zoom * pg.right;
pg.top = pi.zoom * pg.top;
pg.bottom = pi.zoom * pg.bottom;
pg.Deflate(frameln);
int hy = min(format.header, cell.GetCount());
Rect hpg = pg;
PaintInfo pi = _pi;
int frameln = LineZoom(pi.zoom, format.frame);
int gridln = LineZoom(pi.zoom, format.grid);
Rect pg[2];
Rect hpg;
RichContext hrc = rc;
int hy = min(format.header, cell.GetCount());
for(int pass = 0;; pass++) {
Rect& pgr = pg[pass];
pgr = pass ? tab.next_page : tab.first_page;
pgr.left += format.lm;
pgr.right -= format.rm;
pgr.left = pi.zoom * pgr.left;
pgr.right = pi.zoom * pgr.right;
pgr.top = pi.zoom * pgr.top;
pgr.bottom = pi.zoom * pgr.bottom;
pgr.Deflate(LineZoom(pi.zoom, format.frame));
if(pass)
break;
hpg = pgr;
if(tab.hasheader) {
hpg.bottom = pi.zoom * tab.header[hy - 1].pyy.y;
pg.top = hpg.bottom + gridln;
pgr.top = hpg.bottom + LineZoom(pi.zoom, format.grid);
}
bool allsel = false;
if(pi.sell < 0 && pi.selh >= 0) {
pi.sell = pi.selh = 0;
allsel = true;
}
bool sel = pi.tablesel == 0;
int ny = cell.GetCount();
VectorMap<int, Rect> frr;
for(int i = 0; i < ny; i++)
if(RowPaint(pw, *rc.styles, tab, i, ny, pg, frr, pi, 0, sel))
break;
hrc.Page();
}
Color gc = format.gridcolor;
Color fc = format.framecolor;
int fl = frameln;
if(!IsNull(pi.showcodes)) {
if(fl == 0 && !IsNull(pi.showcodes)) {
fl = 1;
fc = pi.showcodes;
}
if(gridln == 0) {
gridln = 1;
gc = pi.showcodes;
}
bool allsel = false;
if(pi.sell < 0 && pi.selh >= 0) {
pi.sell = pi.selh = 0;
allsel = true;
}
bool sel = pi.tablesel == 0;
int ny = cell.GetCount();
if(format.newhdrftr && ny && baselevel) {
Image img = RichTextImg::HdrFtr();
Size isz = img.GetSize();
pw.Page(tab[0].py.page).DrawImage(-7 - isz.cx, pi.zoom * tab[0].py.y, img, pi.showcodes);
}
VectorMap<int, Rect> frr; // page -> table rectangle
for(int i = 0; i < ny; i++)
if(RowPaint(pw, rc, tab, false, i, ny, pg[0], pg[1], frr, pi, 0, sel))
break;
Color gc = format.gridcolor;
Color fc = format.framecolor;
int fl = frameln;
if(!IsNull(pi.showcodes)) {
if(fl == 0 && !IsNull(pi.showcodes)) {
fl = 1;
fc = pi.showcodes;
}
for(int i = 0; i < frr.GetCount(); i++) {
pi.tablesel = 0;
pi.sell = pi.selh = -1;
int pgi = frr.GetKey(i);
Draw& w = pw.Page(pgi);
if(pgi > tab.page0 && tab.hasheader)
for(int i = 0; i < hy; i++) {
RowPaint(pw, *rc.styles, tab.header, i, hy, hpg, frr, pi, pgi, false);
w.DrawRect(pg.left, hpg.bottom, pg.Width(), gridln, format.gridcolor);
}
Rect r = frr[i].Inflated(frameln);
if(!r.IsEmpty()) {
DrawFatFrame(w, r, fc, fl);
if(allsel)
w.DrawRect(r, InvertColor);
if(gridln == 0) {
gridln = 1;
gc = pi.showcodes;
}
}
for(int i = 0; i < frr.GetCount(); i++) { // add headers on subsequent pages and outer border
pi.tablesel = 0;
pi.sell = pi.selh = -1;
int pgi = frr.GetKey(i);
Rect r = frr[i];
if(pgi > tab.py.page && tab.hasheader) // need to paint header here...
for(int i = 0; i < hy; i++) {
RowPaint(pw, rc, tab.header, true, i, hy, hpg, hpg, frr, pi, pgi, false);
pw.Page(pgi).DrawRect(r.left, hpg.bottom, r.Width(), gridln, format.gridcolor);
}
r = frr[i].Inflated(frameln);
Draw& w = pw.Page(pgi);
if(!r.IsEmpty()) {
DrawFatFrame(w, r, fc, fl);
if(allsel)
w.DrawRect(r, InvertColor);
}
}
if(pw.tracer)
@ -200,10 +220,8 @@ PageY RichTable::GetHeight(RichContext rc) const
PageY pyy = Realize(rc).pyy;
pyy.y += format.frame;
pyy.y += format.after;
if(pyy.y > rc.page.bottom) {
pyy.y = rc.page.top;
pyy.page++;
}
if(pyy.y > GetPageRect(pyy).bottom)
NextPage(pyy);
return pyy;
}
@ -211,9 +229,9 @@ PageY RichTable::GetTop(RichContext rc) const
{
if(cell.GetCount() == 0)
return rc.py;
rc.py = Realize(rc)[0].py;
rc.py.y -= format.frame;
return rc.py;
PageY py = Realize(rc)[0].py;
py.y -= format.frame;
return py;
}
RichCaret RichTable::GetCaret(int pos, RichContext rc) const
@ -225,17 +243,14 @@ RichCaret RichTable::GetCaret(int pos, RichContext rc) const
const TabLayout& tab = Realize(rc);
for(int i = 0; i < ny; i++) {
const PaintRow& pr = tab[i];
rc.py = pr.py;
PageY pyy;
for(int j = 0; j < nx; j++) {
if(ci[i][j].valid) {
const RichCell& cl = cell[i][j];
pyy = tab[min(ny - 1, i + cl.vspan)].pyy;
int l = cl.text.GetLength() + 1;
if(pos < l) {
rc.page = pr[j].page;
return cl.GetCaret(pos, rc, pyy);
}
if(pos < l)
return cl.GetCaret(pos, pr[j].MakeRichContext(MakeRichContext(rc, pr.py)), pyy);
ti += cl.text.GetTableCount();
pos -= l;
}
@ -260,11 +275,9 @@ int RichTable::GetPos(int x, PageY y, RichContext rc) const
const PaintCell& pc = pr[j];
PageY pyy = tab[min(ny - 1, i + cl.vspan)].pyy;
if(y < pyy
&& (j == 0 || x >= pc.page.left - format.grid)
&& (j == nx - 1 || x < pc.page.right)) {
rc.page = pc.page;
return cl.GetPos(x, y, rc, pyy) + pos;
}
&& (j == 0 || x >= pc.page_left - format.grid)
&& (j == nx - 1 || x < pc.page_right))
return cl.GetPos(x, y, pr[j].MakeRichContext(MakeRichContext(rc, pr.py)), pyy) + pos;
pos += cl.text.GetLength() + 1;
}
}
@ -273,45 +286,46 @@ int RichTable::GetPos(int x, PageY y, RichContext rc) const
RichHotPos RichTable::GetHotPos(int x, PageY y, int tolerance, RichContext rc) const
{
RichHotPos hp;
hp.textleft = rc.page.left;
hp.textcx = rc.page.Width();
int nx = format.column.GetCount();
int ny = cell.GetCount();
const TabLayout& tab = Realize(rc);
if(abs(x - tab.page.left) <= tolerance) {
int left = tab.first_page.left;
int right = tab.first_page.right;
if(abs(x - left) <= tolerance) {
hp.table = 0;
hp.column = RICHHOT_LM;
hp.delta = x - tab.page.left;
hp.delta = x - left;
return hp;
}
if(abs(x - tab.page.right) <= tolerance) {
if(abs(x - right) <= tolerance) {
hp.table = 0;
hp.column = RICHHOT_RM;
hp.delta = x - tab.page.right;
hp.delta = x - right;
return hp;
}
int ti = 0;
for(int i = 0; i < ny; i++) {
const PaintRow& pr = tab[i];
rc.py = pr.py;
for(int j = 0; j < nx; j++) {
if(ci[i][j].valid) {
const RichCell& cl = cell[i][j];
const PaintCell& pc = pr[j];
PageY pyy = tab[min(ny - 1, i + cl.vspan)].pyy;
if(y < pyy) {
if(j < nx - 1 && abs(x - pc.page.right) <= tolerance) {
if(j < nx - 1 && abs(x - pc.right) <= tolerance) {
hp.table = 0;
hp.column = j + cl.hspan;
hp.delta = x - pc.page.right;
hp.left = tab.page.left;
hp.cx = tab.page.Width();
hp.delta = x - pc.right;
hp.left = left;
hp.cx = right - left;
return hp;
}
if((j == 0 || x >= pc.page.left - format.grid) && (j == nx - 1 || x < pc.page.right)) {
rc.page = pc.page;
hp = cl.GetHotPos(x, y, tolerance, rc, pyy);
if((j == 0 || x >= pc.left - format.grid) && (j == nx - 1 || x < pc.right)) {
hp = cl.GetHotPos(x, y, tolerance, MakeRichContext(rc, pr.py) , pyy);
hp.table += ti;
return hp;
}
@ -338,16 +352,15 @@ int RichTable::GetVertMove(int pos, int gx, RichContext rc, int dir) const
cp.x = 0;
const PaintRow& pr = tab[cp.y];
for(int j = 0; j < nx; j++)
if(ci[cp.y][cp.x].valid && gx < pr[j].page.right) {
if(ci[cp.y][cp.x].valid && gx < pr[j].page_right) {
cp.x = j;
break;
}
pos = -1;
}
for(;;) {
rc.page = tab[cp.y][cp.x].page;
RichContext rc1 = tab[cp.y][cp.x].MakeRichContext(rc);
const RichCell& c = cell[cp.y][cp.x];
RichContext rc1 = rc;
if(c.Reduce(rc1)) {
int q = cell[cp.y][cp.x].text.GetVertMove(pos, gx, rc1, dir);
if(q >= 0)
@ -372,8 +385,7 @@ void RichTable::GatherValPos(Vector<RichValPos>& f, RichContext rc, int pos, int
for(int j = 0; j < nx; j++)
if(ci[i][j].valid) {
const RichCell& cl = cell[i][j];
rc.page = pr[j].page;
cl.GatherValPos(f, rc, tab[min(ny - 1, i + cl.vspan)].pyy, pos, type);
cl.GatherValPos(f, pr[j].MakeRichContext(rc), tab[min(ny - 1, i + cl.vspan)].pyy, pos, type);
pos += cl.text.GetLength() + 1;
}
}

View file

@ -71,15 +71,15 @@ void RichTxt::Advance(int parti, RichContext& rc, RichContext& begin) const
{
if(part[parti].Is<RichTable>()) {
const RichTable& tab = GetTable(parti);
if(tab.format.newhdrftr && rc.text == this) {
rc.NewHeaderFooter(~tab.header, ~tab.footer);
rc.Page();
}
else
if(tab.format.newhdrftr && rc.text == this)
rc.HeaderFooter(~tab.header, ~tab.footer);
if(tab.format.newpage)
rc.Page();
begin = rc;
rc.py = GetTable(parti).GetHeight(rc);
PageY py = GetTable(parti).GetHeight(rc);
if(py.page > rc.py.page)
rc.Page(); // set new header / footer and page size
rc.py = py;
}
else {
Sync(parti, rc);
@ -98,11 +98,8 @@ void RichTxt::Advance(int parti, RichContext& rc, RichContext& begin) const
nbefore = p.before + p.ruler;
nline = p.linecy[0];
}
if(pp.newhdrftr && rc.text == this) {
rc.NewHeaderFooter(~pp.header, ~pp.footer);
rc.Page();
}
else
if(pp.newhdrftr && rc.text == this)
rc.HeaderFooter(~pp.header, ~pp.footer);
if(pp.newpage || rc.py.y + cy + nbefore + nline > rc.page.bottom && cy < rc.page.Height())
rc.Page();
begin = rc;
@ -171,7 +168,7 @@ void RichTxt::Paint(PageDraw& pw, RichContext& rc, const PaintInfo& _pi) const
const RichTable& tab = GetTable(parti);
RichContext begin;
Advance(parti, rc, begin);
tab.Paint(pw, begin, pi);
tab.Paint(pw, begin, pi, rc.text == this);
pi.tablesel -= tab.GetTableCount();
}
else {
@ -195,7 +192,7 @@ void RichTxt::Paint(PageDraw& pw, RichContext& rc, const PaintInfo& _pi) const
pp.spellerrors.Clear();
}
if(IsPainting(pw, pi.zoom, rc.page, begin.py, next.py))
p.Paint(pw, rc.page, begin.py, pi, n, pp.spellerrors, rc.text == this);
p.Paint(pw, begin, pi, n, pp.spellerrors, rc.text == this);
}
rc = next;
}
@ -221,7 +218,7 @@ RichCaret RichTxt::GetCaret(int pos, RichContext rc) const
if(IsTable(parti))
return GetTable(parti).GetCaret(pos, begin);
else {
RichCaret tp = Get(parti, *rc.styles, true).GetCaret(pos, begin.page, begin.py);
RichCaret tp = Get(parti, *rc.styles, true).GetCaret(pos, begin);
tp.textpage = begin.page;
return tp;
}
@ -245,7 +242,7 @@ int RichTxt::GetPos(int x, PageY y, RichContext rc) const
if(IsTable(parti))
return GetTable(parti).GetPos(x, y, begin) + pos;
else
return Get(parti, *rc.styles, true).GetPos(x, y, begin.page, begin.py) + pos;
return Get(parti, *rc.styles, true).GetPos(x, y, begin) + pos;
}
pos += GetPartLength(parti) + 1;
parti++;
@ -329,9 +326,9 @@ void RichTxt::GatherValPos(Vector<RichValPos>& f, RichContext rc, int pos, int t
const Para& p = part[parti].Get<Para>();
if(p.haspos) {
if(type == LABELS)
Get(parti, *begin.styles, true).GatherLabels(f, begin.page, begin.py, pos);
Get(parti, *begin.styles, true).GatherLabels(f, begin, pos);
else
Get(parti, *begin.styles, true).GatherIndexes(f, begin.page, begin.py, pos);
Get(parti, *begin.styles, true).GatherIndexes(f, begin, pos);
}
}
pos += GetPartLength(parti) + 1;