Esempio n. 1
0
 def actionTriggered(self, name):
     name = name[8:]
     direction = ['_', '', '^'][self.direction() + 1]
     isSpanner = name not in dynamic_marks
     if isSpanner:
         dynamic = dynamic_spanners[name]
     else:
         dynamic = '\\' + name
     cursor = self.mainwindow().textCursor()
     if not cursor.hasSelection():
         # dynamic right before the cursor?
         left = tokeniter.partition(cursor).left
         if not left or not isinstance(left[-1], ly.lex.lilypond.Dynamic):
             # no, find the first pitch
             c = lydocument.cursor(cursor)
             c.end = None
             source = lydocument.Source(c, True, ly.document.OUTSIDE, True)
             for p in ly.rhythm.music_tokens(source):
                 cursor = source.cursor(p[-1], start=len(p[-1]))
                 break
         cursor.insertText(direction + dynamic)
         self.mainwindow().currentView().setTextCursor(cursor)
     else:
         c = lydocument.cursor(cursor)
         source = lydocument.Source(c, True, tokens_with_position=True)
         cursors = [
             source.cursor(p[-1], start=len(p[-1]))
             for p in ly.rhythm.music_tokens(source)
         ]
         if not cursors:
             return
         c1, c2 = cursors[0], cursors[-1]
         # are there dynamics at the cursor? then skip them
         d1 = dynamics(c1)
         if d1:
             c1 = tokeniter.cursor(c1.block(), d1[-1], start=len(d1[-1]))
         with cursortools.compress_undo(cursor):
             if len(cursors) > 1:
                 # dynamics after the end cursor?
                 d2 = dynamics(c2)
                 if isSpanner and not d2:
                     # don't terminate the spanner if there's a dynamic there
                     c2.insertText('\\!')
                 elif set(d1).intersection(dynamic_spanners.values()):
                     # write the dynamic at the end if there's a spanner at start
                     # remove ending \! if there
                     terminator = tokeniter.find("\\!", d2)
                     if terminator:
                         c2 = tokeniter.cursor(c2.block(), terminator)
                     if direction in d1:
                         c2.insertText(dynamic)
                     else:
                         c2.insertText(direction + dynamic)
                     return
             c1.insertText(direction + dynamic)
Esempio n. 2
0
def articulation_positions(cursor):
    """Returns a list of positions where an articulation can be added.
    
    Every position is given as a QTextCursor instance.
    If the cursor has a selection, all positions in the selection are returned.
    
    """
    c = lydocument.cursor(cursor)
    if not cursor.hasSelection():
        # just select until the end of the current line
        c.select_end_of_block()
        rests = True
        partial = ly.document.OUTSIDE
    else:
        rests = False
        partial = ly.document.INSIDE
    source = lydocument.Source(c, True, partial, True)

    positions = []
    for p in ly.rhythm.music_tokens(source):
        if not rests and isinstance(p[0], ly.lex.lilypond.Rest):
            continue
        positions.append(source.cursor(p[-1], start=len(p[-1])))
        if not cursor.hasSelection():
            break  # leave if first found, that's enough
    return positions
Esempio n. 3
0
 def actionTriggered(self, name):
     # convert arpeggio_normal to arpeggioNormal, etc.
     name = _arpeggioTypes[name]
     cursor = self.mainwindow().textCursor()
     # which arpeggio type is last used?
     lastused = '\\arpeggioNormal'
     types = set(_arpeggioTypes.values())
     block = cursor.block()
     while block.isValid():
         s = types.intersection(tokeniter.tokens(block))
         if s:
             lastused = s.pop()
             break
         block = block.previous()
     # where to insert
     c = lydocument.cursor(cursor)
     c.select_end_of_block()
     source = lydocument.Source(c, True, ly.document.OUTSIDE, True)
     with cursortools.compress_undo(cursor):
         for p in ly.rhythm.music_tokens(source):
             c = source.cursor(p[-1], start=len(p[-1]))
             c.insertText('\\arpeggio')
             if name != lastused:
                 cursortools.strip_indent(c)
                 indent = c.block().text()[:c.position()-c.block().position()]
                 c.insertText(name + '\n' + indent)
             # just pick the first place
             return
Esempio n. 4
0
def positions(cursor):
    """Return a list of QTextCursors describing the grob the cursor points at.
    
    When the cursor point at e.g. a slur, the returned cursors describe both
    ends of the slur.
    
    The returned list may contain zero to two cursors.
    
    """
    c = lydocument.cursor(cursor)
    c.end = None
    source = lydocument.Source(c, True)
    for token in source.tokens:
        break
    else:
        return []
    
    cur = source.cursor(token, end=0)
    cursors = [cur]
    
    # some heuristic to find the relevant range(s) the linked grob represents
    if isinstance(token, ly.lex.lilypond.Direction):
        # a _, - or ^ is found; find the next token
        for token in source:
            if not isinstance(token, (ly.lex.Space, ly.lex.Comment)):
                break
    end = token.end + source.block.position()
    if token == '\\markup':
        # find the end of the markup expression
        depth = source.state.depth()
        for token in source:
            if source.state.depth() < depth:
                end = token.end + source.block.position()
                break
    elif token == '"':
        # find the end of the string
        for token in source:
            if isinstance(token, ly.lex.StringEnd):
                end = token.end + source.block.position()
                break
    elif isinstance(token, ly.lex.MatchStart):
        # find the end of slur, beam. ligature, phrasing slur, etc.
        name = token.matchname
        nest = 1
        for token in source:
            if isinstance(token, ly.lex.MatchEnd) and token.matchname == name:
                nest -= 1
                if nest == 0:
                    cursors.append(source.cursor(token))
                    break
            elif isinstance(token, ly.lex.MatchStart) and token.matchname == name:
                nest += 1
                
    cur.setPosition(end, QTextCursor.KeepAnchor)
    return cursors
