Skip to content

Commit 037bb07

Browse files
authored
Merge pull request #32652 from pedroataidefonseca/fix/issue#32538
Fix #32538: Keep down spacer from forcing system to page bottom
2 parents 995ecfe + f4425bd commit 037bb07

File tree

4 files changed

+70
-2
lines changed

4 files changed

+70
-2
lines changed

src/engraving/dom/spacer.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include "measure.h"
2929
#include "score.h"
30+
#include "system.h"
3031

3132
using namespace mu;
3233
using namespace muse::draw;
@@ -161,6 +162,62 @@ PropertyValue Spacer::propertyDefault(Pid id) const
161162
}
162163
}
163164

165+
//---------------------------------------------------------
166+
// triggerLayout
167+
//---------------------------------------------------------
168+
169+
void Spacer::triggerLayout() const
170+
{
171+
if (!explicitParent()) {
172+
return;
173+
}
174+
175+
Measure* m = measure();
176+
if (!m) {
177+
EngravingItem::triggerLayout();
178+
return;
179+
}
180+
181+
Score* s = score();
182+
System* system = m->system();
183+
if (!s || !system || s->nstaves() == 0) {
184+
m->triggerLayout();
185+
return;
186+
}
187+
188+
// Most spacer edits can stay local to the measure and are much cheaper.
189+
// Escalate only for down/fixed spacers on the last non-vbox system of the page,
190+
// where edits can repaginate and affect page-end spacing.
191+
if (spacerType() == SpacerType::UP) {
192+
m->triggerLayout();
193+
return;
194+
}
195+
196+
System* nextSystem = m->nextNonVBoxSystem();
197+
if (nextSystem && nextSystem->page() == system->page()) {
198+
m->triggerLayout();
199+
return;
200+
}
201+
202+
// For the last notation system on a page, include the next system boundary
203+
// so page-end spacing can be recomputed without relaying out the whole score.
204+
Measure* firstMeasure = system->firstMeasure();
205+
if (!firstMeasure) {
206+
m->triggerLayout();
207+
return;
208+
}
209+
210+
Fraction startTick = firstMeasure->tick();
211+
Fraction endTick = s->endTick();
212+
if (nextSystem) {
213+
if (Measure* nextFirstMeasure = nextSystem->firstMeasure()) {
214+
endTick = nextFirstMeasure->tick();
215+
}
216+
}
217+
218+
s->setLayout(startTick, endTick, 0, s->nstaves() - 1, this);
219+
}
220+
164221
//---------------------------------------------------------
165222
// subtypeUserName
166223
//---------------------------------------------------------

src/engraving/dom/spacer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class Spacer final : public EngravingItem
7575
PropertyValue getProperty(Pid propertyId) const override;
7676
bool setProperty(Pid propertyId, const PropertyValue&) override;
7777
PropertyValue propertyDefault(Pid id) const override;
78+
void triggerLayout() const override;
7879

7980
struct LayoutData : public EngravingItem::LayoutData {
8081
PainterPath path;

src/engraving/rendering/score/pagelayout.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,9 @@ void PageLayout::collectPage(LayoutContext& ctx)
251251
dist += footerExtension;
252252
}
253253
} else if (!ctx.state().prevSystem()->hasFixedDownDistance()) {
254-
double margin = std::max(ctx.state().curSystem()->minBottom(), ctx.state().curSystem()->spacerDistance(false));
254+
// Down spacers define distance to the following system, not to the page footer.
255+
// Using them here can visually pin/stretch the current system to page edge.
256+
double margin = ctx.state().curSystem()->minBottom();
255257
// ensure it doesn't collide with footer
256258
if (footerExtension > 0) {
257259
margin += footerExtension + headerFooterPadding;
@@ -261,7 +263,10 @@ void PageLayout::collectPage(LayoutContext& ctx)
261263
isPageBreak = (y + dist) >= endY && breakPages;
262264
}
263265
if (isPageBreak) {
264-
double dist = std::max(ctx.state().prevSystem()->minBottom(), ctx.state().prevSystem()->spacerDistance(false));
266+
double dist = ctx.state().prevSystem()->minBottom();
267+
if (!ctx.conf().isVerticalSpreadEnabled()) {
268+
dist = std::max(dist, ctx.state().prevSystem()->spacerDistance(false));
269+
}
265270
double footerPadding = 0.0;
266271
// ensure it doesn't collide with footer
267272
if (footerExtension > 0) {

src/engraving/rendering/score/systemlayout.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2385,6 +2385,11 @@ void SystemLayout::restoreLayout2(System* system, LayoutContext& ctx)
23852385

23862386
system->setHeight(system->systemHeight());
23872387
SystemLayout::setMeasureHeight(system, system->systemHeight(), ctx);
2388+
2389+
// Reused systems can move across pages during partial relayout.
2390+
// Refresh geometry derived from SysStaff vertical positions.
2391+
SystemLayout::layoutBracketsVertical(system, ctx);
2392+
SystemHeaderLayout::setInstrumentNamesVerticalPos(system, ctx);
23882393
}
23892394

23902395
void SystemLayout::setMeasureHeight(System* system, double height, const LayoutContext& ctx)

0 commit comments

Comments
 (0)