From 3ea8a5cd4b1dd0a52ee531ce8e77be2a24ffe710 Mon Sep 17 00:00:00 2001 From: "J.G." Date: Sun, 28 Jun 2026 04:35:54 +0000 Subject: [PATCH 01/14] qDebug() omissions (probably temporary) --- audio/midi/fluid/sfont.cpp | 7 ++++--- libmscore/check.cpp | 22 +++++++++++----------- libmscore/layout.cpp | 2 +- libmscore/score.cpp | 4 ++-- libmscore/utils.cpp | 2 +- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/audio/midi/fluid/sfont.cpp b/audio/midi/fluid/sfont.cpp index 6c04279268ea8..6bbc08ae1b45e 100644 --- a/audio/midi/fluid/sfont.cpp +++ b/audio/midi/fluid/sfont.cpp @@ -693,9 +693,10 @@ void Sample::load() // // now add some extra sanity checks from the SF2 spec (biased so they work with unsigned int); // just a warning, they probably work with Fluid, possibly with audible artefacts though... - if (!(start + 7 < loopstart) || !(loopstart + 31 < loopend) || !(loopend + 7 < end)) - qDebug("SoundFont(%s) Sample(%s) start(%u) startloop(%u) endloop(%u) end(%u) smaller than SoundFont 2.04 spec chapter 7.10 recommendation", - qPrintable(sf->get_name()), name, start, loopstart, loopend, end); + if (!(start + 7 < loopstart) || !(loopstart + 31 < loopend) || !(loopend + 7 < end)) { + // qDebug("SoundFont(%s) Sample(%s) start(%u) startloop(%u) endloop(%u) end(%u) smaller than SoundFont 2.04 spec chapter 7.10 recommendation", + // qPrintable(sf->get_name()), name, start, loopstart, loopend, end); + } // this used to cause a crash if (!data) { diff --git a/libmscore/check.cpp b/libmscore/check.cpp index 3061dd9b7dd25..915e4f3df1c9f 100644 --- a/libmscore/check.cpp +++ b/libmscore/check.cpp @@ -318,9 +318,9 @@ bool Score::checkClefs() void Measure::fillGap(const Fraction& pos, const Fraction& len, int track, const Fraction& stretch, bool useGapRests) { - qDebug().nospace().noquote() - << "measure " << tick().print() << " pos " << pos.print() << ", " - << "len " << len.print() << " stretch " << stretch.print() << " track " << track; + // qDebug().nospace().noquote() + // << "measure " << tick().print() << " pos " << pos.print() << ", " + // << "len " << len.print() << " stretch " << stretch.print() << " track " << track; TDuration d; d.setVal(len.ticks()); if (d.isValid()) { @@ -363,17 +363,17 @@ void Measure::checkMeasure(int staffIdx, bool useGapRests) currentPos = seg->rtick() * stretch; if (currentPos < expectedPos) { - qDebug().nospace().noquote() - << "in measure overrun" << tick().print() - << "at " << (currentPos/stretch).ticks() << "-" << (expectedPos/stretch).ticks() - << " track " << track; + // qDebug().nospace().noquote() + // << "in measure overrun" << tick().print() + // << "at " << (currentPos/stretch).ticks() << "-" << (expectedPos/stretch).ticks() + // << " track " << track; break; } else if (currentPos > expectedPos) { - qDebug().nospace().noquote() - << "in measure underrun " << tick().print() - << " at " << (currentPos/stretch).ticks() << "-" << (expectedPos/stretch).ticks() - << " track " << track; + // qDebug().nospace().noquote() + // << "in measure underrun " << tick().print() + // << " at " << (currentPos/stretch).ticks() << "-" << (expectedPos/stretch).ticks() + // << " track " << track; fillGap(expectedPos, currentPos - expectedPos, track, stretch); } diff --git a/libmscore/layout.cpp b/libmscore/layout.cpp index 1598d433cc48f..a8d1da31a2afc 100644 --- a/libmscore/layout.cpp +++ b/libmscore/layout.cpp @@ -2248,7 +2248,7 @@ void LayoutContext::layoutArticAndFingeringOnCrossStaffBeams(System* system) void LayoutContext::layoutPage(Page* page, qreal restHeight, qreal footerPadding) { if (restHeight < 0.0) { - qDebug("restHeight < 0.0: %f\n", restHeight); + // qDebug("restHeight < 0.0: %f\n", restHeight); restHeight = 0; } diff --git a/libmscore/score.cpp b/libmscore/score.cpp index c1f3191e0f45a..473311fa256b1 100644 --- a/libmscore/score.cpp +++ b/libmscore/score.cpp @@ -4386,7 +4386,7 @@ ChordRest* Score::findCR(Fraction tick, int track) const { Measure* m = tick2measureMM(tick); if (!m) { - qDebug("findCR: no measure for tick %d", tick.ticks()); + // qDebug("findCR: no measure for tick %d", tick.ticks()); return nullptr; } // attach to first rest all spanner when mmRest @@ -4422,7 +4422,7 @@ ChordRest* Score::findCRinStaff(const Fraction& tick, int staffIdx) const Fraction ptick = tick - Fraction::fromTicks(1); Measure* m = tick2measureMM(ptick); if (!m) { - qDebug("findCRinStaff: no measure for tick %d", ptick.ticks()); + // qDebug("findCRinStaff: no measure for tick %d", ptick.ticks()); return 0; } // attach to first rest all spanner when mmRest diff --git a/libmscore/utils.cpp b/libmscore/utils.cpp index 31f7b0ead925e..8b19dce625833 100644 --- a/libmscore/utils.cpp +++ b/libmscore/utils.cpp @@ -147,7 +147,7 @@ Segment* Score::tick2segment(const Fraction& t, bool first, SegmentType st, bool m = tick2measure(tick); if (m == 0) { - qDebug("no measure for tick %d", tick.ticks()); + // qDebug("no measure for tick %d", tick.ticks()); return 0; } for (Segment* segment = m->first(st); segment;) { From efde5dbcb3cb925b24fd2245c5d9cc6cf27a1c95 Mon Sep 17 00:00:00 2001 From: "J.G." Date: Thu, 25 Jun 2026 04:33:06 +0000 Subject: [PATCH 02/14] Progress of layout/save/auto-save will show in status-bar and splash screen will show load. Rendering MIDI will show as a pop-up if the preference is enabled, capable of being cancelled with cancel button or escape key. All the other progresses will be "baked" in and not optional --- global/settings/types/preferencekeys.h | 3 -- libmscore/cmd.cpp | 4 +- libmscore/layout.cpp | 33 +++++----------- libmscore/mscore.cpp | 5 --- libmscore/mscore.h | 5 --- libmscore/rendermidi.cpp | 22 ++++++----- libmscore/score.h | 1 + libmscore/scorefile.cpp | 29 ++++---------- mscore/file.cpp | 6 +++ mscore/mssplashscreen.cpp | 21 +++++++++- mscore/mssplashscreen.h | 9 +++++ mscore/musescore.cpp | 55 +++++++++++++++++++++++--- mscore/musescore.h | 1 + mscore/preferences.cpp | 3 -- mscore/scoreview.cpp | 2 + 15 files changed, 119 insertions(+), 80 deletions(-) diff --git a/global/settings/types/preferencekeys.h b/global/settings/types/preferencekeys.h index dd77d2f40aef5..5ac4aed6ecf51 100644 --- a/global/settings/types/preferencekeys.h +++ b/global/settings/types/preferencekeys.h @@ -59,9 +59,6 @@ #define PREF_APP_TELEMETRY_ALLOWED "application/telemetry/allowed" #define PREF_APP_BACKUP_GENERATE_BACKUP "application/backup/generateBackup" #define PREF_APP_BACKUP_SUBFOLDER "application/backup/subfolder" -#define PREF_APP_SHOW_PROGRESS_LAYOUT "application/show/progressBar/layout" -#define PREF_APP_SHOW_PROGRESS_SAVE "application/show/progressBar/save" -#define PREF_APP_SHOW_PROGRESS_AUTOSAVE "application/show/progressBar/autosave" #define PREF_EXPORT_AUDIO_NORMALIZE "export/audio/normalize" #define PREF_EXPORT_AUDIO_SAMPLERATE "export/audio/sampleRate" #define PREF_EXPORT_AUDIO_PCMRATE "export/audio/PCMRate" diff --git a/libmscore/cmd.cpp b/libmscore/cmd.cpp index 3e6b751f55c74..69a1ff7c8fa4b 100644 --- a/libmscore/cmd.cpp +++ b/libmscore/cmd.cpp @@ -320,8 +320,8 @@ void Score::update(bool resetCmdState) CmdState& cs = ms->cmdState(); Fraction layoutStart = cs.startTick(); Fraction layoutEnd = cs.endTick(); - - if (auto singleElement = cs.element()) { + const auto singleElement = cs.element(); + if (singleElement) { if (singleElement->isFingering() || singleElement->isArticulation()) { layoutEntirePage = true; diff --git a/libmscore/layout.cpp b/libmscore/layout.cpp index a8d1da31a2afc..e13ffd522fd60 100644 --- a/libmscore/layout.cpp +++ b/libmscore/layout.cpp @@ -5704,27 +5704,11 @@ void LayoutContext::layout() { MeasureBase* lmb; - QProgressDialog progress; - const bool layoutAll = (startTick <= Fraction(0,1) && (endTick < Fraction(0,1) || endTick >= score->last()->endTick())); - - const bool showProgress = (MScore::showProgressBarForLayout && layoutAll) || (MScore::showProgressBarForPartialLayout); - if (showProgress) { - const int totalMeasures = score->measures() ? score->measures()->size() : 0; - QString label; - if (layoutAll) - label = QObject::tr("Performing full layout") + QObject::tr(" for") + ":\n" + score->title() + "…"; - else - label = QObject::tr("Performing partial layout between ") + startTick.print() + " and " + endTick.print() - + QObject::tr(" for") + ":\n" + score->title() + "…"; - - progress.setLabelText(label); - progress.setWindowFlags(Qt::WindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint)); - progress.setRange(0, totalMeasures); - progress.setCancelButton(nullptr); - progress.setWindowModality(Qt::WindowModal); - progress.setValue(0); - progress.setMinimumDuration(0); - } + const int min = 0; + const int max = score->measures() ? score->measures()->size() : 0; + const QString progressFormat = "Layout: %p%"; + int progressValue = min; + emit score->updateProgress(progressFormat, min, min, max); do { getNextPage(); @@ -5732,8 +5716,8 @@ void LayoutContext::layout() if (page && !page->systems().isEmpty()) { lmb = page->systems().back()->measures().back(); - if (showProgress) - progress.setValue(lmb->index()); + progressValue = lmb->index(); + emit score->updateProgress(progressFormat, progressValue, min, max); } else lmb = nullptr; @@ -5750,7 +5734,8 @@ void LayoutContext::layout() } while (curSystem && !(rangeDone && lmb == pageOldMeasure)); // && page->system(0)->measures().back()->tick() > endTick // FIXME: perhaps the first measure was meant? Or last system? - progress.close(); + if (progressValue != max) + emit score->updateProgress(progressFormat, max, min, max); if (!curSystem) { // The end of the score. The remaining systems are not needed... diff --git a/libmscore/mscore.cpp b/libmscore/mscore.cpp index 5dfdf0d464b01..141d599ad2313 100644 --- a/libmscore/mscore.cpp +++ b/libmscore/mscore.cpp @@ -56,11 +56,6 @@ bool MScore::showSystemBoundingRect = false; bool MScore::showCorruptedMeasures = true; bool MScore::useFallbackFont = true; -bool MScore::showProgressBarForLayout = true; -bool MScore::showProgressBarForPartialLayout = false; -bool MScore::showProgressBarForSave = true; -bool MScore::showProgressBarForAutosave = true; - bool MScore::saveTemplateMode = false; bool MScore::noGui = false; diff --git a/libmscore/mscore.h b/libmscore/mscore.h index bf2c7f6f377c0..587296ee5719a 100644 --- a/libmscore/mscore.h +++ b/libmscore/mscore.h @@ -456,11 +456,6 @@ class MScore { static bool debugMode; static bool testMode; - static bool showProgressBarForLayout; - static bool showProgressBarForPartialLayout; - static bool showProgressBarForSave; - static bool showProgressBarForAutosave; - static int division; static int sampleRate; static int mtcType; diff --git a/libmscore/rendermidi.cpp b/libmscore/rendermidi.cpp index b722e3a5ef0a7..d30649f79b524 100644 --- a/libmscore/rendermidi.cpp +++ b/libmscore/rendermidi.cpp @@ -2643,33 +2643,37 @@ void MidiRenderer::renderScore(EventMap* events, const Context& ctx) int currentChunk = 0; QProgressDialog progress; - if (MScore::showProgressBarForLayout) { - const int totalChunks = chunks.size(); - QString label = QObject::tr("Rendering MIDI events") + " " + const int min = 0; + const int max = chunks.size(); + const QString& progressFormat = "Rendering MIDI: %p%"; + emit score->updateProgress(progressFormat, min, min, max); + + // When loading score, allow early termination, but not if in some other ctx + if (ScoreLoad::loading() ) { + QString label = QObject::tr("Loading score") + ": " + QObject::tr("Rendering MIDI events") + " " + QObject::tr("for") + ":\n" + score->title() + "…\n" - + QObject::tr("Safe to cancel early"); + + QObject::tr("Cancelling is safe"); progress.setLabelText(label); progress.setCancelButtonText(QObject::tr("Cancel")); progress.setWindowFlags(Qt::WindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint)); - progress.setRange(0, totalChunks); + progress.setRange(min, max); progress.setWindowModality(Qt::WindowModal); progress.setValue(0); progress.setMinimumDuration(2500); } for (const Chunk& chunk : chunks) { - if (MScore::showProgressBarForLayout) { - progress.setValue(++currentChunk); - // Allow user to prematurely break rendering: + emit score->updateProgress(progressFormat, ++currentChunk, min, max); + progress.setValue(currentChunk); if (progress.wasCanceled()) break; - } renderChunk(chunk, events, ctx); } progress.close(); + emit score->updateProgress(progressFormat, max, min, max); } void MidiRenderer::renderChunk(const Chunk& chunk, EventMap* events, const Context& ctx) diff --git a/libmscore/score.h b/libmscore/score.h index 475d477bc374e..681c1a21d7ded 100644 --- a/libmscore/score.h +++ b/libmscore/score.h @@ -593,6 +593,7 @@ class Score : public QObject, public ScoreElement { signals: void posChanged(POS, unsigned, bool); void playlistChanged(); + void updateProgress(const QString&, int, int, int); public: Score(); diff --git a/libmscore/scorefile.cpp b/libmscore/scorefile.cpp index 725dc94ce19bb..c832b75507e89 100644 --- a/libmscore/scorefile.cpp +++ b/libmscore/scorefile.cpp @@ -220,25 +220,12 @@ void Score::writeMovement(XmlWriter& xml, bool selectionOnly) xml.setCurTrack(0); xml.setTrackDiff(-staffStart * VOICES); if (measureStart) { - - // progress bar - const bool showOnSave = (!isAutosaving() && MScore::showProgressBarForSave); - const bool showOnAutosave = (isAutosaving() && MScore::showProgressBarForAutosave); int currentMeasureIdx = 0; - QProgressDialog progress; - if (showOnSave || showOnAutosave) { - int totalMeasuresByStaff = (staffEnd - staffStart) * score()->measures()->size(); - QString label = (showOnAutosave ? QObject::tr("Performing Autosave") - : QObject::tr("Save File")) + ":\n" - + score()->title() + "…"; - progress.setLabelText(label); - progress.setWindowFlags(Qt::WindowFlags(Qt::Dialog | Qt::FramelessWindowHint)); - progress.setCancelButton(nullptr); - progress.setRange(0, totalMeasuresByStaff); - progress.setWindowModality(Qt::WindowModal); - progress.setValue(0); - progress.setMinimumDuration(0); - } + const int totalMeasuresByStaff = (staffEnd - staffStart) * score()->measures()->size(); + const int min = 0; + const int max = totalMeasuresByStaff; + const QString& progressFormat = isAutosaving() ? "Autosave: %p%" : "Saving: %p%"; + emit updateProgress(progressFormat, min, min, max); for (int staffIdx = staffStart; staffIdx < staffEnd; ++staffIdx) { xml.stag(staff(staffIdx), QString("id=\"%1\"").arg(staffIdx + 1 - staffStart)); @@ -259,16 +246,14 @@ void Score::writeMovement(XmlWriter& xml, bool selectionOnly) forceTimeSig = false; } - if (showOnSave || showOnAutosave) - progress.setValue(++currentMeasureIdx); + emit updateProgress(progressFormat, ++currentMeasureIdx, min, max); // Largest consumption of time for file-saving: writeMeasure(xml, m, staffIdx, writeSystemElements, forceTimeSig); } xml.etag(); } - - progress.close(); + emit updateProgress(progressFormat, max, min, max); } xml.setCurTrack(-1); if (isMaster()) { diff --git a/mscore/file.cpp b/mscore/file.cpp index 048ec37c4f465..e44f4edf98354 100644 --- a/mscore/file.cpp +++ b/mscore/file.cpp @@ -422,11 +422,17 @@ Score* MuseScore::openScore(const QString& fn, bool switchTab, const bool consid migrator.migrateScore(score); + setCurrentScore(score); + + connect(score, &Score::updateProgress, mscore, &MuseScore::updateProgress); + score->updateCapo(); score->update(); score->styleChanged(); score->doLayout(); + disconnect(score, &Score::updateProgress, mscore, &MuseScore::updateProgress); + if (considerInCurrentSession) { const int tabIdx = appendScore(score); if (switchTab && !isModalDialogOpen()) diff --git a/mscore/mssplashscreen.cpp b/mscore/mssplashscreen.cpp index bf642f5934d4a..77a31ddcc7811 100644 --- a/mscore/mssplashscreen.cpp +++ b/mscore/mssplashscreen.cpp @@ -32,7 +32,7 @@ const QSize MsSplashScreen::designSize { 720, 405 }; const QRectF MsSplashScreen::designDevBuildIconRect { 25.0, 51.0, 670.0, 38.0 }; const QRectF MsSplashScreen::designDevBuildTextRect { 25.0, 98.0, 670.0, 46.0 }; const QRectF MsSplashScreen::designLogotypeRect { 25.0, 153.0, 670.0, 74.0 }; -const QRectF MsSplashScreen::designMessageTextRect { 25.0, 270.0, 670.0, 56.0 }; +const QRectF MsSplashScreen::designMessageTextRect { 25.0, 270.0, 670.0, 64.0 }; const QRectF MsSplashScreen::designMiscTextRect { 25.0, 326.0, 670.0, 56.0 }; const double MsSplashScreen::gradientDitherAmount { 0.25 }; @@ -106,6 +106,25 @@ void MsSplashScreen::drawContents(QPainter* painter) painter->drawText(_messageTextRect, Qt::AlignHCenter | Qt::AlignTop, message()); drawDebugRect(painter, _messageTextRect, 0x80, 0xFF, 0x80); + // Loading progress bar: + if (_progress) { + const int barWidth = 333; + const int barHeight = 27; + const int x = (width() - barWidth) / 2; + const int y = height() - 50; + + // Progress: Background + painter->setPen(Qt::NoPen); + painter->setBrush(QColor(255, 255, 255)); + painter->drawRect(x, y, barWidth, barHeight); + + // Progress: Fill + painter->setBrush(QColor(155, 202, 250)); + double ratio = double(_progress) / double(_maxProgress); + int fillWidth = int(barWidth * ratio); + painter->drawRect(x, y, fillWidth, barHeight); + } + // Miscellaneous text (version information and Web site). painter->drawText(_miscTextRect, Qt::AlignRight | Qt::AlignBottom, _miscText); #if defined(WIN_PORTABLE) diff --git a/mscore/mssplashscreen.h b/mscore/mssplashscreen.h index 99b62b30ffdf7..b3263b7ce7026 100644 --- a/mscore/mssplashscreen.h +++ b/mscore/mssplashscreen.h @@ -17,6 +17,9 @@ // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. //============================================================================= +#ifndef __MSSPLASHSCREEN_H__ +#define __MSSPLASHSCREEN_H__ + namespace Ms { //--------------------------------------------------------- @@ -46,6 +49,9 @@ class MsSplashScreen : public QSplashScreen { QSvgRenderer _logotypeRenderer; QString _miscText; + int _progress = 0; + int _maxProgress = 0; + const QRectF _devBuildIconRect; const QRectF _devBuildTextRect; QRectF _logotypeRect; @@ -64,6 +70,9 @@ class MsSplashScreen : public QSplashScreen { public: MsSplashScreen(); void drawContents(QPainter* painter) override; + void setProgress(int x) { _progress = x; } + void setProgressMax(int x) { _maxProgress = x; } }; } +#endif diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index 2fe19cb5d3f09..9538f870bcedc 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -203,6 +203,8 @@ bool enableExperimental = false; QString dataPath; QString iconPath; +MsSplashScreen* sc { nullptr }; + bool converterMode = false; static bool rawDiffMode = false; static bool diffMode = false; @@ -549,10 +551,6 @@ void updateExternalValuesFromPreferences() { MScore::dropColor = preferences.getColor(PREF_UI_SCORE_NOTE_DROPCOLOR); MScore::defaultColor = preferences.getColor(PREF_UI_SCORE_DEFAULTCOLOR); - MScore::showProgressBarForLayout = preferences.getBool(PREF_APP_SHOW_PROGRESS_LAYOUT); - MScore::showProgressBarForSave = preferences.getBool(PREF_APP_SHOW_PROGRESS_SAVE); - MScore::showProgressBarForAutosave = preferences.getBool(PREF_APP_SHOW_PROGRESS_AUTOSAVE); - MScore::palettesHideWhenApplied = preferences.getBool(PREF_UI_APP_AUTOHIDE_PALETTES); MScore::pianoHighlightColor = preferences.getColor(PREF_UI_PIANO_HIGHLIGHTCOLOR); @@ -1488,6 +1486,11 @@ MuseScore::MuseScore() _modeText->setAutoFillBackground(false); _modeText->setObjectName("modeLabel"); + _progressBar = new QProgressBar; + _progressBar->setObjectName("progressBar"); + _progressBar->setMinimumWidth(300/*px*/); + _progressBar->hide(); + hRasterAction = getAction("hraster"); vRasterAction = getAction("vraster"); loopAction = getAction("loop"); @@ -1500,6 +1503,7 @@ MuseScore::MuseScore() _statusBar = new QStatusBar; _statusBar->addPermanentWidget(new QWidget(this), 2); _statusBar->addPermanentWidget(new QWidget(this), 100); + _statusBar->addPermanentWidget(_progressBar, 0); _statusBar->addPermanentWidget(_modeText, 0); searchCombo = new SearchComboBox; @@ -2490,6 +2494,9 @@ MuseScore::~MuseScore() // be deleted before paletteWorkspace. delete paletteWidget; paletteWidget = nullptr; + + delete _progressBar; + _progressBar = nullptr; } //--------------------------------------------------------- @@ -7571,7 +7578,6 @@ void MuseScore::cmd(QAction* a, const QString& cmd) MScore::showBoundingRect = a->isChecked(); MScore::showSegmentShapes = a->isChecked(); MScore::showSkylines = a->isChecked(); - MScore::showProgressBarForPartialLayout = MScore::showSkylines; if (cs) { cs->setLayoutAll(); cs->update(); @@ -7839,6 +7845,42 @@ void MuseScore::endSearch() cv->setFocus(); } +//--------------------------------------------------------- +// updateProgress +//--------------------------------------------------------- + +void MuseScore::updateProgress(const QString& format, int val, int min, int max) + { + if (sc) { + QString message = tr("Loading score:\n") + (cs ? cs->title() : "NO SCORE INFORMATION"); + sc->showMessage(message); + sc->setProgress(val); + sc->setProgressMax(max); + } + + if (!_progressBar) + return; + + const int curMin = _progressBar->minimum(); + const int curMax = _progressBar->maximum(); + + if (curMin != min) + _progressBar->setMinimum(min); + if (curMax != max) + _progressBar->setMaximum(max); + + _progressBar->setFormat(format); + _progressBar->setValue(val); + + if (val == max) { + _progressBar->hide(); + if (sc) + sc->setProgress(0); + } + else if (_progressBar->isHidden()) + _progressBar->show(); + } + //--------------------------------------------------------- // showSearchDialog //--------------------------------------------------------- @@ -9093,7 +9135,6 @@ void MuseScore::init(QStringList& argv) if (!MScore::testMode) MScore::readDefaultStyle(preferences.getString(PREF_SCORE_STYLE_DEFAULTSTYLEFILE)); - MsSplashScreen* sc = nullptr; if (!MScore::noGui && preferences.getBool(PREF_UI_APP_STARTUP_SHOWSPLASHSCREEN)) { sc = new MsSplashScreen(); sc->show(); @@ -9345,6 +9386,8 @@ void MuseScore::init(QStringList& argv) if (sc) { sc->close(); + sc->deleteLater(); + sc = nullptr; qApp->processEvents(); } diff --git a/mscore/musescore.h b/mscore/musescore.h index 3b153ce69ab58..74e8398539cbe 100644 --- a/mscore/musescore.h +++ b/mscore/musescore.h @@ -633,6 +633,7 @@ class MuseScore : public QMainWindow, public MuseScoreCore { void restartAudioEngine(); void updateTimer(); void endSearch(); + void updateProgress(const QString&, int, int, int); public: MuseScore(); diff --git a/mscore/preferences.cpp b/mscore/preferences.cpp index 80de15e3e4637..fba65fbeffe95 100644 --- a/mscore/preferences.cpp +++ b/mscore/preferences.cpp @@ -164,9 +164,6 @@ void Preferences::init(bool storeInMemoryOnly) {PREF_MIGRATION_DO_NOT_ASK_ME_AGAIN_XML, new BoolPreference(false, false)}, {PREF_APP_BACKUP_GENERATE_BACKUP, new BoolPreference(true)}, {PREF_APP_BACKUP_SUBFOLDER, new StringPreference(".mscbackup")}, - {PREF_APP_SHOW_PROGRESS_LAYOUT, new BoolPreference(true)}, - {PREF_APP_SHOW_PROGRESS_SAVE, new BoolPreference(true)}, - {PREF_APP_SHOW_PROGRESS_AUTOSAVE, new BoolPreference(true)}, {PREF_EXPORT_AUDIO_NORMALIZE, new BoolPreference(true, false)}, {PREF_EXPORT_AUDIO_SAMPLERATE, new IntPreference(44100, false)}, {PREF_EXPORT_AUDIO_PCMRATE, new IntPreference(16)}, diff --git a/mscore/scoreview.cpp b/mscore/scoreview.cpp index 176817d573fbf..ba1f2cd59072f 100644 --- a/mscore/scoreview.cpp +++ b/mscore/scoreview.cpp @@ -252,6 +252,8 @@ void ScoreView::setScore(Score* s) connect(s, SIGNAL(posChanged(POS,unsigned,bool)), SLOT(posChanged(POS,unsigned,bool))); connect(this, SIGNAL(viewRectChanged()), this, SLOT(updateContinuousPanel())); + + connect(_score, &Score::updateProgress, mscore, &MuseScore::updateProgress); } } From 5c49ba46c44789928056886e2570dfa1eac3555b Mon Sep 17 00:00:00 2001 From: "J.G." Date: Thu, 25 Jun 2026 04:33:28 +0000 Subject: [PATCH 03/14] Fix: Cycle notehead scheme: start/end command --- mscore/musescore.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index 9538f870bcedc..cea6d480304cb 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -7530,6 +7530,7 @@ void MuseScore::cmd(QAction* a, const QString& cmd) else if (cmd == "cycle-head-scheme") { if (cs) { using NHS = NoteHead::Scheme; + cs->startCmd(); for (auto n : cs->selection().noteList()) { const auto scheme = n->headScheme(); const auto beginScheme = NHS::HEAD_NORMAL; @@ -7538,10 +7539,9 @@ void MuseScore::cmd(QAction* a, const QString& cmd) const bool isPitch = (scheme == NHS::HEAD_PITCHNAME); // Normal → Pitch → Solfeggio (Movable): const auto next = isBegin ? NHS::HEAD_PITCHNAME : isPitch ? endScheme : beginScheme; - n->setHeadScheme(next); + n->undoChangeProperty(Pid::HEAD_SCHEME, QVariant::fromValue(next)); } - cs->setLayoutAll(); - cs->update(); + cs->endCmd(); } } else if (cmd == "show-system-bounding-rect") { From a656b10e1d3b1fe44b0bc28477939a7eeebf9d0d Mon Sep 17 00:00:00 2001 From: "J.G." Date: Thu, 25 Jun 2026 06:48:56 +0000 Subject: [PATCH 04/14] Fix: Tablature and Solfeggio/Pitch Noteheads always draw above staff. Also update printing to file --- libmscore/scorefile.cpp | 22 ++++++++++++++++++++++ mscore/scoreview.cpp | 6 ++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/libmscore/scorefile.cpp b/libmscore/scorefile.cpp index c832b75507e89..eb7b8c8a5f528 100644 --- a/libmscore/scorefile.cpp +++ b/libmscore/scorefile.cpp @@ -1176,6 +1176,28 @@ void Score::print(QPainter* painter, int pageNo) painter->restore(); } } + + // PASS #4 Always draw noteheads with information inside them (Solfegge/Pitch) on top of ledger/staff lines + // NOTE: Must be manually applied and not AUTO Notehead with staff properties, otherwise BehindStaff+BehindLedger + // will still be honored + if (MScore::noteheadsBehindStaff || MScore::noteheadsBehindLedger) { + for (const Element* e : elements) { + if (!e->isNote()) + continue; + if (!e->visible()) + continue; + + auto n = toNote(e); + if (!n->onTabStaff() && !n->headSchemeHasAlphaNumerics()) + continue; + + painter->save(); + painter->translate(e->pagePos()); + e->draw(painter); + painter->translate(-e->pagePos()); + painter->restore(); + } + } MScore::pdfPrinting = false; _printing = false; } diff --git a/mscore/scoreview.cpp b/mscore/scoreview.cpp index ba1f2cd59072f..dc6a588d9b9dc 100644 --- a/mscore/scoreview.cpp +++ b/mscore/scoreview.cpp @@ -1756,15 +1756,17 @@ void ScoreView::drawElements(QPainter& painter, QList& el, Element* ed if (!e->visible() && (score()->printing() || !score()->showInvisible())) continue; - if (!(toNote(e)->headSchemeHasAlphaNumerics())) + auto n = toNote(e); + if (!n->onTabStaff() && !n->headSchemeHasAlphaNumerics()) continue; + QPointF pos(e->pagePos()); painter.translate(pos); e->draw(&painter); painter.translate(-pos); + } } - } if (haveHover && !hoverUnder) { if (state != ViewState::LASSO) { From ea76b30a73499f1bd2ee811d3b1a466e8dbd71b1 Mon Sep 17 00:00:00 2001 From: "J.G." Date: Thu, 25 Jun 2026 06:52:07 +0000 Subject: [PATCH 05/14] Fix: File-Reload duplicate during rebase --- mscore/musescore.cpp | 8 -------- mscore/shortcut.cpp | 10 ---------- 2 files changed, 18 deletions(-) diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index cea6d480304cb..27ae1ffbc7b9b 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -7104,14 +7104,6 @@ void MuseScore::cmd(QAction* a, const QString& cmd) for (auto _score : scores()) closeScore(_score); } - else if (cmd == "file-reload") { - saveFile(); - const auto ms = cs->masterScore(); - const auto fi = ms->fileInfo(); - const auto fn = fi->absoluteFilePath(); - closeScore(cs); - openScore(fn); - } else if (cmd == "file-save") saveFile(); else if (cmd == "file-save-as") diff --git a/mscore/shortcut.cpp b/mscore/shortcut.cpp index be1f82908eea6..68268c4f575b0 100644 --- a/mscore/shortcut.cpp +++ b/mscore/shortcut.cpp @@ -181,16 +181,6 @@ Shortcut Shortcut::_sc[] = { QT_TRANSLATE_NOOP("action","File > Close"), QT_TRANSLATE_NOOP("action","Close current score") }, - { - MsWidget::MAIN_WINDOW, - STATE_NORMAL | STATE_NOTE_ENTRY | STATE_EDIT | STATE_PLAY, - "file-reload", - QT_TRANSLATE_NOOP("action","Reload Current Score"), - QT_TRANSLATE_NOOP("action","File > Reload Current Score"), - QT_TRANSLATE_NOOP("action","Reload current score"), - Icons::fileReload_ICON, - Qt::ApplicationShortcut - }, { MsWidget::MAIN_WINDOW, STATE_NORMAL | STATE_NOTE_ENTRY | STATE_EDIT | STATE_PLAY, From 9eef011c290f3f439aa6d53222b1249de68757b8 Mon Sep 17 00:00:00 2001 From: "J.G." Date: Fri, 26 Jun 2026 00:36:09 +0000 Subject: [PATCH 06/14] Replace quotes with curly-quotes 4.x uses an undo stack to get back to regular quotes if desired. Here I allow ' or " with Ctrl + apostrophe or double quote The flip of start/end was a simple way to make sure that if starting with a " after a full selection that the cursor would be at the beginning and register the proper start quote instead of at the end. MSS4 does this already, but not from this section, so there must be something else going on that fixes it. For now, this works just fine though and should have no repercussions --- libmscore/textedit.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/libmscore/textedit.cpp b/libmscore/textedit.cpp index 307a8fdd42ecc..327ba99ff8d71 100644 --- a/libmscore/textedit.cpp +++ b/libmscore/textedit.cpp @@ -295,6 +295,28 @@ bool TextBase::edit(EditData& ed) //printf("======%x\n", s.isEmpty() ? -1 : s[0].unicode()); switch (ed.key) { + case Qt::Key_QuoteDbl: + case Qt::Key_Apostrophe: + { + // Use CTRL modifier for default vertical quotes (instead of undo stack à la 4.x) + if (ed.control(true)) + break; + + const bool isSingle = (s == u"\'"); + bool useCloseQuote = false; + const int row = _cursor->row(); + const int col = _cursor->column(); + + if (col > 0) { + const QString prev { _cursor->extractText(row, col - 1, row, col) }; + const bool spaceBeforeNewInput = (prev == QString(" ")); + useCloseQuote = !spaceBeforeNewInput; + } + auto curlyReplacement = isSingle ? QString(useCloseQuote ? u'’' : u'‘') + : QString(useCloseQuote ? u'”' : u'“'); + s = curlyReplacement; + break; + } case Qt::Key_Z: // happens when the undo stack is empty if (ed.modifiers == Qt::ControlModifier) return true; @@ -441,8 +463,8 @@ bool TextBase::edit(EditData& ed) case Qt::Key_A: if (ctrlPressed) { - _cursor->movePosition(QTextCursor::Start, QTextCursor::MoveMode::MoveAnchor); - _cursor->movePosition(QTextCursor::End, QTextCursor::MoveMode::KeepAnchor); + _cursor->movePosition(QTextCursor::End, QTextCursor::MoveMode::MoveAnchor); + _cursor->movePosition(QTextCursor::Start, QTextCursor::MoveMode::KeepAnchor); s.clear(); } break; From fe967cb9964e59ae417cd7b581be1073e0b5d338 Mon Sep 17 00:00:00 2001 From: "J.G." Date: Sun, 28 Jun 2026 08:43:20 +0000 Subject: [PATCH 07/14] Curly quote: downgrade code to Qt 5.9 compatibility --- libmscore/textedit.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libmscore/textedit.cpp b/libmscore/textedit.cpp index 327ba99ff8d71..1c4ea5630da5f 100644 --- a/libmscore/textedit.cpp +++ b/libmscore/textedit.cpp @@ -302,18 +302,18 @@ bool TextBase::edit(EditData& ed) if (ed.control(true)) break; - const bool isSingle = (s == u"\'"); + const bool isSingle = (s == QStringLiteral("'")); bool useCloseQuote = false; const int row = _cursor->row(); const int col = _cursor->column(); if (col > 0) { const QString prev { _cursor->extractText(row, col - 1, row, col) }; - const bool spaceBeforeNewInput = (prev == QString(" ")); + const bool spaceBeforeNewInput = (prev == QStringLiteral(" ")); useCloseQuote = !spaceBeforeNewInput; } - auto curlyReplacement = isSingle ? QString(useCloseQuote ? u'’' : u'‘') - : QString(useCloseQuote ? u'”' : u'“'); + auto curlyReplacement = isSingle ? QString(useCloseQuote ? QStringLiteral("’") : QStringLiteral("‘")) + : QString(useCloseQuote ? QStringLiteral("”") : QStringLiteral("“")); s = curlyReplacement; break; } From 9357e5111b8d2b4a77e2aca3bbf83a6630e95454 Mon Sep 17 00:00:00 2001 From: "J.G." Date: Fri, 26 Jun 2026 02:31:58 +0000 Subject: [PATCH 08/14] Status Bar: List-selection now shows information regarding varied list or elements of same type If of the same elemente type, information regarding the first element of that type will be included --- mscore/scoreaccessibility.cpp | 42 +++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/mscore/scoreaccessibility.cpp b/mscore/scoreaccessibility.cpp index 39f489d33b050..e4dab39498620 100644 --- a/mscore/scoreaccessibility.cpp +++ b/mscore/scoreaccessibility.cpp @@ -236,6 +236,7 @@ void ScoreAccessibility::currentInfoChanged(Element* hover) { ScoreView* scoreView = static_cast(mainWindow)->currentScoreView(); Score* score = scoreView->score(); + const Selection& sel = score->selection(); int oldStaff = _oldStaff; int oldBar = _oldBar; _oldStaff = -1; @@ -243,8 +244,24 @@ void ScoreAccessibility::currentInfoChanged(Element* hover) QString oldStatus = statusBarLabel->text(); QString oldScreenReaderInfo = score->accessibleInfo(); clearAccessibilityInfo(); - if (score->selection().isSingle() || hover) { - Element* e = hover ? hover : score->selection().element(); + + Element* singleEl = sel.element(); + QString listString(tr("List Selection")); + if (sel.isList() && !singleEl) { + for (auto el : sel.elements()) { + if (!singleEl) + singleEl = el; + else if (el->type() != singleEl->type()) { + singleEl = nullptr; + break; + } + } + if (singleEl) + listString += " " + tr("of") + " " + QString(singleEl->name()) + "s" + " " + tr("starting with") + ":"; + } + + if (singleEl || hover) { + Element* e = hover ? hover : singleEl; if (!e) { return; } @@ -305,7 +322,13 @@ void ScoreAccessibility::currentInfoChanged(Element* hover) } } - QString rez = e->accessibleInfo(); + QString rez; + if (hover) + rez += tr("Hovering over"); + else if (!sel.isSingle()) + rez += listString; + rez += " " + e->accessibleInfo(); + if (!barsAndBeats.isEmpty()) rez += "; " + barsAndBeats; else @@ -362,13 +385,13 @@ void ScoreAccessibility::currentInfoChanged(Element* hover) } score->setAccessibleInfo(screenReaderRez); } - else if (score->selection().isRange()) { + else if (sel.isRange()) { QString barsAndBeats = ""; std::pair bar_beat; - bar_beat = score->selection().startSegment()->barbeat(); + bar_beat = sel.startSegment()->barbeat(); barsAndBeats += " " + tr("Start Measure: %1; Start Beat: %2").arg(QString::number(bar_beat.first), QString::number(bar_beat.second)); - Segment* endSegment = score->selection().endSegment(); + Segment* endSegment = sel.endSegment(); if (!endSegment) endSegment = score->lastSegment(); @@ -380,9 +403,10 @@ void ScoreAccessibility::currentInfoChanged(Element* hover) statusBarLabel->setText(tr("Range Selection") + barsAndBeats); score->setAccessibleInfo(tr("Range Selection") + barsAndBeats); } - else if (score->selection().isList()) { - statusBarLabel->setText(tr("List Selection")); - score->setAccessibleInfo(tr("List Selection")); + else if (sel.isList()) { + listString += " " + tr("of varying types"); + statusBarLabel->setText(listString); + score->setAccessibleInfo(listString); } } From 03014774661663a873c7d3dae23f6c2d17ab47ac Mon Sep 17 00:00:00 2001 From: "J.G." Date: Fri, 26 Jun 2026 03:20:25 +0000 Subject: [PATCH 09/14] Fix: Mouse Hover - If score selection exists, update status bar when going from hovering to non-hovering to show the score selection info --- mscore/scoreview.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mscore/scoreview.cpp b/mscore/scoreview.cpp index dc6a588d9b9dc..cc03f55f7b449 100644 --- a/mscore/scoreview.cpp +++ b/mscore/scoreview.cpp @@ -2338,8 +2338,9 @@ void ScoreView::updateHover(const QPointF& position) { QPoint point = position.toPoint(); - auto selected = score()->selection().element(); - auto pastHover = dropTarget; + bool noSelection = score()->selection().isNone(); + auto selectedEl = score()->selection().element(); + auto pastHover = dropTarget; const qreal zoomThresh = 0.33; Element* presentHover = logicalZoomLevel() > zoomThresh ? elementNear(toLogical(point)) : nullptr; @@ -2349,7 +2350,7 @@ void ScoreView::updateHover(const QPointF& position) QRectF view; if (pastHover != presentHover) { - if (presentHover && (presentHover != selected)) { + if (presentHover && (presentHover != selectedEl)) { view = presentHover->canvasBoundingRect(); setDropTarget(presentHover, false /*no highlight*/); ScoreAccessibility::instance()->currentInfoChanged(presentHover); @@ -2357,12 +2358,13 @@ void ScoreView::updateHover(const QPointF& position) else if (pastHover) { view = pastHover->canvasBoundingRect(); setDropTarget(nullptr); + ScoreAccessibility::instance()->currentInfoChanged(); } const int margin = 2; update(toPhysical(view).adjusted(-margin, -margin, +margin, +margin)); update(); } - if (!selected && !presentHover) { + if (noSelection && !presentHover) { if (Page* currentPage = point2page(editData.startMove)) { int currentPageNumber = currentPage->no() + 1; int totalPages = score()->npages(); From 6b87f74860803839d31a677e53afaa45fa7c1ef9 Mon Sep 17 00:00:00 2001 From: "J.G." Date: Fri, 26 Jun 2026 10:20:01 +0000 Subject: [PATCH 10/14] Score View: Text Edit: adjust canvas to include minTop & minBottom --- mscore/events.cpp | 4 +++- mscore/scoreview.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/mscore/events.cpp b/mscore/events.cpp index 5bd50b9c47d1e..0d0f63dd07bb6 100644 --- a/mscore/events.cpp +++ b/mscore/events.cpp @@ -1101,8 +1101,10 @@ void ScoreView::keyPressEvent(QKeyEvent* ev) mscore->endCmd(); return; } - if (textEdit) + if (textEdit) { mscore->textTools()->updateTools(editData); + adjustCanvasPosition(e, false); + } return; } } diff --git a/mscore/scoreview.cpp b/mscore/scoreview.cpp index cc03f55f7b449..b7151e57e2ec8 100644 --- a/mscore/scoreview.cpp +++ b/mscore/scoreview.cpp @@ -5576,6 +5576,8 @@ void ScoreView::adjustCanvasPosition(const Element* el, bool playBack, int staff else if (editing){ auto ry = sys->canvasBoundingRect().y(); auto h = sys->canvasBoundingRect().height(); + ry -= sys->minTop(); + h += sys->minBottom(); showRect.setY(ry); showRect.setHeight(h); } From 2d9aa0ca6635902b8e7c72747492e6428a05a327 Mon Sep 17 00:00:00 2001 From: "J.G." Date: Sun, 28 Jun 2026 06:59:13 +0000 Subject: [PATCH 11/14] Customize Splash Screen: Color + 3.7.1 version --- config.cmake | 2 +- mscore/mssplashscreen.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.cmake b/config.cmake index 0d4a0494cb013..b57c55cda6177 100644 --- a/config.cmake +++ b/config.cmake @@ -21,7 +21,7 @@ SET(MUSESCORE_NAME "MuseScore") SET(MUSESCORE_VERSION_MAJOR "3") SET(MUSESCORE_VERSION_MINOR "7") -SET(MUSESCORE_VERSION_PATCH "0") +SET(MUSESCORE_VERSION_PATCH "1") SET(MUSESCORE_VERSION_LABEL "") message(STATUS "MUSESCORE_BUILD_CONFIG ${MUSESCORE_BUILD_CONFIG}") diff --git a/mscore/mssplashscreen.cpp b/mscore/mssplashscreen.cpp index 77a31ddcc7811..a00e7f9815d4a 100644 --- a/mscore/mssplashscreen.cpp +++ b/mscore/mssplashscreen.cpp @@ -37,7 +37,7 @@ const QRectF MsSplashScreen::designMiscTextRect { 25.0, 326.0, 670.0, 56.0 } const double MsSplashScreen::gradientDitherAmount { 0.25 }; -const std::tuple MsSplashScreen::stableBuildGradientColors { "#508BFF", "#1043A9" }; +const std::tuple MsSplashScreen::stableBuildGradientColors { "#d6dfea", "#465c83" }; const std::tuple MsSplashScreen::unstableBuildGradientColors { "#3464C1", "#0C2B6B" }; const QColor MsSplashScreen::textColor { 0xCCFFFFFF }; From 4ef780f488fe580dce5aa29c4b1ccacac9eabb99 Mon Sep 17 00:00:00 2001 From: "J.G." Date: Sun, 28 Jun 2026 03:42:39 +0000 Subject: [PATCH 12/14] Multiple Instances: allow only between other versions (3.6.2/3.7-evolution) but not between this particular version Reason: personal builds get confusing if running multiple times, not knowing for sure which state I'm in if it happens accidentally, while developing. I definitely don't mind having regular 3.7-Evolution running or old 3.6.2 for a quick test here and there, though. --- mscore/musescore.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index 27ae1ffbc7b9b..f8795c54915d0 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -8586,7 +8586,7 @@ MuseScoreApplication* MuseScoreApplication::initApplication(int& argc, char** ar appName = "MuseScore3Development"; } else { - appName2 = "mscore3"; + appName2 = "mscore3www"; // allow multiple instances between other builds using different names, but not this very project appName = "MuseScore3Evolution-WWW"; // to maintain separate .ini file in ~/.config etc } @@ -8921,6 +8921,10 @@ MuseScoreApplication::CommandLineParseResult MuseScoreApplication::parseCommandL return parseResult; } } + else if (app->sendMessage(QString(""))) { + parseResult.exit = true; + return parseResult; + } } if (rawDiffMode || diffMode) { if (argv.size() != 2) { From 938d4a64e8587b1622316d74fa53de7232180a2e Mon Sep 17 00:00:00 2001 From: "J.G." Date: Mon, 29 Jun 2026 08:27:32 +0000 Subject: [PATCH 13/14] CmdState:: Ever so slightly updated dump message --- libmscore/cmd.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libmscore/cmd.cpp b/libmscore/cmd.cpp index 69a1ff7c8fa4b..eb39e4697f84c 100644 --- a/libmscore/cmd.cpp +++ b/libmscore/cmd.cpp @@ -300,10 +300,14 @@ void Score::endCmd(bool rollback) void CmdState::dump() { - qDebug("CmdState: mode %d %d-%d", int(_updateMode), _startTick.ticks(), _endTick.ticks()); + qDebug().noquote().nospace() + << "CmdState: mode " << int(_updateMode) << " " << _startTick.print() << "-" << _endTick.print() << " " + << (_el ? _el->name() : "no element") << " " + << (_el ? _el->tick().print() : "") << " " + << "mbase: " << (_mb ? _mb->index() : 0) + ; // bool _excerptsChanged { false }; // bool _instrumentsChanged { false }; - } #endif From ad3b2f290684fbc9e53070044d694075da04e96a Mon Sep 17 00:00:00 2001 From: "J.G." Date: Mon, 29 Jun 2026 08:23:04 +0000 Subject: [PATCH 14/14] Fix: Full score layout when traversing empty lyrics Found this by seeing score layout act funny with the new progress bars The bug is present in 3.6.2 and 3.7-evolution currently. It may also affect other texts like staff text when skipping with alt+right etc, but not sure --- libmscore/cmd.cpp | 2 ++ libmscore/score.h | 1 + libmscore/textedit.cpp | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/libmscore/cmd.cpp b/libmscore/cmd.cpp index eb39e4697f84c..c5bca886d6c98 100644 --- a/libmscore/cmd.cpp +++ b/libmscore/cmd.cpp @@ -130,6 +130,8 @@ void CmdState::setTick(TickType tt, const Fraction& t) _startTick = t; else if (tt == TickType::EndTick) _endTick = t; + else + _startTick = _endTick = t; setUpdateMode(UpdateMode::Layout); } diff --git a/libmscore/score.h b/libmscore/score.h index 681c1a21d7ded..991c43367c1a1 100644 --- a/libmscore/score.h +++ b/libmscore/score.h @@ -259,6 +259,7 @@ enum class UpdateMode { enum class TickType { // for explicit cmdState updates StartTick, EndTick, + StartAndEndTick, }; //--------------------------------------------------------- diff --git a/libmscore/textedit.cpp b/libmscore/textedit.cpp index 1c4ea5630da5f..f16e82ab3f05e 100644 --- a/libmscore/textedit.cpp +++ b/libmscore/textedit.cpp @@ -167,6 +167,10 @@ void TextBase::endEdit(EditData& ed) Filter::Link, }; + // Force updating the cmdState, otherwise a 0/1 starting tick will trigger a full layout + // when the endCmd performs score->update() + score()->cmdState().setTick(TickType::StartAndEndTick, tick()); + if (!emptyUndo && newlyAdded && !undo->current()->hasUnfilteredChildren(filters, this)) { for (Filter f : filters) undo->current()->filterChildren(f, this);