Exemple #1
0
 def __init__(
     self,
     start: PointDef,
     start_parent: GraphicObject,
     stop: PointDef,
     stop_parent: GraphicObject,
 ):
     """
     Args:
         start: The starting (left) position of the beam
         start_parent: The parent for the starting position.
             Must be a staff or in one.
         stop: The ending (right) position of the beam
         stop_parent: The parent for the ending position.
             Must be a staff or in one.
     """
     Path.__init__(self, start, parent=start_parent)
     StaffObject.__init__(self, start_parent)
     self.beam_thickness = self.staff.music_font.engraving_defaults[
         "beamThickness"]
     # Draw beam
     stop = Point.from_def(stop)
     self.line_to(stop.x, stop.y, stop_parent)
     self.line_to(stop.x, stop.y + self.beam_thickness, stop_parent)
     self.line_to(ZERO, self.beam_thickness, self)
     self.close_subpath()
Exemple #2
0
 def __init__(
     self,
     start: PointDef,
     start_parent: GraphicObject,
     stop: PointDef,
     stop_parent: Optional[GraphicObject],
     direction: int = -1,
 ):
     """
     Args:
         start: The starting point.
         start_parent: The parent for the starting position.
             Must be a staff or in one.
         stop: The stopping point.
         stop_parent: The parent for the ending position.
             If `None`, defaults to `self`.
         direction: The direction of the slur, where
             `-1` indicates curving upward, and `1` vice versa.
     """
     Path.__init__(self,
                   start,
                   parent=start_parent,
                   brush=Brush((0, 0, 0, 255)))
     StaffObject.__init__(self, self.parent)
     stop = Point.from_def(stop)
     Spanner2D.__init__(self, stop, stop_parent or self)
     self.direction = direction
     # Load relevant engraving defaults from music font
     engraving_defaults = self.staff.music_font.engraving_defaults
     self.midpoint_thickness = self.staff.unit(
         engraving_defaults["slurMidpointThickness"])
     self.endpoint_thickness = self.staff.unit(
         engraving_defaults["slurEndpointThickness"])
     self._draw_path()
Exemple #3
0
 def __init__(
     self,
     start: PointDef,
     start_parent: GraphicObject,
     stop: PointDef,
     stop_parent: Optional[GraphicObject],
     direction: int,
     width: Optional[Unit] = None,
 ):
     """
     Args:
         start: The starting point.
         start_parent: The parent for the starting position.
             Must be a staff or in one.
         stop: The stopping point.
         stop_parent: The parent for the ending position.
             If `None`, defaults to `self`.
         direction: The direction of the hairpin, where `-1` means diminuendo (>)
             and `1` means crescendo (<).
         width: The width of the wide hairpin. Defaults to 1 staff unit.
     """
     Path.__init__(self, start, parent=start_parent)
     StaffObject.__init__(self, start_parent)
     stop = Point.from_def(stop)
     Spanner2D.__init__(self, stop, stop_parent or self)
     self.direction = direction
     self.width = width if width is not None else self.staff.unit(1)
     self.thickness = self.staff.music_font.engraving_defaults[
         "hairpinThickness"]
     self._draw_path()
Exemple #4
0
 def test_move_to_with_parent(self):
     path = Path(ORIGIN)
     parent = InvisibleObject((Unit(100), Unit(50)))
     path.move_to(Unit(10), Unit(11), parent)
     assert len(path.elements) == 1
     assert_path_els_equal(
         path.elements[0], MoveTo(Point(Unit(10), Unit(11)), parent)
     )
Exemple #5
0
 def test_line_to_with_parent(self):
     path = Path((Unit(5), Unit(6)))
     parent = InvisibleObject((Unit(100), Unit(50)))
     path.line_to(Unit(1), Unit(3), parent)
     assert path.elements[-1].parent == parent
     resolved_els = path._resolve_path_elements()
     assert resolved_els == [
         ResolvedMoveTo(ZERO, ZERO),
         ResolvedLineTo(Unit(100 + 1 - 5), Unit(50 + 3 - 6)),
     ]
Exemple #6
0
 def test_line_to(self):
     path = Path((Unit(5), Unit(6)))
     path.line_to(Unit(10), Unit(12))
     assert len(path.elements) == 2
     assert_path_els_equal(path.elements[0], MoveTo(ORIGIN, path))
     assert_path_els_equal(path.elements[1], LineTo(Point(Unit(10), Unit(12)), path))
     resolved_els = path._resolve_path_elements()
     assert resolved_els == [
         ResolvedMoveTo(ZERO, ZERO),
         ResolvedLineTo(Unit(10), Unit(12)),
     ]
