More systematic layout for articulations
It seems many layout issues with articulations (like dependence on order and interactions with slurs) have to do with special casing of the code. I would like to propose a better way to handle articulation layout.
I'm going to assume a chord may not have more than one of the same articulation, and that slurs should not be allowed to collide with them by default.
A score's style has a list defining the placement of all articulations. Each entry has a direction (above, below, auto) and some spacing parameters (min distance above, min distance below). The order of entries in this list determines the stacking order when multiple articulations are placed on a chord on the same side.
The list also contains a couple of meta-elements: the "staff-chord separator" (above which articulations anchor to the notes if within the staff) and the "slur anchor" (the position for a slur, if present, relative to other articulations).
Each chord in a score has two lists of articulations, one for each side. They are initially empty, except for the meta-elements. As articulations get added to the chord, they are inserted into the appropriate list according to the style's order and direction. Pressing X on an articulation moves it into the other list, but otherwise still obeying the style order. The order of these lists may be overridden individually for a specific chord.
Every articulation may be stacked onto a note on the same side, if desired, and should stack properly. The larger of the two minima will be considered for each adjacent pair of articulations.
There are some exceptions to the spacing rules. The slur anchor is only considered if there is a slur on that side. The staff-chord separator is only considered if within the staff. Articulations within the staff have their minimum distances rounded to the nearest space (so an articulation that needs at least 1.25 spaces between itself and the next articulation will need 2 spaces if placed within the staff).
The list may look like this: (many elements removed for brevity)
[Note]
Tenuto: auto, 0.25, 0.25
Staccato: auto, 0.25, 0.25
Sforzato: auto, 0.5, 0.5
[Slur anchor]
[Staff-chord]
Fermata: above, 1.0, 1.0
Here's an example:
If the user enters a downstem chord with a tenuto, a staccato, a sforzato, and a slur, their y positions would be in that order with 0.5sp between each, and all would be positioned notehead side (above). The "up" articulation list would contain all of these elements and the "down" list would be empty.
If the user then adds a fermata, it would go into the "up" list and be positioned 1sp above the slur.
If the user presses X on the slur, it anchors to the "down" list's slur anchor, and the fermata moves to 1sp above the sforzato.
If the user presses X on the sforzato, it moves to the "down" list (and becomes locked there by setting its direction property), moving the fermata down further, and moving the slur below the sforzato.
If the user changes the style and moves the sforzato entry past the staff-chord entry, the slur moves back and the sforzato moves past the staff.
I'm sure I'm missing a few cases, but I think this is a step in the right direction for a more consistent, extensible articulation editor.
Comments
I agree that ultimately we should mvoe to something like this. There are additional complications, BTW - some markings need to center between staff lines whereas some can overlap them; we need to behave reasonably on staves with non-standard spacing, etc. But I too would prefer much less special casing and instead have some sort of table-driven algorithm, ideally with the contents of the table under some amount of user control (if not necessarily every last aspect of it).
Examples of issues with the current system include #94546: Bad layout of articulations and slurs and #76046: Apply collision avoidance rules for marcato to sforzato accent as well.