QML api: "Select an element" needed so plugins can search
Reported version
3.x-dev
Type
Plugins
Frequency
Once
Severity
S5 - Suggestion
Reproducibility
Always
Status
closed
Regression
No
Workaround
No
Project
The desirability of having plugins to look for a specific thing, e.g., a certain harmonic or contrapuntal feature, or, most significantly, a word or string of lyric or text, seems self-evident.
All that is needed (as far as I can tell) is the ability to select an extant element (as does clicking single on it) exposed to QML.
Fix version
3.5.0
Comments
Added pull request to satisfy this issue:
https://github.com/musescore/MuseScore/pull/5259
See that attached QML script for example of use.
-Dale
"Well, ain't that special!??!" Fantastic. Do you have a merged branch with the previous stuff I can clone? Thanks so much; what an elegant solution!
Sure... This branch on my MuseScore fork has everything I'm working on...
https://github.com/DLLarson/MuseScore/tree/uber-commit-ties-pos-selecti…
It has the note.tieXX stuff, a bunch of exposed element position properties stuff, plus the new selection stuff.
-Dale
The ability to select elements from plugins could certainly be useful but I believe it should be added with some caution. While preparing 3.0 release (and perhaps some time after it) we had a lot of issues related to wrong elements being somehow added to a selection, for example, some elements that may get deleted during a re-layout (Brackets for example). Such elements are better not to be added to a selection. Other elements (like Measure, Segment) cannot normally be directly added to a selection, and it is not clear what can happen if we put such an element to the selected elements list.
Unfortunately
libmscore
does not currently have any mechanism to determine which elements can be added to a selection and which cannot. Some information on which elements are probably safe to be selected programmatically can be found in UndoStack implementation as we try to make selection undoable in the cases when it is most necessary and safe to implement. Maybe for the time being the same set of restrictions (maybe with some exceptions like Chord type) could be applied for plugins too.What should be probably safer to implement is allowing a range selection: it is enough just to define its boundaries and all the relevant elements will be found automatically.
So, to sum up, for now it seems to be better to an ability to select only a limited subset of elements and/or an ability to select a range of a score. Does this make sense for this feature request?
By the way, concerning the "so plugins can search" part, it should be also needed to allow plugins to adjust score view position (either by specifying a position directly or by going to a specific element), otherwise it may happen to be not easy to figure out what exactly a plugin has found.
These are reasonable reservations; the rest of "search" (e.g., position the score) is needed. The largest "search" thing I currently find missing is find text, extremely important to me because I write (to the joy of many) pamphlet/book texts in many of my scores and cannot find text I have entered. But a lot is missing for that, including QML visibility of frames, words within text, and more. Finding a particular chord or stack of notes (in a part or the score) would be great, too. I had hoped that this would be the start for experimentation, but so much more is needed (and I am studying the source). This should not be on a 3.3 timeframe, obviously.
using the cmd("select-similar") you can select every element of a given type, and then loop through the selection, but that requires an initial selection from the user.
See these two plugins for an example: https://musescore.org/en/project/rehearsal-marks-management
In reply to using the cmd("select… by ecstrema
That doesn't match any of my plans, i.e., commands that find a specific element meeting some criterion and select it (and scroll to it).
dmitrio95 Your concerns are understandable, but these are plugins. It should be made clear to plugin developpers that selecting elements is risky, but that PR doesn't change anything to non-plugin users, doesn't it?
@BSG have you tried cmd("select-all") and looping through the selection?
Summary of what you could do:
1.cmd("select-all")
2.find your element
3.loop through the element's parent (recursion?) to find a measure.
4.cmd("select-next-measure") until you find the measure (the tick is the only thing I could compare here to check if i had found my measure)
5. cmd("staff-text") to scroll down to your element. then cmd("escape") to exit staff text entering mode. or maybe cmd("play"), so the cursor show you where you are.
for the cmd commands, this thing is pretty useful: https://github.com/calculuswhiz/musescore-utils/blob/master/ValidComman…
Of course, this is unconvenient, it it still gives some possibilities...
Can't say I thought of that! I will look into your technique ... thanks!
@dmitrio95 what about unselecting?
@BSG if only https://github.com/musescore/MuseScore/blob/0b55077b2e79e075486ee1675d9… could make its way to the plugin API...
Deselecting elements should probably be a lot safer to implement in plugins API. In fact I believe it should probably be relatively safe to implement the following operations:
- Clearing selection;
- Removing elements from a selection;
- Selecting a range of a score (defined by ticks and staves range);
- Selecting elements from a limited set of types, as it is unclear how to handle selection of elements that may potentially be deleted a bit later.
Concerning your second comment, as I mentioned above, it would indeed be logical to expose to plugins some part of
ScoreView
's functionality in the context of this feature request, maybe it could indeed be some functions likegotoMeasure()
oradjustCanvasPosition()
or even just something to simply set a viewport for a score view (maybe something similar to this).For now the easiest method to add a command to the API looks to be adding it to the
cmd
commands. MaybegotoMeasure
could be implemented that way...Ex:
cmd("go-to-measure-22")
would callsearchMeasure(22)
but that would be better implemented directly in the plugin api: override the
cmd
function by creating acallCmd
which would filter the cmd call and transfer it the usualcmd
if needed.The cmd called by plugins would look like (sorry, can't do any c++ recently, so i don't remember all these function names so well...)
void callCmd(const Srtring* command) {
// filter command ex:
if (command.startswith("go-to-measure-"))
searchmeasure(command.findTheEndOfThatCmd)
}
else{
// Keep filtering with other commands
}
//delegate to normal cmd:
else{
cmd(command.tochararray())
}
<\code>
In reply to Can't say I thought of that!… by [DELETED] 1831606
@BSG Just tried the technique above. Unfortunately, cmd select all selects the whole range of the score. This means text, barlines, etc. are not part of the selection...
In my case it worked because I had to look only into rehearsal marks, so I could ask the user to select one and use
cmd("select-similar")
but that wouldn't work to loop through all text elements...Here is a PR which implements my suggestion here regarding possible ways to select elements: https://github.com/musescore/MuseScore/pull/6091
In reply to Here is a PR which… by dmitrio95
This is terrific; what types of elements may be selected? Are texts included?
Yes, texts are included. It is the same list of types which is used to preserve selection on undo/redo operations (defined here): currently notes, rests, most of text elements (except for instrument names which are probably not accessible yet from plugins anyway) and fretboard diagrams. This list can certainly be changed in future but probably only by including more element types in it.
Fixed in branch 3.x, commit da65f99afd
_fix #293017: add a possibility to change selection from plugins
Also expose range selection properties in Selection object_
Fixed in branch 3.x, commit 6be170fd77
_Merge pull request #6091 from dmitrio95/plugin-api-selection-change
fix #293017: add a possibility to change selection from plugins_
Automatically closed -- issue fixed for 2 weeks with no activity.
How do we actually use it though? Neither curScore.selection.add or curScore.selection.elements.add are defined when I try...
In reply to How do we actually use it… by Dylan Nicholson1
Figured it out, can use curScore.selection.select( ) and curScore.selection.deselect( ). Only worked that out from some runtime javascript reflection though...