Exemple #7
0
 def test_close_subpath(self):
     path = Path((Unit(5), Unit(6)))
     path.line_to(Unit(10), Unit(10))
     path.line_to(Unit(10), Unit(100))
     path.close_subpath()
     assert len(path.elements) == 4
     assert_path_els_equal(path.elements[3], MoveTo(ORIGIN, path))
Exemple #8
0
    def __init__(self, start: PointDef, height: Unit, parent: GraphicObject):
        """
        Args:
            start: Starting point for the stem
            height: The height of the stem,
                where positive extend downward.
            parent:
        """
        Path.__init__(self, start, parent=parent)
        StaffObject.__init__(self, parent=parent)
        thickness = self.staff.music_font.engraving_defaults["stemThickness"]
        self.pen = Pen(thickness=thickness)

        self._height = height
        # Draw stem path
        self.line_to(self.staff.unit(0), self.height)
Exemple #9
0
 def test_init(self):
     mock_parent = InvisibleObject(ORIGIN, parent=None)
     test_pen = Pen("#eeeeee")
     test_brush = Brush("#dddddd")
     path = Path((Unit(5), Unit(6)), test_pen, test_brush, mock_parent)
     assert path.pos == Point(Unit(5), Unit(6))
     assert path.pen == test_pen
     assert path.brush == test_brush
Exemple #10
0
 def __init__(self, pos_x: Unit, staves: Iterable[Staff]):
     """
     Args:
         pos_x: The barline position relative to
             the top staff.
         staves:
     """
     MultiStaffObject.__init__(self, set(staves))
     Path.__init__(self, Point(pos_x, ZERO), parent=self.highest_staff)
     engraving_defaults = self.highest_staff.music_font.engraving_defaults
     thickness = engraving_defaults["thinBarlineThickness"]
     self.pen = Pen(thickness=thickness)
     # Draw path
     offset = map_between(self.lowest_staff, self.highest_staff)
     bottom_x = pos_x + offset.x
     self.line_to(bottom_x,
                  self.lowest_staff.height,
                  parent=self.lowest_staff)
Exemple #11
0
 def test_cubic_to_with_no_parents(self):
     path = Path((Unit(5), Unit(6)))
     path.cubic_to(Unit(10), Unit(11), ZERO, Unit(1), Unit(5), Unit(6))
     assert len(path.elements) == 2
     assert_path_els_equal(path.elements[0], MoveTo(ORIGIN, path))
     assert_path_els_equal(
         path.elements[1],
         CurveTo(
             ControlPoint(Point(Unit(10), Unit(11)), path),
             ControlPoint(Point(ZERO, Unit(1)), path),
             Point(Unit(5), Unit(6)),
             path,
         ),
     )
     resolved_els = path._resolve_path_elements()
     assert resolved_els == [
         ResolvedMoveTo(ZERO, ZERO),
         ResolvedCurveTo(Unit(10), Unit(11), ZERO, Unit(1), Unit(5), Unit(6)),
     ]
Exemple #12
0
 def __init__(self, pos: PointDef, parent: GraphicObject,
              base_length: Unit):
     """
     Args:
         pos: The position of the left edge of the notehead column.
         parent: The parent, which must be a staff or in one.
         base_length: The of the notehead this line is related to.
             The real length will be this plus a small extension defined in the
             `MusicFont`s engraving defaults.
     """
     Path.__init__(self, pos, parent=parent)
     StaffObject.__init__(self, parent=parent)
     thickness = self.staff.music_font.engraving_defaults[
         "legerLineThickness"]
     self.pen = Pen(thickness=thickness)
     extension = self.staff.music_font.engraving_defaults[
         "legerLineExtension"]
     length = base_length + extension
     self.move_to(extension * -1, self.staff.unit(0))
     self.line_to(length, self.staff.unit(0))
Exemple #13
0
 def test_cubic_to_with_parents(self):
     path = Path((Unit(Unit(100)), Unit(Unit(200))))
     parent_1 = InvisibleObject((Unit(Unit(10)), Unit(Unit(20))))
     parent_2 = InvisibleObject((Unit(Unit(30)), Unit(Unit(40))))
     parent_3 = InvisibleObject((Unit(Unit(50)), Unit(Unit(60))))
     path.cubic_to(
         Unit(1),
         Unit(2),
         Unit(3),
         Unit(4),
         Unit(5),
         Unit(6),
         parent_1,
         parent_2,
         parent_3,
     )
     assert len(path.elements) == 2
     assert_path_els_equal(path.elements[0], MoveTo(ORIGIN, path))
     assert_path_els_equal(
         path.elements[1],
         CurveTo(
             ControlPoint(Point(Unit(1), Unit(2)), parent_1),
             ControlPoint(Point(Unit(3), Unit(4)), parent_2),
             Point(Unit(5), Unit(6)),
             parent_3,
         ),
     )
     resolved_els = path._resolve_path_elements()
     assert resolved_els == [
         ResolvedMoveTo(ZERO, ZERO),
         ResolvedCurveTo(
             Unit(10 + 1 - 100),
             Unit(20 + 2 - 200),
             Unit(30 + 3 - 100),
             Unit(40 + 4 - 200),
             Unit(50 + 5 - 100),
             Unit(60 + 6 - 200),
         ),
     ]
