Source code for neoscore.core.has_music_font

from __future__ import annotations

from typing import TYPE_CHECKING, Type, cast

from neoscore.core.exceptions import NoAncestorWithMusicFontError
from neoscore.core.positioned_object import PositionedObject
from neoscore.core.units import Unit

if TYPE_CHECKING:
    from neoscore.core.music_font import MusicFont


[docs]class HasMusicFont: """A mixin for classes which have an associated staff measurement. This is useful for integration with SMuFL fonts, where glyphs and their metadata are measured relative to a staff space. A naive and slow implementation of the :obj:`music_font <.HasMusicFont.music_font>` property is provided which returns the nearest music found in the object's ancestors. Subclasses will often want to override this. """ @property def music_font(self) -> MusicFont: """The music font used by this object.""" return HasMusicFont.find_music_font(cast(PositionedObject, self).parent) @property def unit(self) -> Type[Unit]: """A unit type where ``unit(1)`` is the size of a staff space in the font.""" return self.music_font.unit
[docs] @staticmethod def find_music_font(obj: PositionedObject) -> MusicFont: """Return the music font from ``obj`` or its nearest ancestor with one. This checks ``obj`` and then its ancestors for whether they have a ``music_font`` attribute, returning the first value found. If no font is found, this raises a :obj:`.NoAncestorWithMusicFontError`. """ if hasattr(obj, "music_font"): return cast(HasMusicFont, obj).music_font lookup_result = obj.first_ancestor_with_attr("music_font") if lookup_result is None: raise NoAncestorWithMusicFontError() return cast(HasMusicFont, lookup_result).music_font