Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New score and parts interactions #18722

Merged
merged 14 commits into from
Sep 26, 2023

Conversation

mike-spa
Copy link
Contributor

@mike-spa mike-spa commented Jul 20, 2023

Resolves: #16544

This PR provides a number of important, long-awaited new functionalities on the interaction between score and parts. A short summary:

  • After a part has been created, changes made in the score also affect the part (this is currently not the case for most properties).
  • Changes made in the part never affect the score. In fact, soon as an item is edited in one part, it will be marked as unlinked and, when selected, will turn orange. Changes made to the score will not affect items that have been unlinked.
  • Items can be re-linked by using two toggles in a new dedicated section of the property panel which separately control the linking of "Position" and "Appearance" properties. The "Reset shapes and position" command (ctrl+R) also has the effect of re-linking the item properties to the main score.
image
  • For a few selected item types (namely Staff text, System text, Clefs, Ottava lines, and frames) a new possibility is now introduced to exclude the selected item from the part (or from the score). This enables to introduce items that may be relevant only in the score (or only in the part), and currently can't be achieved by making the item invisible. When ottavas and clefs are excluded from parts or score, the notation updates accordingly. Importantly, frames (with the exclusion of title frames) default to be excluded. This can also be controlled via a new option in the property panel.
image

@mike-spa mike-spa force-pushed the partScorePropertyLinking branch 4 times, most recently from 7d926f9 to 20eb630 Compare July 27, 2023 15:56
@mike-spa mike-spa force-pushed the partScorePropertyLinking branch 4 times, most recently from f72747d to 27517cb Compare August 1, 2023 13:19
@mike-spa mike-spa force-pushed the partScorePropertyLinking branch 2 times, most recently from 70df530 to 74da07b Compare August 18, 2023 16:06
@mike-spa mike-spa force-pushed the partScorePropertyLinking branch 9 times, most recently from 424e4db to f6c7b02 Compare August 29, 2023 07:27
@mike-spa mike-spa changed the title Part score property linking New score and parts interactions Aug 29, 2023
@mike-spa mike-spa marked this pull request as ready for review August 29, 2023 08:16
@cbjeukendrup cbjeukendrup force-pushed the partScorePropertyLinking branch 2 times, most recently from fc9b1e6 to 9554aa1 Compare September 19, 2023 10:11
@cbjeukendrup
Copy link
Contributor

