~ubuntu-branches/ubuntu/vivid/frescobaldi/vivid

« back to all changes in this revision

Viewing changes to frescobaldi_app/quickinsert/articulations.py

  • Committer: Package Import Robot
  • Author(s): Ryan Kavanagh
  • Date: 2012-01-03 16:20:11 UTC
  • mfrom: (1.4.1)
  • Revision ID: package-import@ubuntu.com-20120103162011-tsjkwl4sntwmprea
Tags: 2.0.0-1
* New upstream release 
* Drop the following uneeded patches:
  + 01_checkmodules_no_python-kde4_build-dep.diff
  + 02_no_pyc.diff
  + 04_no_binary_lilypond_upgrades.diff
* Needs new dependency python-poppler-qt4
* Update debian/watch for new download path
* Update copyright file with new holders and years

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# This file is part of the Frescobaldi project, http://www.frescobaldi.org/
 
2
#
 
3
# Copyright (c) 2008 - 2011 by Wilbert Berendsen
 
4
#
 
5
# This program is free software; you can redistribute it and/or
 
6
# modify it under the terms of the GNU General Public License
 
7
# as published by the Free Software Foundation; either version 2
 
8
# of the License, or (at your option) any later version.
 
9
#
 
10
# This program is distributed in the hope that it will be useful,
 
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
# GNU General Public License for more details.
 
14
#
 
15
# You should have received a copy of the GNU General Public License
 
16
# along with this program; if not, write to the Free Software
 
17
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
# See http://www.gnu.org/licenses/ for more information.
 
19
 
 
20
"""
 
21
The Quick Insert panel Articulations Tool.
 
22
"""
 
23
 
 
24
from __future__ import unicode_literals
 
25
 
 
26
import itertools
 
27
 
 
28
from PyQt4.QtGui import QCheckBox
 
29
 
 
30
import app
 
31
import symbols
 
32
import cursortools
 
33
import tokeniter
 
34
import music
 
35
import ly.lex.lilypond
 
36
 
 
37
from . import tool
 
38
from . import buttongroup
 
39
 
 
40
 
 
41
# a dict mapping long articulation names to their short sign
 
42
shorthands = {
 
43
    'marcato': '^',
 
44
    'stopped': '+',
 
45
    'tenuto': '-',
 
46
    'staccatissimo': '|',
 
47
    'accent': '>',
 
48
    'staccato': '.',
 
49
    'portato': '_',
 
50
}
 
51
 
 
52
 
 
53
class Articulations(tool.Tool):
 
54
    """Articulations tool in the quick insert panel toolbox.
 
55
    
 
56
    """
 
57
    def __init__(self, panel):
 
58
        super(Articulations, self).__init__(panel)
 
59
        self.shorthands = QCheckBox(self)
 
60
        self.shorthands.setChecked(True)
 
61
        self.layout().addWidget(self.shorthands)
 
62
        for cls in (
 
63
                ArticulationsGroup,
 
64
                OrnamentsGroup,
 
65
                SignsGroup,
 
66
                OtherGroup,
 
67
            ):
 
68
            self.layout().addWidget(cls(self))
 
69
        self.layout().addStretch(1)
 
70
        app.translateUI(self)
 
71
        
 
72
    def translateUI(self):
 
73
        self.shorthands.setText(_("Allow shorthands"))
 
74
        self.shorthands.setToolTip(_(
 
75
            "Use short notation for some articulations like staccato."))
 
76
 
 
77
    def icon(self):
 
78
        """Should return an icon for our tab."""
 
79
        return symbols.icon("articulation_prall")
 
80
    
 
81
    def title(self):
 
82
        """Should return a title for our tab."""
 
83
        return _("Articulations")
 
84
  
 
85
    def tooltip(self):
 
86
        """Returns a tooltip"""
 
87
        return _("Different kinds of articulations and other signs.")
 
88
 
 
89
 
 
90
class Group(buttongroup.ButtonGroup):
 
91
    def actionData(self):
 
92
        for name, title in self.actionTexts():
 
93
            yield name, symbols.icon('articulation_'+name), None
 
94
 
 
95
    def actionTriggered(self, name):
 
96
        if self.tool().shorthands.isChecked() and name in shorthands:
 
97
            text = '_-^'[self.direction()+1] + shorthands[name]
 
98
        else:
 
99
            text = ('_', '', '^')[self.direction()+1] + '\\' + name
 
100
        cursor = self.mainwindow().textCursor()
 
101
        selection = cursor.hasSelection()
 
102
        cursors = articulation_positions(cursor)
 