Exemple #14
0
 def __init__(
     self,
     start: PointDef,
     start_parent: GraphicObject,
     end_x: Unit,
     end_parent: Optional[GraphicObject] = None,
     half_lift_positions: Unit = None,
 ):
     """
     Args:
         start (Point or init tuple): The starting position of the
             pedal line.
         start_parent (GraphicObject): An object either in a Staff
             or an actual Staff.
         end_x (Unit): The
     """
     StaffObject.__init__(self, start_parent)
     pen = Pen(thickness=self.staff.music_font.
               engraving_defaults["pedalLineThickness"])
     Path.__init__(self, start, pen, parent=start_parent)
     Spanner.__init__(self, end_x, end_parent or self)
     self.half_lift_positions = half_lift_positions
     self._draw_path()
Exemple #15
0
 def draw_bar_lines(self):
     for measure_num in range(self.measure_count + 1):
         current_path = Path(
             (Measure(measure_num), GridUnit(0)),
             pen=Score._bar_line_pen,
             parent=self,
         )
         drawing = False
         for divider_num in range(len(self.instruments) + 1):
             if self._bar_line_extends_below(measure_num, divider_num):
                 if not drawing:
                     current_path.move_to(
                         GridUnit(0), Score._instrument_pos_y(divider_num))
                     drawing = True
             else:
                 if drawing:
                     current_path.line_to(
                         GridUnit(0), Score._instrument_pos_y(divider_num))
                     drawing = False
Exemple #16
0
 def draw_instrument_dividers(self):
     for divider in range(len(self.instruments) + 1):
         current_path = Path(
             (Measure(0), Score._divider_pos_y(divider)),
             pen=Score._instrument_divider_pen,
             parent=self,
         )
         instrument_above = self.instruments[divider -
                                             1] if divider > 0 else None
         instrument_below = (self.instruments[divider]
                             if divider < len(self.instruments) else None)
         drawing = False
         for measure_num in range(self.measure_count + 1):
             if Score._divider_visible(instrument_above, instrument_below,
                                       measure_num):
                 if not drawing:
                     current_path.move_to(Measure(measure_num), GridUnit(0))
                     drawing = True
             else:
                 if drawing:
                     current_path.line_to(Measure(measure_num), GridUnit(0))
                     drawing = False
Exemple #17
0
 def test_move_to_with_no_parent(self):
     path = Path((Unit(5), Unit(6)))
     path.move_to(Unit(10), Unit(11))
     assert len(path.elements) == 1
     assert_path_els_equal(path.elements[0], MoveTo(Point(Unit(10), Unit(11)), path))
Exemple #18
0
 def test_straight_line(self):
     path = Path.straight_line((Unit(5), Unit(6)), (Unit(10), Unit(11)))
     assert path.pos == Point(Unit(5), Unit(6))
     assert len(path.elements) == 2
     assert_path_els_equal(path.elements[0], MoveTo(ORIGIN, path))
     assert_path_els_equal(path.elements[1], LineTo(Point(Unit(10), Unit(11)), path))
Exemple #19
0
 def __init__(self, parent, length):
     Path.__init__(
         self, (GridUnit(0), GridUnit(0)), pen=_EventBox.box_pen, parent=parent
     )
     Spanner.__init__(self, length, self)
     self._construct_path()
Exemple #20
0
    def __init__(
        self,
        start: PointDef,
        start_parent: GraphicObject,
        end_x: Unit,
        end_parent: Optional[GraphicObject] = None,
        indication: str = "8va",
    ):
        """
        Args:
            start (Point or tuple init args):
            start_parent (GraphicObject): An object either in a Staff or
                a staff itself. This object will become the line's parent.
            end_x (Unit): The spanner end x position. The y position will be
                automatically calculated to be horizontal.
            end_parent (GraphicObject): An object either in a Staff or
                a staff itself. The root staff of this *must* be the same
                as the root staff of `start_parent`. If omitted, the
                stop point is relative to the start point.
            indication (str): A valid octave indication.
                currently supported indications are:
                    - '15ma' (two octaves higher)
                    - '8va' (one octave higher)
                    - '8vb' (one octave lower)
                    - '15mb' (two octaves lower)
                The default value is '8va'.
        """
        ObjectGroup.__init__(self, start, start_parent)
        Spanner.__init__(self, end_x, end_parent or self)
        StaffObject.__init__(self, self.parent)
        self.transposition = Transposition(OctaveLine.intervals[indication])
        self.line_text = _OctaveLineText(
            # No offset relative to ObjectGroup
            pos=ORIGIN,
            parent=self,
            length=self.length,
            indication=indication,
        )

        # Vertically center the path relative to the text
        text_rect = self.line_text.bounding_rect
        # TODO LOW line needs some padding
        path_x = text_rect.width
        path_y = text_rect.height / -2
        self.line_path = Path(
            pos=Point(path_x, path_y),
            pen=Pen(
                thickness=self.staff.music_font.engraving_defaults[
                    "octaveLineThickness"
                ],
                pattern=PenPattern.DASH,
            ),
            parent=self,
        )
        # Drawn main line part
        self.line_path.line_to(self.end_pos.x, path_y, self.end_parent)
        pos_relative_to_staff = map_between(self.staff, self)
        # Draw end hook pointing toward the staff
        hook_direction = 1 if pos_relative_to_staff.y <= ZERO else -1
        self.line_path.line_to(
            self.end_pos.x,
            (path_y + self.staff.unit(0.75 * hook_direction)),
            self.end_parent,
        )
