-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Parse dynamics when finished editing #25396
base: master
Are you sure you want to change the base?
Conversation
@CMakeScore You noted that you can use Ctrl + Shift + [character] to enter the proper dynamic character, which works, but it looks like you've also included some handling for automatically changing regular text to dynamic characters after editing (if that's all you've typed). This is an awesome addition, but there are a couple bugs and some room for improvement if you're willing to take it on. Screen.Recording.2024-10-22.at.4.44.31.PM.2.movBug: Replacing selected text (0:00–0:17 in video)If I double click into an existing dynamic to select the text, the first character I type does not appear.
This appears to be a preeexisting issue (at least in MSS 4.4), but since we didn't really previously provide much utility to typing in dynamics, I think we should aim to fix it in this PR. Request: Format known dynamics while typing (0:18–end of video)Ideally, anytime you begin a "word" in a dynamic text field with a character that typically starts a dynamic (p, m, f, s, or r), it should show up as a dynamic character while you're still editing the field. If you start a word with any other character, or you type a space and add expression text, it should look like expression text. You know you want a dynamic, so why require modifier keys to get the right characters? We should essentially recognize if the user is typing any of the existing dynamics in palettes until the string stops matching (i.e. another letter or a space is typed). Ideally, we would also retain the ability to prepend expression text by typing before a dynamic (and append after). Example 1:
Example 2:
Would much appreciate the bug fix to get this merged, and if you want to take on the request too, even better. If not, we can just turn that part into a feature request. Thanks! |
Before working on that request, it might make sense to do #25229 first. Otherwise, we're creating even more complexity right now, that will all need to be considered during the refactor task. |
Thanks for the context @cbjeukendrup. I'd then recommend fixing that bug (if not too difficult) and merging this, since the Add dynamic shortcut isn't very useful without at least the basic parsing of dynamics that's already been implemented. The request section can be saved for later implementation. |
21e8a53
to
f9c396e
Compare
@avvvvve I’ve identified the cause of the bug you mentioned and committed a fix. |
710f891
to
d2043bf
Compare
@CMakeScore Thanks for making quick work of this! Really nice solution you've come up with and I think people will be really excited to use this. I'll create another feature request to render dynamic characters as they're typed so we at least have it recorded. @cbjeukendrup Ready for code review |
Dynamic characters are not synced when parts exist Untitled.mp4 |
a5b3ef8
to
c70a897
Compare
deleteSelectedText() updates the font family and must be executed before setting the new font family.
c70a897
to
1bfd1d2
Compare
Fixed a problem with synchronization with the part. Edit: |
src/engraving/dom/dynamic.cpp
Outdated
for (size_t i = 0; i < n; ++i) { | ||
if (TConv::toXml(DynamicType(i)).ascii() == matchStr || DYN_LIST[i].text == matchStr) { | ||
utf8Tag.replace(match.position(0), match.length(0), DYN_LIST[i].text); | ||
setXmlText(String::fromStdString(utf8Tag)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setXmlText(String::fromStdString(utf8Tag)); |
In principle this function should have a single responsibility - parsing and returning dynamics - so I don't think we should also be mutating the object with setXmlText
here.
It might be easier said than done, but moving this call up to setDynamicText
would be more cohesive. Once that's done we can make parseDynamicText
a const function, and we can perhaps even make it private after the suggested changes to textedit.cpp
.
const DynamicType dt = d->parseDynamicText(xmlText()); | ||
undoChangeProperty(Pid::DYNAMIC_TYPE, dt); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we can't do something like this?
const DynamicType dt = d->parseDynamicText(xmlText()); | |
undoChangeProperty(Pid::DYNAMIC_TYPE, dt); | |
d->setDynamicType(xmlText()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that I need to call undoChangeProperty
to set the dynamic type consistently across all parts. Otherwise, for example, if you add or edit the dynamics in a part score, the playback will not reflect those changes.
However, while calling undoChangeProperty
from within Dynamic::setDynamicType
seems fine at first glance, the program crashes when I copy and paste the dynamic. This led me to believe that something is wrong, so I refrained from doing so.
Split from #25252
With this PR, dynamics you type with Ctrl+Shift+Alphabets will be interpreted and reflected in the playback.