103
        if cursors:
 
104
            with cursortools.editBlock(cursor):
 
105
                for c in cursors:
 
106
                    c.insertText(text)
 
107
            if not selection:
 
108
                self.mainwindow().currentView().setTextCursor(c)
 
109
        elif not selection:
 
110
            cursor.insertText(text)
 
111
 
 
112
 
 
113
class ArticulationsGroup(Group):
 
114
    def translateUI(self):
 
115
        self.setTitle(_("Articulations"))
 
116
        
 
117
    def actionTexts(self):
 
118
        yield 'accent', _("Accent")
 
119
        yield 'marcato', _("Marcato")
 
120
        yield 'staccatissimo', _("Staccatissimo")
 
121
        yield 'staccato', _("Staccato")
 
122
        yield 'portato', _("Portato")
 
123
        yield 'tenuto', _("Tenuto")
 
124
        yield 'espressivo', _("Espressivo")
 
125
 
 
126
 
 
127
class OrnamentsGroup(Group):
 
128
    def translateUI(self):
 
129
        self.setTitle(_("Ornaments"))
 
130
        
 
131
    def actionTexts(self):
 
132
        yield 'trill', _("Trill")
 
133
        yield 'prall', _("Prall")
 
134
        yield 'mordent', _("Mordent")
 
135
        yield 'turn', _("Turn")
 
136
        yield 'prallprall', _("Prall prall")
 
137
        yield 'prallmordent', _("Prall mordent")
 
138
        yield 'upprall', _("Up prall")
 
139
        yield 'downprall', _("Down prall")
 
140
        yield 'upmordent', _("Up mordent")
 
141
        yield 'downmordent', _("Down mordent")
 
142
        yield 'prallup', _("Prall up")
 
143
        yield 'pralldown', _("Prall down")
 
144
        yield 'lineprall', _("Line prall")
 
145
        yield 'reverseturn', _("Reverse turn")
 
146
 
 
147
 
 
148
class SignsGroup(Group):
 
149
    def translateUI(self):
 
150
        self.setTitle(_("Signs"))
 
151
        
 
152
    def actionTexts(self):
 
153
        yield 'fermata', _("Fermata")
 
154
        yield 'shortfermata', _("Short fermata")
 
155
        yield 'longfermata', _("Long fermata")
 
156
        yield 'verylongfermata', _("Very long fermata")
 
157
        yield 'segno', _("Segno")
 
158
        yield 'coda', _("Coda")
 
159
        yield 'varcoda', _("Varcoda")
 
160
        yield 'signumcongruentiae', _("Signumcongruentiae")
 
161
 
 
162
 
 
163
class OtherGroup(Group):
 
164
    def translateUI(self):
 
165
        self.setTitle(_("Other"))
 
166
    
 
167
    def actionTexts(self):
 
168
        yield 'upbow', _("Upbow")
 
169
        yield 'downbow', _("Downbow")
 
170
        yield 'snappizzicato', _("Snappizzicato")
 
171
        yield 'open', _("Open (e.g. brass)")
 
172
        yield 'stopped', _("Stopped (e.g. brass)")
 
173
        yield 'flageolet', _("Flageolet")
 
174
        yield 'thumb', _("Thumb")
 
175
        yield 'lheel', _("Left heel")
 
176
        yield 'rheel', _("Right heel")
 
177
        yield 'ltoe', _("Left toe")
 
178
        yield 'rtoe', _("Right toe")
 
179
        yield 'halfopen', _("Half open (e.g. hi-hat)")
 
180
 
 
181
 
 
182
def articulation_positions(cursor):
 
183
    """Returns a list of positions where an articulation can be added.
 
184
    
 
185
    Every position is given as a QTextCursor instance.
 
186
    If the cursor has a selection, all positions in the selection are returned.
 
187
    
 
188
    """
 
189
    if cursor.hasSelection():
 
190
        source = tokeniter.Source.selection(cursor, True)
 
191
        tokens = None
 
192
        rests = False
 
193
    else:
 
194
        source = tokeniter.Source.fromCursor(cursor, True, -1)
 
195
        tokens = source.tokens # only current line
 
196
        rests = True
 
197
    
 
198
    positions = []
 
199
    for p in music.music_items(source, tokens=tokens):
 
200
        if not rests and isinstance(p[0], ly.lex.lilypond.Rest):
 
201
            continue
 
202
        positions.append(source.cursor(p[-1], start=len(p[-1])))
 
203
        if not cursor.hasSelection():
 
204
            break # leave if first found, that's enough
 
205
    return positions
 
206
 
 
207