From beab1177bdceeb48aecdd7d642a2c9973f739739 Mon Sep 17 00:00:00 2001 From: cxl Date: Wed, 15 Feb 2017 20:42:19 +0000 Subject: [PATCH] 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 --- uppsrc/RichText/HeaderFooter.cpp | 46 +++++- uppsrc/RichText/Para.h | 14 +- uppsrc/RichText/ParaPaint.cpp | 233 ++++++++++++++--------------- uppsrc/RichText/RichText.h | 43 +++--- uppsrc/RichText/RichText.iml | 11 +- uppsrc/RichText/Table.h | 55 ++++--- uppsrc/RichText/TableCell.cpp | 19 ++- uppsrc/RichText/TableData.cpp | 43 +++--- uppsrc/RichText/TableLayout.cpp | 169 ++++++++++++--------- uppsrc/RichText/TablePaint.cpp | 246 ++++++++++++++++--------------- uppsrc/RichText/TxtPaint.cpp | 31 ++-- 11 files changed, 493 insertions(+), 417 deletions(-) diff --git a/uppsrc/RichText/HeaderFooter.cpp b/uppsrc/RichText/HeaderFooter.cpp index cd0c8f5e2..cbc997cbd 100644 --- a/uppsrc/RichText/HeaderFooter.cpp +++ b/uppsrc/RichText/HeaderFooter.cpp @@ -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; diff --git a/uppsrc/RichText/Para.h b/uppsrc/RichText/Para.h index 62c6059f1..3679d5187 100644 --- a/uppsrc/RichText/Para.h +++ b/uppsrc/RichText/Para.h @@ -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& info, const Rect& page, PageY py, int pos) const; - void GatherIndexes(Vector& 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& info, RichContext rc, int pos) const; + void GatherIndexes(Vector& 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, CharFormat& cf, Array& obj) const; diff --git a/uppsrc/RichText/ParaPaint.cpp b/uppsrc/RichText/ParaPaint.cpp index 2613c20b2..f854fe2f3 100644 --- a/uppsrc/RichText/ParaPaint.cpp +++ b/uppsrc/RichText/ParaPaint.cpp @@ -4,28 +4,12 @@ namespace Upp { #define IMAGECLASS RichTextImg #define IMAGEFILE -#include +#include -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 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& info, const Rect& page, PageY py, int pos) const +void RichPara::GatherLabels(Vector& 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& info, const Rect& page, PageY py, int pos) const +void RichPara::GatherIndexes(Vector& 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& 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; } } diff --git a/uppsrc/RichText/RichText.h b/uppsrc/RichText/RichText.h index fe1c4428c..b7a5491ef 100644 --- a/uppsrc/RichText/RichText.h +++ b/uppsrc/RichText/RichText.h @@ -6,6 +6,10 @@ namespace Upp { +#define IMAGECLASS RichTextImg +#define IMAGEFILE +#include + INITIALIZE(RichImage) class PasteClip; @@ -288,6 +292,28 @@ struct PaintInfo { int LineZoom(Zoom z, int a); class RichTable; +class RichText; +struct RichStyle; + +typedef ArrayMap 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 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 { diff --git a/uppsrc/RichText/RichText.iml b/uppsrc/RichText/RichText.iml index 61f30bae4..3d68a94e0 100644 --- a/uppsrc/RichText/RichText.iml +++ b/uppsrc/RichText/RichText.iml @@ -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) diff --git a/uppsrc/RichText/Table.h b/uppsrc/RichText/Table.h index 3eb4807b3..e06834ec7 100644 --- a/uppsrc/RichText/Table.h +++ b/uppsrc/RichText/Table.h @@ -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 header, footer; struct PaintCell : Moveable { - 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 { - PageY gpy; - PageY py, pyy; + PageY gpy; // position of grid line (if not first) + PageY py, pyy; //start, end of line Buffer 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 col; Buffer 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 > 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& 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& 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; diff --git a/uppsrc/RichText/TableCell.cpp b/uppsrc/RichText/TableCell.cpp index c652aa725..d237adc33 100644 --- a/uppsrc/RichText/TableCell.cpp +++ b/uppsrc/RichText/TableCell.cpp @@ -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; diff --git a/uppsrc/RichText/TableData.cpp b/uppsrc/RichText/TableData.cpp index e6d4dbc4a..042ddd57d 100644 --- a/uppsrc/RichText/TableData.cpp +++ b/uppsrc/RichText/TableData.cpp @@ -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(); } diff --git a/uppsrc/RichText/TableLayout.cpp b/uppsrc/RichText/TableLayout.cpp index 675ee1414..2e532bebc 100644 --- a/uppsrc/RichText/TableLayout.cpp +++ b/uppsrc/RichText/TableLayout.cpp @@ -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 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& 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; } diff --git a/uppsrc/RichText/TablePaint.cpp b/uppsrc/RichText/TablePaint.cpp index 625680dc2..61ca80146 100644 --- a/uppsrc/RichText/TablePaint.cpp +++ b/uppsrc/RichText/TablePaint.cpp @@ -24,17 +24,15 @@ void RichTable::ExpandFrr(VectorMap& 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& frr, +bool RichTable::RowPaint(PageDraw& pw, RichContext rc, const Layout& tab, bool header, + int i, int ny, Rect pg, Rect npg, + VectorMap& frr, PaintInfo& pi, int pd, bool sel) const { - RichContext rc(st, NULL); const Array& 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 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 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& 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; } } diff --git a/uppsrc/RichText/TxtPaint.cpp b/uppsrc/RichText/TxtPaint.cpp index 411108ed5..f7492669b 100644 --- a/uppsrc/RichText/TxtPaint.cpp +++ b/uppsrc/RichText/TxtPaint.cpp @@ -71,15 +71,15 @@ void RichTxt::Advance(int parti, RichContext& rc, RichContext& begin) const { if(part[parti].Is()) { 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& f, RichContext rc, int pos, int t const Para& p = part[parti].Get(); 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;