Found a bug:

  1. Add ottava
  2. Exclude it from parts
  3. Drag a note in a part => the note does not properly follow the mouse. It always stays an octave higher than the mouse. (the laggy-ness is just my computer; that's not the problem.)
Schermopname.2023-09-24.om.20.59.31.mov

@cbjeukendrup
Copy link
Contributor

Another questionable bit of behaviour:

  1. Select a system header clef
  2. Enable "exclude from parts"
  3. Disable "exclude from parts" => Now there is suddenly a new clef in the parts, that is not a system header clef but a real clef change! But that clef change is not in the main score.
  4. Enter some notes before and after the system break in question, via the main score
  5. When I then switched to the part score, MuseScore crashed.

So the question is: should the "exclude from parts" checkbox be available for system header clefs? And if yes, how should it behave?

@cbjeukendrup cbjeukendrup force-pushed the partScorePropertyLinking branch 2 times, most recently from 34c65c6 to 375421e Compare September 25, 2023 00:27
Copy link
Contributor

@cbjeukendrup cbjeukendrup left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not entirely trough it, but here are some comments and questions already!

src/notation/internal/masternotation.cpp Outdated Show resolved Hide resolved
src/inspector/models/parts/partssettingsmodel.cpp Outdated Show resolved Hide resolved
Comment on lines 448 to 450
extern const std::set<Pid>& positionProperties(); ///< All the properties that have to do with the position of an item
extern const std::set<Pid>& textProperties(); ///< Text body of text items
extern const std::set<Pid>& appearanceProperties(); ///< All the properties that are not position or text properties
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the ways these methods are currently used, I'm thinking it might be more elegant to add a propertyGroup field in PropertyMetaData / propertyList. This has some advantages:

  • it forces each property to be in a category (we'd need to add a "none" category for those special excluded properties though) without the need for that logic in appearanceProperties()
  • retrieving the category of a property can be done in constant time
  • the stuff in EngravingItem::relinkPropertiesToMaster may become a bit cleaner in terms of code (just iterate over all properties and check propertyGroup equality) without becoming very different in terms of functionality and performance
  • it might be a slightly more extensible approach, if we ever introduce other categories


if (score == this) {
result = newMeasureBase;
} else if (!result && score == scores.back()) {
result = newMeasureBase;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this change? It looks like this could cause that the returned MeasureBase* points to a measure that is not part of the Score* on which insertMeasure was called. Is that desired?

src/engraving/dom/engravingitem.cpp Show resolved Hide resolved
return PropertyPropagation::NONE;
}

bool EngravingItem::canBeExcludedFromOtherParts() const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a specific reason to choose for this implementation instead of making this a virtual method? I consider it closely related to manageExclusionFromParts, which is virtual, so I'd personally prefer to keep these methods close to each other.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly because for such simple methods I hate to spread the information across 10 different files: it makes it harder later to find what I need, for no real benefit. I agree that in this case it looks more consistent with manageExclusionFromParts though

score()->undo(new ChangeTextProperties(m_cursor, id, v, ps));
} else {

bool isTextSpecificProperty = id == Pid::FONT_STYLE || id == Pid::FONT_FACE || id == Pid::FONT_SIZE || id == Pid::TEXT_SCRIPT_ALIGN;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I see a lot more properties listed than in textProperties(). Of course, this is about something different, so the list need not be the same, but still... shouldn't these properties also be in textProperties()? Or otherwise, why only FONT_STYLE and these others not?

}

Score* linkedScore = linkedText->score();
TextCursor* linkedCursor = linkedText->cursor();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I understanding correctly that this is about setting properties to selected characters of the text (and that that is the reason that TextCursor is being used here)? In that case, can we be certain that the linkedCursor is synchronised with the "original" one? If it's not, I'm afraid that could give quite strange results, couldn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this gets called also when changing the property of the "full" text item, without necessarily entering edit mode and therefore having an actual cursor. linkedCursor is a default-initialized one, it's not actually linked to the present cursor. When editing individual characters things get more complicated and indeed there are still imperfections, but that's a minor case that can (and will) be smoothed out later. The format of the full text works fine as expected

@mike-spa
Copy link
Contributor Author

Found a bug:

  1. Add ottava
  2. Exclude it from parts
  3. Drag a note in a part => the note does not properly follow the mouse. It always stays an octave higher than the mouse. (the laggy-ness is just my computer; that's not the problem.)

@cbjeukendrup not a blocker. There's a plan to open an issue with a checklist of quirks and refinements as soon as we merge this. Let's add it there and I'll work through it together with with the rest.

@mike-spa
Copy link
Contributor Author

Another questionable bit of behaviour:

  1. Select a system header clef
  2. Enable "exclude from parts"
  3. Disable "exclude from parts" => Now there is suddenly a new clef in the parts, that is not a system header clef but a real clef change! But that clef change is not in the main score.
  4. Enter some notes before and after the system break in question, via the main score
  5. When I then switched to the part score, MuseScore crashed.

So the question is: should the "exclude from parts" checkbox be available for system header clefs? And if yes, how should it behave?

@cbjeukendrup also not a blocker, same thing as previous one. Btw no, for header clefs the "exclude from part/score" checkbox shouldn't be available, and I was sure it wasn't, so I'll have to check what's happening.

@mike-spa
Copy link
Contributor Author

@cbjeukendrup all done! Let's merge soon if we can 👍

MeasureBase* scoreMeasure = score->first();

if (!scoreMeasure || !scoreMeasure->isVBox()) {
if ((!scoreMeasure || !scoreMeasure->isVBox()) && !masterMeasure->excludeFromOtherParts()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: this causes a crash when creating parts for a score that contains no measures nor boxes. Although 4.1.1 also shows some funny behaviour in that situation, it does not crash, so this will be a regression.

(just making a note of it so that we can log/fix it later)

(a little bit)
Copy link
Contributor

@cbjeukendrup cbjeukendrup left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🥳🥳🥳🥳🥳

@cbjeukendrup
Copy link
Contributor

@mike-spa I'll leave the honour of pressing the big green button to you! I've already rebased #19127 on top of this; that looks a bit messy now, but it will be alright.

The procedure is now as follows:

  1. Merge this PR to master and refresh your local master branch
  2. Pull the latest version of #19127 to your computer
  3. Rebase that on top of master -> there should be no conflicts, because I've already fixed those
  4. Push -> now #19127 should only contain the commits that belong there
  5. Merge #19127

(Don't wait for me tomorrow morning, I'll probably be late!)

@mike-spa mike-spa merged commit 62fe329 into musescore:master Sep 26, 2023
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Fix linking between score and parts
2 participants