-
Notifications
You must be signed in to change notification settings - Fork 19
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
Support style properties with a uniform mechanism #263
Comments
I've read your proposal slowly and in detail and I only have one brainstorming comment, for your consideration. I'm not sure about the priority hierarchy. I have no experience in dealing with styles so my naive first idea would be to give maximum priority to any style in the target element itself: • the target element itself As I deduce from your proposal, any style in the target element itself will be overridden by style in |
Here are some examples. They include many freely invented style properties, so please don't take those literally: these are just meant to illustrate the structure. Explicit properties on a target<mnx>
<part>
<measure>
<sequence>
<directions>
<expression color="#0000FF">...</expression>
<event>
<note color="#0000FF" .../>
...
Properties inherited from an ancestor<mnx>
<part>...</part>
<part>
<measure color="#0000FF">
<sequence>
<directions>
<expression>...</expression>
<event color="#FF0000">
<note .../>
...
Properties inherited from a global measure<mnx>
<global>
<measure index="1" color="#0000FF">...</measure>
</global>
<part>...</part>
<part>...</part>
...
Document-wide properties inherited from
|
@cecilios I agree that the priority hierarchy might be wrong. I think it's important to have one, but my initial stab at it might be flawed (and particularly on this point of explicit style properties). Let's continue looking at examples and fleshing out what behavior is most useful. |
I'd propose to reconsider the abbreviation Apart of that, your examples looks great to me. Nothing to comment. |
Trying to understand how styles will work, and the priority hierarchy for styles, I've done the following analogy to html/css
In CSS/Html the priority of styles that apply to a specific element is as follows (highest priority first): • Inline styles Thus, if we would like to mimic CSS/Html behavior, probably the best ordering for MNX would be (highest priority first): • the target element itself, followed by its ancestors (except |
Hmm... I feel like the layout/score should be able to override properties explicitly defined on the target elements, especially things like stem direction and maybe color. What if you want a score display with every measure a different color of the rainbow, but the score has each element specifically encoded as "black"? |
@clnoel This is exactly the same situation as with CSS/HTML: HTML is the document content and should not contain style. And CSS is the layout/styling. HTML should not include any style, for good separation between content and layout/style. If HTML does not include any style, you have full control of how content is displayed by choosing another css style sheet. But if HTML contains style, it has priority and the style sheet cannot override it. It is not a problem of HTML/CSS design but a problem created by not putting layout/style were it should be: in the style sheet. Here we have the same situation. We would like (I hope) to achieve good separation between music content and layout/style. Thus:
We could do it the other way, In any case, to enforce good separation between content and layout/style I think it is better to give priority to style in the A second argument, is my first example (#263 (comment)): if an application would like to override the style for an specific element, by giving priority to style in the |
I am starting to come around to @cecilios's proposal that style properties in
But here's a potential fly in that soup: some properties like Fortunately the set of overridables here seems small and bounded. Perhaps we allow the layouts to apply a different set of properties that are understood to have a special override behavior (e.g. |
With HTML and CSS, global CSS styles do override HTML attributes. Only inline CSS (in the element's For example, here is a basic HTML document without any CSS styles. The
In this example, the global CSS defined in the
But here, inline CSS in the
Regular HTML attributes are overridden by global styles, but both HTML attributes and global styles are overridden by inline styles. Could this paradigm be adapted to help solve the problem? |
@samuelbradshaw Essentially that's the exact behavior being proposed by @cecilios, which I agree with. |
I'm also broadly in agreement with @cecilios proposal but, as @joeberkovitz said:
I think #252 needs to be settled before we can continue here, so am continuing there... |
Here is an update of the proposed styles architecture. It accounts the feedback on priorities, and has been harmonized with the CSS specification so that the things MNX does line up with a subset of CSS, conceptually speaking. (We are still not using any CSS syntax, no worries on that score.) I don't think this changes any of the examples given already. Of necessity this is somewhat technical, even though it is a tiny subset of the CSS mechanism. If you don't want to get into the weeds, you can look at the examples elsewhere. Target elements and style properties"Target elements" are notational content to which styles may be applied. They are restricted to the semantic hierarchy at/under Style properties are meant to control a target's appearance and/or performance. Simple examples are color, volume, font, size. Style properties are optional, and have default values supplied by the specification and perhaps by the rendering application. Style properties are declared in the document only when they override these defaults. As a corollary, the style mechanism can be completely ignored by documents that are not interested in modifying the defaults. Style sourcesMost elements in an MNX document can serve as a style source. This means that they include one or more declarations that apply style properties to a set of target elements. The following kinds of style sources exist:
(Note: unlike CSS, class definitions cannot match on both element name and class name. That's a possible future enhancement.) Computing valuesThe first step in determining the value of a style property for some target element is to find all of its style sources, and collect the declared values in a list. The list is sorted into the following categories in the given priority order:
Each of these categories is then sorted internally so that later declarations in the document take priority over earlier ones. For scores and layouts, this has the effect that more specific elements override their ancestors. It also means that when multiple class names or specific values are provided in a target element, later ones override earlier ones. The first value in the final sorted list is adopted as the computed value of the style property. If the list is empty, then there is no computed value. Defaulting valuesIf no computed value is found for the target element in the previous step, and the property is inherited (most will be), the ancestors of the target element are searched by ascending the element chain. If For each ancestor consulted during this search, its computed value is examined. If one is found, the search terminates and that value is used as the target element's default value. If no computed value is found on an ancestor and the search completes at |
Would it make sense for |
@samuelbradshaw I think this change is possible, but my guess is it doesn’t give us much because a page does not need to belong to classes or inherit properties from ancestors (the only one is Note: A page can already override default styles by defining classes, and so could affect the style properties of the content inside it as in your color example. |
As to the “Computing values” section, it looks ok to me but I have doubts about if it is just illustrative, to understand priorities, or it is also some kind of guidelines for implementing the algorithm to determine the value of a style property for some target element. And this raises an off-topic issue: Will the MNX specification provide some algorithm for processing styles? If the group considers this to be something worth exploring it would be good to open an issue for it, in due time. |
@cecilios The language in my post is illustrative, but it's as accurate as I can make it, and you should try it out on examples to see if it behaves correctly. Yes, I think there has to be an actual algorithm, which I was planning to spec out in a PR rather than in this issue. I think the pull request is where the really fine details will be worked out. For the latest worked example please jump ahead to this post: #263 (comment) Click on the text below to expand the originally-posted worked examples which have been superseded: Original worked exampleHere is a fully worked example of the algorithm with a toy document:<mnx>
<global>
<measure index="1" preferred-width="10st"/>
<measure/>
</global>
<part name="Violin">
<measure>
<directions>
<clef sign="G" line="2"/>
<instruction text-font-size="2.5st">Allegro</instruction>
</directions>
<sequence>
<event value="/4">
<note pitch="F4" class="emphasis"/>
</event>
...
</sequence>
</measure>
<measure>...</measure>
</part>
<part name="Viola">...</part>
<layouts>
<style-class element="global"
music-font="Bravura"
text-font="Times New Roman"/>
<system-layout id="violin-part">
<style-class element="global"
staff-line-spacing="8px"
system-spacing="5st"
text-font="Georgia"
text-font-size="14px"/>
<style-class element="instruction"
text-font-size="12px"/>
<part-layout part="Violin"/>
</system-layout>
<system-layout id="full-score">
<style-class element="global"
staff-line-spacing="5px"
system-spacing="3st"
music-font="Petaluma"
text-font-size="10px"/>
<part-layout part="Violin"/>
<part-layout part="Viola"/>
</system-layout>
</layouts>
<score name="Full score">
<style-class name="emphasis"
color="#0000FF"/>
<page>
<system measure="1" layout="full-score"/>
</page>
</score>
<score name="Violin Part">
<style-class text-font="Arial"/>
<page>
<system measure="1" layout="violin-part"/>
</page>
</score> Notes:
Example:
|
@joeberkovitz Thank you for the examples! They are always very useful. If my understanding is correct, I think there are a couple of issues in the examples: Example: text-font of the element, full score layouts/system-layout/style-class: "Georgia" Value: Example: color of the element, |
@joeberkovitz A question: how do you infer that
Thus |
@cecilios First, thanks for catching the mistakes, I directly fixed them by editing the example. |
@joeberkovitz Thanks! I forgot about the section Defaulting values |
As we've moved ahead on other fronts some changes are needed, I'm revising the basic styles proposal here to keep in step. Note: I'm going to keep this issue focused solely on the generic style mechanism and begin to break out other side issues to deal with specific groups of properties for page layout, dimensions, display, text and so forth. There's already a side issue for style property units (#247). |
Here is the updated spec on the generic calculation of style properties. This has been changed to allow the direct specification of styles on layout and score elements which keeps things simple-looking and allows us to use styling to control many aspects of layouts and scores with one scheme, including dimensions, margins etc. Target elements and style properties"Target elements" are any content to which style properties may be applied. They are not restricted to any particular section of an MNX document: semantic elements, layout elements and score elements may all possess style properties. "Style properties" are meant to control a target's rendering and/or performance. Simple examples are color, volume, font, size. Style properties are optional, and have default values supplied by the specification and perhaps by the rendering application. Style properties are declared in the document only when they override these defaults. As a corollary, the style mechanism can be completely ignored by documents that are not interested in modifying the defaults. Style sourcesMost elements in an MNX document can serve as a style source. This means that they include one or more declarations that apply style properties to a set of target elements. The following kinds of style sources exist:
(Note: unlike CSS, class definitions cannot match on both element name and class name. That's a possible future enhancement.) Computing valuesThe first step in determining the value of a style property for some target element is to find all of its style sources, and collect the declared values in a list. The list is sorted into the following categories in the given priority order:
Each of these categories is then sorted internally so that later declarations in the document take priority over earlier ones. For scores and layouts, this has the effect that more specific elements override their ancestors. It also means that when multiple class names or specific values are provided in a target element, later ones override earlier ones. The first value in the final sorted list is adopted as the computed value of the style property. If the list is empty, then there is no computed value. Defaulting valuesIf no computed value is found for the target element in the previous step, and the property is inherited (other than dimensions and margins/padding, most are), the ancestors of the target element are searched by ascending the property inheritance chain looking for an element that does have a computed value. This chain is defined as follows:
For each ancestor consulted during this search, its computed value is examined. If one is found, the search terminates and that value is used as the target element's default value. If no computed value is found on an ancestor and the search completes at Worked ExamplesHere is a fully worked example of the algorithm with a toy document: <mnx>
<global>
<measure index="1" preferred-width="10st"/>
<measure/>
</global>
<part name="Violin">
<measure>
<directions>
<clef sign="G" line="2"/>
<instruction text-font-size="2.5st">Allegro</instruction>
</directions>
<sequence>
<event value="/4">
<note pitch="F4" class="emphasis"/>
</event>
...
</sequence>
</measure>
<measure>...</measure>
</part>
<part name="Viola">...</part>
<layouts music-font="Bravura" text-font="Times New Roman"/>
<system-layout id="violin-part"
staff-line-spacing="8px" system-spacing="5st"
text-font="Georgia" text-font-size="14px">
<style-class element="instruction" text-font-size="12px"/>
<part-layout part="Violin"/>
</system-layout>
<system-layout id="full-score"
staff-line-spacing="5px" system-spacing="3st"
text-font-size="10px">
<part-layout part="Violin"/>
<part-layout part="Viola"/>
</system-layout>
</layouts>
<score name="Full score" page-size="A4" page-margin="25px 25px 25px 25px">
<style-class name="emphasis"
color="#0000FF"/>
<page>
<system measure="1" layout="full-score"/>
</page>
</score>
<score name="Violin Part">
<page page-size="A4" page-margin="25px 25px 25px 25px">
<system measure="1" layout="violin-part"/>
</page>
</score> Notes:
Example:
|
Assuming we can table direct changes to strings, as in #263 (comment) (see #278 and #280 for this), I think this is a good proposal. I would like to reword this to see if I understand it. In this explanation, the word "set" is used in the typographic sense of determining the exact placement, font, size, color, and other visual attributes of a visible element. Possibly incorrect reworded explanation/algorithm:All elements in the layouts hierarchy and the score hierarchy gain the When trying to set each visible element in a score:
Note: For any given element being set on a particular score, these two hierarchies are well-defined.
If all of that is correct, the I have the following notes:
If I understand correctly, since the only |
Thanks for putting this together, @joeberkovitz. It makes intuitive sense (especially for folks coming from an HTML/CSS background) and is powerful yet elegant. I think we should run with it! Just a few reactions regarding details:
How is everybody feeling about this proposal? In absence of any pushback, I can make a pull request with the appropriate changes to the spec, along with an example or two. |
I've added pull request #282 to encode these ideas into the spec. Feedback welcome! |
Quick update: there's been a non-trivial proposed tweak to this. See my comment here and please leave feedback there on the pull request! |
Preamble
The idea of MNX style properties and classes was first presented in the original draft spec. That proposal was rejected some time ago, and is not part of 1.0. It relied on CSS syntax, it was overcomplicated, and it didn't anticipate
<system-layout>
or<score>
.However, there's still a need for style properties as evidenced by the fact that styles and classes have been proposed multiple times in the CG to solve problems with text, dynamics, graphics, repeats. Each proposal has been a little different. It makes sense to revisit styles and address them in a way that's more uniform. That way we can have a single useful tool that can be rolled out repeatedly when we need it. This proposal tries to put forth a new vision of styles and how they fit into MNX 1.0.
This proposal is big enough to need a fair amount of up-front rationales and definitions before getting into the meat of it all, so thanks for your patience in reading. I can't see how to do this more briefly. At least, this proposal is a lot simpler than CSS both conceptually and syntactically.
What do style properties control?
Here are some possible examples that illustrate the variety of possible styles:
Let's not debate the full set of style properties here. Those can be broken out as separate issues once the mechanism is clarified.
Design Goals
Architecture
For the latest architecture please jump ahead to this post: #263 (comment)
Click on the text below to expand the originally-posted architecture which has been superseded:
Original architecture proposal
Style computation
"Target elements" are things you can see and/or hear. For example,
<note>
is a kind of target element. A target's appearance and/or sound has default characteristics, but that can be altered by one or more style properties e.g. color, volume, and so on.Any element can serve as a "style source". This means that it defines a particular set of style properties, which in turn affect a set of one or more target elements.
Obviously, a target element can always be a style source for itself. A note might specify that its own color is blue, for example.
However, other elements can also be style sources for the same target element. For example, our note's parent
<event>
might specify that all its child notes are blue. Or a system layout that's in effect, might specify that all note heads in some part are shown smaller than normal. Or the document as a whole might specify a uniform music font to be used everywhere. In these examples, one style source controls many target elements.Style sources can include elements living in
<global>
,<part>
,<system-layout>
and<score>
. To control how these many sources work on each target element, we need a well-defined algorithm. Therefore, the set of style properties for any single target element are derived from a number of style sources, consulted in the following order, highest priority first:<score>
, followed by its ancestors<system-layout>
, followed by its ancestors<global>
)<global>
, any<measure>
to which the target element belongs<global>
elementMuch of the utility of styles lies in this priority order. It establishes a useful scheme, in which specific values take precedence over basic defaults.
Sources, properties, and classes
A style source can supply a target element's properties directly. To do this, it defines some name/value pairs of style properties, attached directly to the style source in XML. The style source in effect is saying, "here are the style properties for target elements that I apply to". When the style source is consulted as part of style computation, these properties are simply applied to the target (if they weren't already defined with a higher priority).
However, target elements can also name "style classes" to which they belongs. A style class lets the target element say, "I am a certain kind of thing", without declaring any style properties. In turn, other elements like layouts or scores can say, "Here are the style properties for that kind of thing", by supplying a definition of that same style class.
This lets semantic elements be very specific about their differences from other elements, while leaving the details up to
<score>
or<system-layout>
elements. For example a<note>
might say it belongs to a class namedsmall
. A<staff-layout>
being used for some score might specify that within it, asmall
note is 0.75 the size of a regular note; another layout might instead specify 0.85 because it just looks better in that layout.Specifying attributes in a style source
A basic choice confronting us is how to specify a set of property values in MNX for some style source. Here are several approaches that could be taken; they all work at a mechanical level. For simplicity we stick to one example: changing the color of all elements in a sequence to make them blue, and also making all notes in the sequence smaller than normal. Thus, we are supplying style properties for a sequence (which itself is invisible), to be inherited by its descendants (which are things we can see like notes and directions).
Note that more than one of these could be allowed... not that that is necessarily a good thing.
1. Direct attributes
In this approach all style properties are represented as XML attribute-value pairs on an element being styled:
Notes:
color
on<note>
.note-size
is inherited by all<note>
elements below<sequence>
). So it may have the effect of requiring a huge style-attribute group that applies to almost every element in the schema.2. Style element attributes
Notes:
3. Style element children
Notes:
For compactness, only choice 1 (Direct attributes) will be used in remaining examples.
Declaring style classes
Target elements may list the classes they belong to using the
class
attribute, which takes a whitespace-delimited list of class identifiers:Target elements can declare more than one class. Style properties declared by a target element are applied in the order in which they were named, allowing subsequent class names to override earlier ones.
Defining style classes
Style sources may include one or more
<style-class>
children, each of which defines a set of properties for some class name; here a system layout defines what the classesemphasis
andsmall
mean for that particular layout:Class definitions are always optional; if a style source doesn't supply one, then the class's properties are unaffected by that source.
Defining element classes
Target elements are considered to automatically belong to a special "element class" determined by the target element's name alone. This permits style sources to control the appearance of different elements by name.
Element-name-based classes can be defined in a style source as follows. In this example, a
<score>
element defines some default fonts for instruction text and expression text:A target's element class is always processed first, before iterating through the explicitly named classes. This means that element classes are defaults, and they are overridden by named classes.
Relationship to existing and future MNX concepts
color
andstem-direction
. These would need to be retrofitted as style properties. Depending on the choice of syntax (asee above), this might not have any effect, or it might add new ways of specifying these values, or we might retire these as first-class XML attributes.<global>
seems like a natural place to define default style properties for an entire document.<staff-layout>
and other layout elements proposed in How to group parts? #185 might simply be regular old style properties. There is no reason we need to limit what style properties a layout might or might not wish to control. Any style property that's fair game can be controlled by a layout.<layout>
(say,<performance>
) which use style properties to define specific mixes or subsets of parts to be used for audio rendering.The text was updated successfully, but these errors were encountered: