Source code for neoscore.western.flag

from __future__ import annotations

from typing import Optional, cast

from neoscore.core.directions import DirectionY
from neoscore.core.exceptions import NoFlagNeededError
from neoscore.core.music_font import MusicFont
from neoscore.core.music_text import MusicText
from neoscore.core.point import PointDef
from neoscore.core.positioned_object import PositionedObject
from neoscore.western.duration import Duration, DurationDef
from neoscore.western.duration_display import DurationDisplay


[docs]class Flag(MusicText): """A simple flag glyph determined by a duration and direction""" _up_glyphnames = { 8: "flag1024thUp", 7: "flag512thUp", 6: "flag256thUp", 5: "flag128thUp", 4: "flag64thUp", 3: "flag32ndUp", 2: "flag16thUp", 1: "flag8thUp", } _down_glyphnames = { 8: "flag1024thDown", 7: "flag512thDown", 6: "flag256thDown", 5: "flag128thDown", 4: "flag64thDown", 3: "flag32ndDown", 2: "flag16thDown", 1: "flag8thDown", }
[docs] def __init__( self, pos: PointDef, parent: PositionedObject, duration: Duration, direction: DirectionY, font: Optional[MusicFont] = None, ): """ Args: pos: The position of this flag. When ``parent`` is a stem end point this should typically be :obj:`.ORIGIN`. parent: If no font is given, this or one of its ancestors must implement :obj:`.HasMusicFont`. duration: The duration corresponding to the flag. This controls the flag glyph rendered. direction: The direction of the flag font: If provided, this overrides any font found in the ancestor chain. """ self.duration = duration self.direction = direction duration_display = cast(DurationDisplay, self.duration.display) if duration_display.flag_count == 0: raise NoFlagNeededError(self.duration) if self.direction == DirectionY.DOWN: glyph_name = self._down_glyphnames[duration_display.flag_count] else: glyph_name = self._up_glyphnames[duration_display.flag_count] MusicText.__init__(self, pos, parent, [glyph_name], font)
@property def duration(self) -> Duration: return self._duration @duration.setter def duration(self, value: DurationDef): value = Duration.from_def(value) if value.display is None: raise ValueError(f"{value} cannot be represented as a single note") self._duration = value @property def direction(self) -> DirectionY: return self._direction @direction.setter def direction(self, value: DirectionY): self._direction = value
[docs] @classmethod def vertical_offset_needed(cls, duration: Duration) -> int: """Find the space needed in a stem using a flag of a given duration The value is given in pseudo-staff-units. """ if duration.display is None: return 0 elif duration.display.flag_count: return 1 else: return 0