Exemple #21
0
class OctaveLine(ObjectGroup, Spanner, StaffObject):

    """An octave indication with a dashed line.

    When placed in the context of a Staff, pitched content under the spanner
    is automatically transposed accordingly. Care should be taken to ensure
    OctaveLines do not overlap with one another. If this occurs,
    the transposition reflected in the staff will be an undefined choice
    among those active.

    Supported octave indications are:
        - '15ma' (two octaves higher)
        - '8va' (one octave higher)
        - '8vb' (one octave lower)
        - '15mb' (two octaves lower)

    At the starting position the octave is written in text, followed by
    a dashed line ending in a small vertical hook pointing toward the staff.
    If the spanner goes across line breaks, the octave text is repeated
    in parenthesis at the line beginning.

    TODO LOW: The dashed line portion of this spanner overlaps with
    the '8va' text. This is an involved fix that may require
    implementing text background masking or a way to easily inject
    line continuation offsets for paths.
    """

    intervals = {
        "15ma": Interval("aP15"),
        "8va": Interval("aP8"),
        "8vb": Interval("dP8"),
        "15mb": Interval("dP15"),
    }

    glyphs = {
        "15ma": "quindicesimaAlta",
        "8va": "ottavaAlta",
        "8vb": "ottavaBassaVb",
        "15mb": "quindicesimaBassaMb",
        "(": "octaveParensLeft",
        ")": "octaveParensRight",
    }

    def __init__(
        self,
        start: PointDef,
        start_parent: GraphicObject,
        end_x: Unit,
        end_parent: Optional[GraphicObject] = None,
        indication: str = "8va",
    ):
        """
        Args:
            start (Point or tuple init args):
            start_parent (GraphicObject): An object either in a Staff or
                a staff itself. This object will become the line's parent.
            end_x (Unit): The spanner end x position. The y position will be
                automatically calculated to be horizontal.
            end_parent (GraphicObject): An object either in a Staff or
                a staff itself. The root staff of this *must* be the same
                as the root staff of `start_parent`. If omitted, the
                stop point is relative to the start point.
            indication (str): A valid octave indication.
                currently supported indications are:
                    - '15ma' (two octaves higher)
                    - '8va' (one octave higher)
                    - '8vb' (one octave lower)
                    - '15mb' (two octaves lower)
                The default value is '8va'.
        """
        ObjectGroup.__init__(self, start, start_parent)
        Spanner.__init__(self, end_x, end_parent or self)
        StaffObject.__init__(self, self.parent)
        self.transposition = Transposition(OctaveLine.intervals[indication])
        self.line_text = _OctaveLineText(
            # No offset relative to ObjectGroup
            pos=ORIGIN,
            parent=self,
            length=self.length,
            indication=indication,
        )

        # Vertically center the path relative to the text
        text_rect = self.line_text.bounding_rect
        # TODO LOW line needs some padding
        path_x = text_rect.width
        path_y = text_rect.height / -2
        self.line_path = Path(
            pos=Point(path_x, path_y),
            pen=Pen(
                thickness=self.staff.music_font.engraving_defaults[
                    "octaveLineThickness"
                ],
                pattern=PenPattern.DASH,
            ),
            parent=self,
        )
        # Drawn main line part
        self.line_path.line_to(self.end_pos.x, path_y, self.end_parent)
        pos_relative_to_staff = map_between(self.staff, self)
        # Draw end hook pointing toward the staff
        hook_direction = 1 if pos_relative_to_staff.y <= ZERO else -1
        self.line_path.line_to(
            self.end_pos.x,
            (path_y + self.staff.unit(0.75 * hook_direction)),
            self.end_parent,
        )

    @property
    def length(self) -> Unit:
        return self.spanner_x_length