From 237e9d6ab9df449706fa8bb1405d0ddcbdaf688f Mon Sep 17 00:00:00 2001 From: Nick Mazuk Date: Tue, 21 Sep 2021 09:03:03 +0200 Subject: [PATCH] Fix GH#9043: Music should automatically clear headers and footers Backport of #9193, part 1 and 2 --- libmscore/layout.cpp | 10 ++-- libmscore/page.cpp | 103 +++++++++++++++++++++++++++++++++++++++-- libmscore/page.h | 3 ++ libmscore/textbase.cpp | 28 +++++++++++ libmscore/textbase.h | 1 + 5 files changed, 136 insertions(+), 9 deletions(-) diff --git a/libmscore/layout.cpp b/libmscore/layout.cpp index faf118aaa4040..86bbab151b953 100644 --- a/libmscore/layout.cpp +++ b/libmscore/layout.cpp @@ -4742,7 +4742,9 @@ void LayoutContext::collectPage() { const qreal slb = score->styleP(Sid::staffLowerBorder); bool breakPages = score->layoutMode() != LayoutMode::SYSTEM; - qreal ey = page->height() - page->bm(); + qreal footerExtension = qMax(0.0, page->footerHeight() - score->styleV(Sid::footerOffset).value().y()); // how much the footer extends above the margin + qreal headerExtension = qMax(0.0, page->headerHeight() - score->styleV(Sid::headerOffset).value().y()); // how much the header extends below the margin + qreal endY = page->height() - page->bm() - footerExtension; qreal y = 0.0; System* nextSystem = 0; @@ -4756,7 +4758,7 @@ void LayoutContext::collectPage() y = page->system(0)->y() + page->system(0)->height(); } else { - y = page->tm(); + y = page->tm() + headerExtension; } for (int i = 1; i < pSystems; ++i) { System* cs = page->system(i); @@ -4886,12 +4888,12 @@ void LayoutContext::collectPage() qreal margin = qMax(curSystem->minBottom(), curSystem->spacerDistance(false)); dist += qMax(margin, slb); } - breakPage = (y + dist) >= ey && breakPages; + breakPage = (y + dist) >= endY && breakPages; } if (breakPage) { qreal dist = qMax(prevSystem->minBottom(), prevSystem->spacerDistance(false)); dist = qMax(dist, slb); - layoutPage(page, ey - (y + dist)); + layoutPage(page, endY - (y + dist)); // if we collected a system we cannot fit onto this page, // we need to collect next page in order to correctly set system positions if (collected) diff --git a/libmscore/page.cpp b/libmscore/page.cpp index 8154fb59ee623..58023179d2dd1 100644 --- a/libmscore/page.cpp +++ b/libmscore/page.cpp @@ -147,10 +147,25 @@ void Page::draw(QPainter* painter) const //--------------------------------------------------------- void Page::drawHeaderFooter(QPainter* p, int area, const QString& ss) const + { + Text* text = layoutHeaderFooter(area, ss); + if (!text) + return; + p->translate(text->pos()); + text->draw(p); + p->translate(-text->pos()); + text->setParent(0); + } + +//--------------------------------------------------------- +// layoutHeaderFooter +//--------------------------------------------------------- + +Text* Page::layoutHeaderFooter(int area, const QString& ss) const { QString s = replaceTextMacros(ss); if (s.isEmpty()) - return; + return nullptr; Text* text; if (area < MAX_HEADERS) { @@ -187,10 +202,88 @@ void Page::drawHeaderFooter(QPainter* p, int area, const QString& ss) const text->setAlign(flags); text->setXmlText(s); text->layout(); - p->translate(text->pos()); - text->draw(p); - p->translate(-text->pos()); - text->setParent(0); + return text; + } + + //--------------------------------------------------------- + // headerHeight + //--------------------------------------------------------- + +qreal Page::headerHeight() const + { + if (!score()->pageMode()) + return 0.0; + + int n = no() + 1 + score()->pageNumberOffset(); + + QString s1, s2, s3; + + if (score()->styleB(Sid::showHeader) && (no() || score()->styleB(Sid::headerFirstPage))) { + bool odd = (n & 1) || !score()->styleB(Sid::headerOddEven); + if (odd) { + s1 = score()->styleSt(Sid::oddHeaderL); + s2 = score()->styleSt(Sid::oddHeaderC); + s3 = score()->styleSt(Sid::oddHeaderR); + } + else { + s1 = score()->styleSt(Sid::evenHeaderL); + s2 = score()->styleSt(Sid::evenHeaderC); + s3 = score()->styleSt(Sid::evenHeaderR); + } + + Text* headerLeft = layoutHeaderFooter(0, s1); + Text* headerCenter = layoutHeaderFooter(1, s2); + Text* headerRight = layoutHeaderFooter(2, s3); + + qreal headerLeftHeight = headerLeft ? headerLeft->visibleHeight() : 0.0; + qreal headerCenterHeight = headerCenter ? headerCenter->visibleHeight() : 0.0; + qreal headerRightHeight = headerRight ? headerRight->visibleHeight() : 0.0; + return qMax(headerLeftHeight, qMax(headerCenterHeight, headerRightHeight)); + } + + return 0.0; + } + +//--------------------------------------------------------- +// footerHeight +//--------------------------------------------------------- + +qreal Page::footerHeight() const + { + if (!score()->pageMode()) + return 0.0; + + int n = no() + 1 + score()->pageNumberOffset(); + + QString s1, s2, s3; + + if (score()->styleB(Sid::showFooter) && (no() || score()->styleB(Sid::footerFirstPage))) { + bool odd = (n & 1) || !score()->styleB(Sid::footerOddEven); + if (odd) { + s1 = score()->styleSt(Sid::oddFooterL); + s2 = score()->styleSt(Sid::oddFooterC); + s3 = score()->styleSt(Sid::oddFooterR); + } + else { + s1 = score()->styleSt(Sid::evenFooterL); + s2 = score()->styleSt(Sid::evenFooterC); + s3 = score()->styleSt(Sid::evenFooterR); + } + + Text* footerLeft = layoutHeaderFooter(3, s1); + Text* footerCenter = layoutHeaderFooter(4, s2); + Text* footerRight = layoutHeaderFooter(5, s3); + + qreal footerLeftHeight = footerLeft ? footerLeft->visibleHeight() : 0.0; + qreal footerCenterHeight = footerCenter ? footerCenter->visibleHeight() : 0.0; + qreal footerRightHeight = footerRight ? footerRight->visibleHeight() : 0.0; + + qreal footerHeight = qMax(footerLeftHeight, qMax(footerCenterHeight, footerRightHeight)); + + return footerHeight; + } + + return 0.0; } #if 0 diff --git a/libmscore/page.h b/libmscore/page.h index bea5ef2271cb2..3fb286f49ea5e 100644 --- a/libmscore/page.h +++ b/libmscore/page.h @@ -42,6 +42,7 @@ class Page final : public Element { QString replaceTextMacros(const QString&) const; void drawHeaderFooter(QPainter*, int area, const QString&) const; + Text* layoutHeaderFooter(int area, const QString& ss) const; public: Page(Score*); @@ -65,6 +66,8 @@ class Page final : public Element { qreal bm() const; qreal lm() const; qreal rm() const; + qreal headerHeight() const; + qreal footerHeight() const; void draw(QPainter*) const override; void scanElements(void* data, void (*func)(void*, Element*), bool all=true) override; diff --git a/libmscore/textbase.cpp b/libmscore/textbase.cpp index 480c4ac1363fb..e13e6176e9db2 100644 --- a/libmscore/textbase.cpp +++ b/libmscore/textbase.cpp @@ -1798,6 +1798,8 @@ void TextBase::layout1() _layout.append(TextBlock()); QRectF bb; qreal y = 0; + + // adjust the bounding box for the text item for (int i = 0; i < rows(); ++i) { TextBlock* t = &_layout[i]; t->layout(this); @@ -1933,6 +1935,32 @@ qreal TextBase::lineHeight() const return fontMetrics().height(); } +//--------------------------------------------------------- +// visibleHeight +//--------------------------------------------------------- + +qreal TextBase::visibleHeight() + { + QRectF bb; + qreal y = 0; + + // adjust the bounding box for the text item + for (int i = 0; i < rows(); ++i) { + TextBlock* t = &_layout[i]; + if (t->columns() == 0 && i != rows() - 1) + continue; + t->layout(this); + const QRectF* r = &t->boundingRect(); + + if (r->height() == 0) + r = &_layout[i - i].boundingRect(); + y += t->lineSpacing(); + t->setY(y); + bb |= r->translated(0.0, y); + } + return bb.height(); + } + //--------------------------------------------------------- // baseLine //--------------------------------------------------------- diff --git a/libmscore/textbase.h b/libmscore/textbase.h index 27c7a03dcbaf9..09312fc30daf1 100644 --- a/libmscore/textbase.h +++ b/libmscore/textbase.h @@ -298,6 +298,7 @@ class TextBase : public Element { qreal lineSpacing() const; qreal lineHeight() const; virtual qreal baseLine() const override; + qreal visibleHeight(); bool empty() const { return xmlText().isEmpty(); } void clear() { setXmlText(QString()); }