Source code for neoscore.western.pedal_line

from __future__ import annotations

from typing import Optional

from neoscore.core.brush import Brush
from neoscore.core.music_font import MusicFont
from neoscore.core.music_path import MusicPath
from neoscore.core.pen import Pen
from neoscore.core.point import PointDef
from neoscore.core.positioned_object import PositionedObject
from neoscore.core.spanner import Spanner
from neoscore.core.units import Unit


[docs]class PedalLine(Spanner, MusicPath): """A line-style pedal marking with optional half-lift (^) marks. The mark begins with an upward crook, continues as a horizontal line interrupted with optional half-lift upward triangular marks, and terminates with another upward crook. The object's position is that of the top of the opening crook; this y-axis position is also the height two which the half-lift marks extend. The main line of the path is drawn 1 staff unit below this position. A list of half-lift x-axis positions may be provided as either simple x-axis Unit values (relative to the line's start position) or as 2-tuples of x-axis positions and position parents: >>> PedalLine(start=(Mm(10), staff.unit(8)), start_parent=staff, ... end_x=Mm(200), end_parent=None, ... half_lift_positions=[ ... Mm(20), # Relative to start_parent ... Mm(40), # Relative to start_parent ... (Mm(1), some_chord)] # 1 mm right of some_chord ... ) # doctest: +SKIP While this is a path, it requires a music font from which to derive its appearance. """
[docs] def __init__( self, start: PointDef, start_parent: PositionedObject, end_x: Unit, end_parent: Optional[PositionedObject] = None, half_lift_positions: List[Unit | Tuple[Unit, PositionedObject]] = None, font: Optional[MusicFont] = None, ): """ Args: start: The starting position of the pedal line. start_parent: The parent for the starting position. If no font is given, this or one of its ancestors must implement ``HasMusicFont``. end_x: x position of the end point relative to end_parent end_parent: parent for end_x half_lift_positions: A list of x-axis positions along the line where half lift notches should be drawn. font: If provided, this overrides any font found in the ancestor chain. """ MusicPath.__init__(self, start, start_parent, font, Brush.no_brush(), Pen()) self.pen.thickness = self.music_font.engraving_defaults["pedalLineThickness"] Spanner.__init__(self, end_x, end_parent or self) self.half_lift_positions = half_lift_positions self._draw_path()
def _draw_path(self): """Draw the path according to this object's attributes. Returns: None """ # Set up constants # The vertical extent of the shape descent = self.music_font.unit(1) # The horizontal distance extended to from half lift positions half_lift_x_extent = self.music_font.unit(0.5) # Draw opening crook self.line_to(self.music_font.unit(0), descent) # Draw half lift positions, if any exist if self.half_lift_positions: for pos in self.half_lift_positions: if pos >= self.end_x - (half_lift_x_extent * 2): raise AttributeError("Invalid half lift position: {}".format(pos)) if isinstance(pos, tuple): lift_parent = pos[1] lift_center_x = pos[0] lift_center_y = lift_parent.map_to(self).y + descent elif isinstance(pos, Unit): lift_parent = self lift_center_x = pos lift_center_y = descent else: raise AttributeError("Invalid half lift position: {}".format(pos)) lift_left_x = lift_center_x - half_lift_x_extent lift_right_x = lift_center_x + half_lift_x_extent self.line_to(lift_left_x, lift_center_y, lift_parent) self.line_to(lift_center_x, lift_center_y - descent, lift_parent) self.line_to(lift_right_x, lift_center_y, lift_parent) # Draw closing crook self.line_to(self.end_x, self.end_y + descent, self.end_parent) self.line_to(self.end_x, self.end_y, self.end_parent)