Esempio n. 5
0
    def actionTriggered(self, name):
        d = ['_', '', '^'][self.direction()+1]
        single = ''
        if name == "grace_grace":
            inner = ''
            outer = '\\grace { ', ' }'
            single = '\\grace '
        elif name == "grace_beam":
            inner = d + '[', ']'
            outer = '\\grace { ', ' }'
        elif name == "grace_accia":
            inner = ''
            outer = '\\acciaccatura { ', ' }'
            single = '\\acciaccatura '
        elif name == "grace_appog":
            inner = ''
            outer = '\\appoggiatura { ', ' }'
            single = '\\appoggiatura '
        elif name == "grace_slash":
            inner = d + '[', ']'
            outer = '\\slashedGrace { ', ' }'
        elif name == "grace_after":
            inner = d + '{ '
            outer = '\\afterGrace ', ' }'               

        cursor = self.mainwindow().textCursor()
        with cursortools.compress_undo(cursor):
            if inner:     
                for i, ci in zip(inner, spanner_positions(cursor)):
                    ci.insertText(i)
            if cursor.hasSelection():
                ins = self.mainwindow().textCursor()      
                ins.setPosition(cursor.selectionStart())
                ins.insertText(outer[0])
                ins.setPosition(cursor.selectionEnd())
                ins.insertText(outer[1])
            else:
                if single:
                    cursor.insertText(single)
                else:
                    c = lydocument.cursor(cursor)
                    c.end = None
                    source = lydocument.Source(c, True, ly.document.OUTSIDE, True)
                    music_list = list(ly.rhythm.music_tokens(source))
                    try:
                        m = music_list[2][0]
                        after = source.cursor(m, 1)
                    except IndexError:                      
                        after = self.mainwindow().textCursor()
                        after.movePosition(cursor.EndOfLine)        
                    after.insertText(outer[1])
                    cursor.insertText(outer[0])
Esempio n. 6
0
 def actionTriggered(self, name):
     cursor = self.mainwindow().textCursor()
     style = _glissandoStyles[name]
     c = lydocument.cursor(cursor)
     c.select_end_of_block()
     source = lydocument.Source(c, True, ly.document.OUTSIDE, True)
     for p in ly.rhythm.music_tokens(source):
         c = source.cursor(p[-1], start=len(p[-1]))
         if style:
             text = "-\\tweak #'style #'{0} \\glissando".format(style)
         else:
             text = '\\glissando'
         c.insertText(text)
         return
Esempio n. 7
0
 def hyphenate(self):
     """Hyphenates selected Lyrics text."""
     view = self.mainwindow().currentView()
     cursor = view.textCursor()
     found = []
     c = lydocument.cursor(cursor, select_all=True)
     # find text to hyphenate
     source = lydocument.Source(c)
     for token in source:
         if isinstance(token, ly.lex.lilypond.LyricText):
             # a word found
             pos = source.position(token)
             for m in _word_re.finditer(token):
                 found.append((pos + m.start(), pos + m.end(), m.group()))
     if not found and cursor.hasSelection():
         # no tokens were found, then tokenize the text again as if in lyricmode
         start = cursor.selectionStart()
         state = ly.lex.State(ly.lex.lilypond.ParseLyricMode)
         for token in state.tokens(cursor.selection().toPlainText()):
             if isinstance(token, ly.lex.lilypond.LyricText):
                 # a word found
                 pos = start + token.pos
                 for m in _word_re.finditer(token):
                     found.append(
                         (pos + m.start(), pos + m.end(), m.group()))
     if not found and cursor.hasSelection():
         # still not succeeded, then try flat text
         for m in _word_re.finditer(cursor.selection().toPlainText()):
             found.append((start + m.start(), start + m.end(), m.group()))
     if found:
         import hyphendialog
         h = hyphendialog.HyphenDialog(self.mainwindow()).hyphenator()
         if h:
             with c.document as d:
                 for start, end, word in found:
                     hyph_word = h.inserted(word, ' -- ')
                     if word != hyph_word:
                         d[start:end] = hyph_word
Esempio n. 8
0
def spanner_positions(cursor):
    """Return a list with 0 to 2 QTextCursor instances.
    
    At the first cursor a starting spanner item can be inserted, at the
    second an ending item.
    
    """   
    c = lydocument.cursor(cursor)
    if cursor.hasSelection():
        partial = ly.document.INSIDE
    else:
        # just select until the end of the current line
        c.select_end_of_block()
        partial = ly.document.OUTSIDE
    source = lydocument.Source(c, True, partial, True)
      
    positions = [source.cursor(p[-1], start=len(p[-1]))
        for p in ly.rhythm.music_tokens(source)]
    
    if cursor.hasSelection():
        del positions[1:-1]
    else:
        del positions[2:]
    return positions