Plugins API design for MuseScore 3
Full plugins support is the commonly requested feature for MuseScore 3, and I am currently working on its implementation. Regarding that there are some questions on certain aspects of plugins API designs which can be resolved differently, at least until this gets merged into release builds. So I would like to ask for your opinion on how would it be better to make these API parts.
Properties of elements
In its recent revision the handbook page on plugins for 3.0 says that the new way to access elements properties is via
set() functions (where
set is not working actually). Still I see some drawbacks of this solution:
1) It is less convenient to use (as it seems to me). For example (from Note Names plugin),
text.text = qsTranslate("InspectorAmbitus", "F♭♭") + text.text;
text.set("text", qsTranslate("InspectorAmbitus", "F♭♭") + text.get("text"));
2) It causes more changes on code updating from 2.X plugins API.
3) It may cause inconsistencies with other properties for which it doesn't make sense to include them to the common libmscore properties system (which makes plugins updating even more difficult). For example, position offsets for elements (which would be, for example,
offsetY), score properties (number of staves, measures etc.) or container properties (e.g. list of notes in chord) are not included to this system now. On the other side it is always possible to implement getting them by name too.
On the other side, there are some advantages in this approach:
1) It is very easy to implement on C++ side (unless we decide to add a large number of new
Pids to resolve the issue 3) from the list above).
2) In case we need some operations other than getting, setting and resetting properties, this approach will allow to make such operations available in a similar way.
I can try to make properties available via the old syntax, but maybe there drawback are not so critical, or there are some other reasons why the
get("name")/set("name") approach is more preferable?
Properties vs functions
The mentioned above handbook page mentions a change from
cursor.element properties to
cursor.element() functions. I don't see any reasons for such a change so I reverted it in my branch, but perhaps there are still some reasons to prefer the latter way?
The page also mentions change between namespaces for element types enumeration. I suggest having a
Element::type property that actually returns a string instead of enumeration value. The reasons are:
typeofreturns a string rather than any possible numbers or special enumerations).
- This solution does not depend on enumeration namespaces in any way.
- It is actually already used: see the source code of Chord Identifier plugin where
Element::_name()is used for checking elements types. I just propose to make this a main way to check elements types.
The same would apply for element creation: instead of
var text = newElement(Element.STAFF_TEXT);
one would have to write
var text = newElement("StaffText");
Enumeration properties values
These suffer from the same problem as element types: most of enumerations have renamed, and once we expose enumerations used inside libmscore again we are bound not to rename its values and not to move it anywhere. So there is an option to make some string-based interface also available for them. Personally I would prefer not to do it right now as the benefit for them is not so large as it seems to be for element types, and it it much more difficult to implement for them than for element types. So maybe it would be sufficient to have just renamed enumerations for such cases.
Possible API expansions
Just a quick list of what may be useful (or not useful) to add:
- Fractions instead of / alongside with ticks: fractions are more natural to use than ticks (for example, 1440 ticks will become 3/4 in fractions), and they may be more precise in some situations.
- Selection API: I saw some mysterious tricks with
Cursorobject in plugins code just to define whether a score has a selection. Having an explicit selection API will help to avoid the necessity for those tricks.
- Styles API: maybe it could be useful to have an API to access and modify styles values. Not sure whether it is needed but If you find it useful please let me know about that.
- Persistent dock widgets: currently there are "dock" type plugins which provide some docking widgets. Still one has to relaunch such plugins on each MuseScore restart. Maybe it would be convenient to have MuseScore to remember plugins widgets positions and relaunch them on start. This will be useful, of course, only if there is an API that is powerful enough to make some often tasks more convenient, maybe some API for updating a plugin state on score change would be needed for that. That is a more distant perspective though, and is not too relevant to this topic right now.
So it would be great to hear your feedback on these issues. Other suggestions on plugin API design are also welcome!