class StaffGroup(_base.Container): @staticmethod def title(_=_base.translate): return _("Staff Group") def accepts(self): return (StaffGroup, _base.Part) def createWidgets(self, layout): self.systemStartLabel = QLabel() self.systemStart = QComboBox() self.systemStartLabel.setBuddy(self.systemStart) self.systemStart.setModel( listmodel.ListModel( ( # L10N: Brace like a piano staff (lambda: _("Brace"), 'system_start_brace'), # L10N: Bracket like a choir staff (lambda: _("Bracket"), 'system_start_bracket'), # L10N: Square bracket like a sub-group (lambda: _("Square"), 'system_start_square'), ), self.systemStart, display=listmodel.translate_index(0), icon=lambda item: symbols.icon(item[1]))) self.systemStart.setIconSize(QSize(64, 64)) self.connectBarLines = QCheckBox(checked=True) box = QHBoxLayout() box.addWidget(self.systemStartLabel) box.addWidget(self.systemStart) layout.addLayout(box) layout.addWidget(self.connectBarLines) def translateWidgets(self): self.systemStartLabel.setText(_("Type:")) self.connectBarLines.setText(_("Connect Barlines")) self.connectBarLines.setToolTip( _("If checked, barlines are connected between the staves.")) self.systemStart.model().update() def build(self, data, builder): s = self.systemStart.currentIndex() b = self.connectBarLines.isChecked() if s == 0: node = ly.dom.GrandStaff() if not b: ly.dom.Line("\\remove Span_bar_engraver", node.getWith()) else: node = ly.dom.StaffGroup() if b else ly.dom.ChoirStaff() if s == 2: node.getWith()['systemStartDelimiter'] = ly.dom.Scheme( "'SystemStartSquare") data.nodes.append(node) data.music = ly.dom.Simr(node)
class StaffGroup(_base.Container): @staticmethod def title(_=_base.translate): return _("Staff Group") def accepts(self): return (StaffGroup, _base.Part) def createWidgets(self, layout): self.systemStartLabel = QLabel() self.systemStart = QComboBox() self.systemStartLabel.setBuddy(self.systemStart) self.systemStart.setModel(listmodel.ListModel(( # L10N: Brace like a piano staff (lambda: _("Brace"), 'system_start_brace'), # L10N: Bracket like a choir staff (lambda: _("Bracket"), 'system_start_bracket'), # L10N: Square bracket like a sub-group (lambda: _("Square"), 'system_start_square'), ), self.systemStart, display=listmodel.translate_index(0), icon=lambda item: symbols.icon(item[1]))) self.systemStart.setIconSize(QSize(64, 64)) self.connectBarLines = QCheckBox(checked=True) box = QHBoxLayout() box.addWidget(self.systemStartLabel) box.addWidget(self.systemStart) layout.addLayout(box) layout.addWidget(self.connectBarLines) def translateWidgets(self): self.systemStartLabel.setText(_("Type:")) self.connectBarLines.setText(_("Connect Barlines")) self.connectBarLines.setToolTip(_("If checked, barlines are connected between the staves.")) self.systemStart.model().update() def build(self, data, builder): s = self.systemStart.currentIndex() b = self.connectBarLines.isChecked() if s == 0: node = ly.dom.GrandStaff() if not b: ly.dom.Line("\\remove Span_bar_engraver", node.getWith()) else: node = ly.dom.StaffGroup() if b else ly.dom.ChoirStaff() if s == 2: node.getWith()['systemStartDelimiter'] = ly.dom.Scheme("'SystemStartSquare") data.nodes.append(node) data.music = ly.dom.Simr(node)
class RecentPathsWComboMixin(RecentPathsWidgetMixin): """ Adds file combo handling to :obj:`RecentPathsWidgetMixin`. The mixin constructs a combo box `self.file_combo` and provides a method `set_file_list` for updating its content. The mixin also overloads the inherited `add_path` and `select_file` to call `set_file_list`. """ def __init__(self): super().__init__() self.file_combo = \ QComboBox(self, sizeAdjustPolicy=QComboBox.AdjustToContents) def add_path(self, filename): """Add (or move) a file name to the top of recent paths""" super().add_path(filename) self.set_file_list() def select_file(self, n): """Move the n-th file to the top of the list""" super().select_file(n) self.set_file_list() def set_file_list(self): """ Sets the items in the file list combo """ self._check_init() self.file_combo.clear() if not self.recent_paths: self.file_combo.addItem("(none)") self.file_combo.model().item(0).setEnabled(False) else: for i, recent in enumerate(self.recent_paths): self.file_combo.addItem(recent.basename) self.file_combo.model().item(i).setToolTip(recent.abspath) def workflowEnvChanged(self, key, value, oldvalue): super().workflowEnvChanged(key, value, oldvalue) if key == "basedir": self.set_file_list()
class ChordNames(object): def createWidgets(self, layout): self.chordStyleLabel = QLabel() self.chordStyle = QComboBox() self.chordStyleLabel.setBuddy(self.chordStyle) self.chordStyle.setModel(listmodel.ListModel(chordNameStyles, self.chordStyle, display=listmodel.translate)) self.guitarFrets = QCheckBox() box = QHBoxLayout() box.addWidget(self.chordStyleLabel) box.addWidget(self.chordStyle) layout.addLayout(box) layout.addWidget(self.guitarFrets) def translateWidgets(self): self.chordStyleLabel.setText(_("Chord style:")) self.guitarFrets.setText(_("Guitar fret diagrams")) self.guitarFrets.setToolTip(_( "Show predefined guitar fret diagrams below the chord names " "(LilyPond 2.12 and above).")) self.chordStyle.model().update() def build(self, data, builder): p = ly.dom.ChordNames() a = data.assign('chordNames') ly.dom.Identifier(a.name, p) s = ly.dom.ChordMode(a) ly.dom.Identifier(data.globalName, s).after = 1 i = self.chordStyle.currentIndex() if i > 0: ly.dom.Line('\\{0}Chords'.format( ('german', 'semiGerman', 'italian', 'french')[i-1]), s) ly.dom.LineComment(_("Chords follow here."), s) ly.dom.BlankLine(s) data.nodes.append(p) if self.guitarFrets.isChecked(): f = ly.dom.FretBoards() ly.dom.Identifier(a.name, f) data.nodes.append(f) data.includes.append("predefined-guitar-fretboards.ly")
class Drums(_base.Part): @staticmethod def title(_=_base.translate): return _("Drums") @staticmethod def short(_=_base.translate): return _("abbreviation for Drums", "Dr.") def createWidgets(self, layout): self.voicesLabel = QLabel() self.voices = QSpinBox(minimum=1, maximum=4, value=1) self.drumStyleLabel = QLabel() self.drumStyle = QComboBox() self.drumStyle.setModel( listmodel.ListModel(drumStyles, self.drumStyle, display=listmodel.translate)) self.drumStems = QCheckBox() box = QHBoxLayout() box.addWidget(self.voicesLabel) box.addWidget(self.voices) layout.addLayout(box) box = QHBoxLayout() box.addWidget(self.drumStyleLabel) box.addWidget(self.drumStyle) layout.addLayout(box) layout.addWidget(self.drumStems) def translateWidgets(self): self.voicesLabel.setText(_("Voices:")) self.drumStyleLabel.setText(_("Style:")) self.drumStems.setText(_("Remove stems")) self.drumStems.setToolTip(_("Remove the stems from the drum notes.")) self.drumStyle.model().update() def assignDrums(self, data, name=None): """Creates an empty name = \drummode assignment. Returns the assignment. """ a = data.assign(name) s = ly.dom.DrumMode(a) ly.dom.Identifier(data.globalName, s) ly.dom.LineComment(_("Drums follow here."), s) ly.dom.BlankLine(s) return a def build(self, data, builder): p = ly.dom.DrumStaff() s = ly.dom.Simr(p) if self.voices.value() > 1: for i in range(1, self.voices.value() + 1): q = ly.dom.Seq(ly.dom.DrumVoice(parent=s)) ly.dom.Text('\\voice' + ly.util.int2text(i), q) a = self.assignDrums(data, 'drum' + ly.util.int2text(i)) ly.dom.Identifier(a.name, q) else: a = self.assignDrums(data, 'drum') ly.dom.Identifier(a.name, s) builder.setInstrumentNamesFromPart(p, self, data) i = self.drumStyle.currentIndex() if i > 0: v = ('drums', 'timbales', 'congas', 'bongos', 'percussion')[i] p.getWith()['drumStyleTable'] = ly.dom.Scheme(v + '-style') v = (5, 2, 2, 2, 1)[i] ly.dom.Line("\\override StaffSymbol #'line-count = #{0}".format(v), p.getWith()) if self.drumStems.isChecked(): ly.dom.Line("\\override Stem #'stencil = ##f", p.getWith()) ly.dom.Line( "\\override Stem #'length = #3 % " + _("keep some distance."), p.getWith()) data.nodes.append(p)
class ScoreProperties(object): """This is only the base class, it should be mixed in with a widget or a different way.""" def createWidgets(self): """Creates all widgets.""" self.createKeySignatureWidget() self.createTimeSignatureWidget() self.createPickupWidget() self.createMetronomeWidget() self.createTempoWidget() def layoutWidgets(self, layout): """Adds all widgets to a vertical layout.""" self.layoutKeySignatureWidget(layout) self.layoutTimeSignatureWidget(layout) self.layoutPickupWidget(layout) self.layoutMetronomeWidget(layout) self.layoutTempoWidget(layout) def translateWidgets(self): self.translateKeySignatureWidget() self.translateTimeSignatureWidget() self.translatePickupWidget() self.tranlateMetronomeWidget() self.translateTempoWidget() def ly(self, node, builder): """Adds appropriate LilyPond command nodes to the parent node. Settings from the builder are used where that makes sense. All widgets must be present. """ self.lyKeySignature(node, builder) self.lyTimeSignature(node, builder) self.lyPickup(node, builder) self.lyTempo(node, builder) def globalSection(self, builder): """Returns a sequential expression between { } containing the output of ly().""" seq = ly.dom.Seq() self.ly(seq, builder) return seq # Key signature def createKeySignatureWidget(self): self.keySignatureLabel = QLabel() self.keyNote = QComboBox() self.keyNote.setModel(listmodel.ListModel(keyNames['nederlands'], self.keyNote)) self.keyMode = QComboBox() self.keyMode.setModel(listmodel.ListModel(modes, self.keyMode, display=listmodel.translate_index(1))) self.keySignatureLabel.setBuddy(self.keyNote) def translateKeySignatureWidget(self): self.keySignatureLabel.setText(_("Key signature:")) self.keyMode.model().update() def layoutKeySignatureWidget(self, layout): """Adds our widgets to a layout, assuming it is a QVBoxLayout.""" box = QHBoxLayout() box.addWidget(self.keySignatureLabel) box.addWidget(self.keyNote) box.addWidget(self.keyMode) layout.addLayout(box) def setPitchLanguage(self, language='nederlands'): self.keyNote.model()._data = keyNames[language or 'nederlands'] self.keyNote.model().update() def lyKeySignature(self, node, builder): """Adds the key signature to the ly.dom node parent.""" note, alter = keys[self.keyNote.currentIndex()] alter = fractions.Fraction(alter, 2) mode = modes[self.keyMode.currentIndex()][0] ly.dom.KeySignature(note, alter, mode, node).after = 1 # Time signature def createTimeSignatureWidget(self): self.timeSignatureLabel = QLabel() self.timeSignature = QComboBox(editable=True) icons = { '(4/4)': symbols.icon('time_c44'), '(2/2)': symbols.icon('time_c22'), } self.timeSignature.setModel(listmodel.ListModel(timeSignaturePresets, self.timeSignature, icon=icons.get)) self.timeSignature.setCompleter(None) self.timeSignatureLabel.setBuddy(self.timeSignature) def translateTimeSignatureWidget(self): self.timeSignatureLabel.setText(_("Time signature:")) def layoutTimeSignatureWidget(self, layout): """Adds our widgets to a layout, assuming it is a QVBoxLayout.""" box = QHBoxLayout() box.addWidget(self.timeSignatureLabel) box.addWidget(self.timeSignature) layout.addLayout(box) def lyTimeSignature(self, node, builder): """Adds the time signature to the ly.dom node parent.""" sig = self.timeSignature.currentText().strip() if '+' in sig: pass # TODO: implement support for \compoundMeter else: if sig == '(2/2)': ly.dom.TimeSignature(2, 2, node).after = 1 elif sig == '(4/4)': ly.dom.TimeSignature(4, 4, node).after = 1 else: match = re.search(r'(\d+).*?(\d+)', sig) if match: if builder.lyVersion >= (2, 11, 44): ly.dom.Line(r"\numericTimeSignature", node) else: ly.dom.Line(r"\override Staff.TimeSignature #'style = #'()", node) num, beat = map(int, match.group(1, 2)) ly.dom.TimeSignature(num, beat, node).after = 1 # Pickup bar def createPickupWidget(self): self.pickupLabel = QLabel() self.pickup = QComboBox() pickups = [''] pickups.extend(durations) self.pickup.setModel(listmodel.ListModel(pickups, self.pickup, display = lambda item: item or _("None"), icon = lambda item: symbols.icon('note_{0}'.format(item.replace('.', 'd'))) if item else None)) self.pickup.view().setIconSize(QSize(22, 22)) self.pickupLabel.setBuddy(self.pickup) def translatePickupWidget(self): self.pickupLabel.setText(_("Pickup measure:")) self.pickup.model().update() def layoutPickupWidget(self, layout): box = QHBoxLayout() box.addWidget(self.pickupLabel) box.addWidget(self.pickup) layout.addLayout(box) def lyPickup(self, node, builder): if self.pickup.currentIndex() > 0: dur, dots = partialDurations[self.pickup.currentIndex() - 1] ly.dom.Partial(dur, dots, parent=node) # Metronome value def createMetronomeWidget(self): self.metronomeLabel = QLabel() self.metronomeNote = QComboBox() self.metronomeNote.setModel(listmodel.ListModel(durations, display=None, icon = lambda item: symbols.icon('note_{0}'.format(item.replace('.', 'd'))))) self.metronomeNote.setCurrentIndex(durations.index('4')) self.metronomeNote.view().setIconSize(QSize(22, 22)) self.metronomeEqualSign = QLabel('=') self.metronomeEqualSign.setFixedWidth(self.metronomeEqualSign.minimumSizeHint().width()) self.metronomeValue = QComboBox(editable=True) self.metronomeValue.setModel(listmodel.ListModel(metronomeValues, self.metronomeValue, display=format)) self.metronomeValue.setCompleter(None) self.metronomeValue.setValidator(QIntValidator(0, 999, self.metronomeValue)) self.metronomeValue.setCurrentIndex(metronomeValues.index(100)) self.metronomeTempo = widgets.tempobutton.TempoButton() self.metronomeTempo.tempo.connect(self.setMetronomeValue) self.metronomeLabel.setBuddy(self.metronomeNote) def layoutMetronomeWidget(self, layout): box = QHBoxLayout(spacing=0) box.addWidget(self.metronomeLabel) box.addWidget(self.metronomeNote) box.addWidget(self.metronomeEqualSign) box.addWidget(self.metronomeValue) box.addWidget(self.metronomeTempo) layout.addLayout(box) def tranlateMetronomeWidget(self): self.metronomeLabel.setText(_("Metronome mark:")) def setMetronomeValue(self, bpm): """ Tap the tempo tap button """ l = [abs(t - bpm) for t in metronomeValues] m = min(l) if m < 6: self.metronomeValue.setCurrentIndex(l.index(m)) # Tempo indication def createTempoWidget(self): self.tempoLabel = QLabel() self.tempo = widgets.lineedit.LineEdit() completionmodel.complete(self.tempo, "scorewiz/completion/scoreproperties/tempo") self.tempo.completer().setCaseSensitivity(Qt.CaseInsensitive) self.tempoLabel.setBuddy(self.tempo) def layoutTempoWidget(self, layout): box = QHBoxLayout() box.addWidget(self.tempoLabel) box.addWidget(self.tempo) layout.addLayout(box) def translateTempoWidget(self): self.tempoLabel.setText(_("Tempo indication:")) def lyTempo(self, node, builder): """Returns an appropriate tempo indication.""" text = self.tempo.text().strip() if builder.showMetronomeMark: dur = durations[self.metronomeNote.currentIndex()] val = self.metronomeValue.currentText() elif text: dur = None val = None else: return tempo = ly.dom.Tempo(dur, val, node) if text: ly.dom.QuotedString(text, tempo) def lyMidiTempo(self, node): """Sets the configured tempo in the tempoWholesPerMinute variable.""" node['tempoWholesPerMinute'] = ly.dom.Scheme(self.schemeMidiTempo()) def schemeMidiTempo(self): """Returns a string with the tempo like '(ly:make-moment 100 4)' from the settings.""" base, mul = midiDurations[self.metronomeNote.currentIndex()] val = int(self.metronomeValue.currentText()) * mul return "(ly:make-moment {0} {1})".format(val, base) def lySimpleMidiTempo(self, node): """Return a simple \tempo x=y node for the currently set tempo.""" dur = durations[self.metronomeNote.currentIndex()] val = self.metronomeValue.currentText() return ly.dom.Tempo(dur, val, node)
class TablaturePart(_base.Part): """Base class for tablature instrument part types.""" octave = 0 clef = None transposition = None tunings = () # may contain a list of tunings. tabFormat = '' # can contain a tablatureFormat value. def createWidgets(self, layout): self.staffTypeLabel = QLabel() self.staffType = QComboBox() self.staffTypeLabel.setBuddy(self.staffType) self.staffType.setModel( listmodel.ListModel(tablatureStaffTypes, self.staffType, display=listmodel.translate)) box = QHBoxLayout() layout.addLayout(box) box.addWidget(self.staffTypeLabel) box.addWidget(self.staffType) if self.tunings: self.createTuningWidgets(layout) self.staffType.activated.connect(self.slotTabEnable) self.slotTabEnable(0) def createTuningWidgets(self, layout): self.tuningLabel = QLabel() self.tuning = QComboBox() self.tuningLabel.setBuddy(self.tuning) tunings = [('', lambda: _("Default"))] tunings.extend(self.tunings) tunings.append(('', lambda: _("Custom tuning"))) self.tuning.setModel( listmodel.ListModel(tunings, self.tuning, display=listmodel.translate_index(1))) self.tuning.setCurrentIndex(1) self.customTuning = QLineEdit(enabled=False) completionmodel.complete( self.customTuning, "scorewiz/completion/plucked_strings/custom_tuning") self.tuning.currentIndexChanged.connect(self.slotCustomTuningEnable) box = QHBoxLayout() layout.addLayout(box) box.addWidget(self.tuningLabel) box.addWidget(self.tuning) layout.addWidget(self.customTuning) def translateWidgets(self): self.staffTypeLabel.setText(_("Staff type:")) self.staffType.model().update() if self.tunings: self.translateTuningWidgets() def translateTuningWidgets(self): self.tuningLabel.setText(_("Tuning:")) self.customTuning.setToolTip('<qt>' + _( "Select custom tuning in the combobox and " "enter a custom tuning here, e.g. <code>e, a d g b e'</code>. " "Use absolute note names in the same language as you want to use " "in your document (by default: \"nederlands\").")) try: self.customTuning.setPlaceholderText(_("Custom tuning...")) except AttributeError: pass # only in Qt 4.7+ self.tuning.model().update() def slotTabEnable(self, enable): """Called when the user changes the staff type. Non-zero if the user wants a TabStaff. """ self.tuning.setEnabled(bool(enable)) if enable: self.slotCustomTuningEnable(self.tuning.currentIndex()) else: self.customTuning.setEnabled(False) def slotCustomTuningEnable(self, index): self.customTuning.setEnabled(index > len(self.tunings)) def voiceCount(self): """Returns the number of voices. Inherit to make this user-settable. """ return 1 def build(self, data, builder): # First make assignments for the voices we want to create numVoices = self.voiceCount() if numVoices == 1: voices = (ly.util.mkid(data.name()), ) elif numVoices == 2: order = 1, 2 voices = 'upper', 'lower' elif numVoices == 3: order = 1, 3, 2 voices = 'upper', 'middle', 'lower' else: order = 1, 2, 3, 4 voices = [ ly.util.mkid(data.name(), "voice") + ly.util.int2text(i) for i in order ] assignments = [ data.assignMusic(name, self.octave, self.transposition) for name in voices ] staffType = self.staffType.currentIndex() if staffType in (0, 2): # create a normal staff staff = ly.dom.Staff() seq = ly.dom.Seqr(staff) if self.clef: ly.dom.Clef(self.clef, seq) mus = ly.dom.Simr(seq) for a in assignments[:-1]: ly.dom.Identifier(a.name, mus) ly.dom.VoiceSeparator(mus) ly.dom.Identifier(assignments[-1].name, mus) builder.setMidiInstrument(staff, self.midiInstrument) if staffType in (1, 2): # create a tab staff tabstaff = ly.dom.TabStaff() if self.tabFormat: tabstaff.getWith()['tablatureFormat'] = ly.dom.Scheme( self.tabFormat) self.setTunings(tabstaff) sim = ly.dom.Simr(tabstaff) if numVoices == 1: ly.dom.Identifier(assignments[0].name, sim) else: for num, a in zip(order, assignments): s = ly.dom.Seq(ly.dom.TabVoice(parent=sim)) ly.dom.Text('\\voice' + ly.util.int2text(num), s) ly.dom.Identifier(a.name, s) if staffType == 0: # only a normal staff p = staff elif staffType == 1: # only a TabStaff builder.setMidiInstrument(tabstaff, self.midiInstrument) p = tabstaff else: # both TabStaff and normal staff p = ly.dom.StaffGroup() s = ly.dom.Sim(p) s.append(staff) s.append(tabstaff) builder.setInstrumentNamesFromPart(p, self, data) data.nodes.append(p) def setTunings(self, tab): if self.tunings: i = self.tuning.currentIndex() if i == 0: return elif i > len(self.tunings): value = ly.dom.Text("\\stringTuning <{0}>".format( self.customTuning.text())) else: tuning = self.tunings[self.tuning.currentIndex() - 1][0] value = ly.dom.Scheme(tuning) tab.getWith()['stringTunings'] = value
class InstrumentNames(QGroupBox): def __init__(self, parent): super(InstrumentNames, self).__init__(parent, checkable=True, checked=True) grid = QGridLayout() self.setLayout(grid) self.firstSystemLabel = QLabel() self.firstSystem = QComboBox() self.firstSystemLabel.setBuddy(self.firstSystem) self.otherSystemsLabel = QLabel() self.otherSystems = QComboBox() self.otherSystemsLabel.setBuddy(self.otherSystems) self.languageLabel = QLabel() self.language = QComboBox() self.languageLabel.setBuddy(self.language) self.firstSystem.setModel( listmodel.ListModel((lambda: _("Long"), lambda: _("Short")), self.firstSystem, display=listmodel.translate)) self.otherSystems.setModel( listmodel.ListModel( (lambda: _("Long"), lambda: _("Short"), lambda: _("None")), self.otherSystems, display=listmodel.translate)) self._langs = l = ['', 'C'] l.extend(sorted(po.available())) def display(lang): if lang == 'C': return _("English (untranslated)") elif not lang: return _("Default") return language_names.languageName(lang, po.setup.current()) self.language.setModel( listmodel.ListModel(l, self.language, display=display)) grid.addWidget(self.firstSystemLabel, 0, 0) grid.addWidget(self.firstSystem, 0, 1) grid.addWidget(self.otherSystemsLabel, 1, 0) grid.addWidget(self.otherSystems, 1, 1) grid.addWidget(self.languageLabel, 2, 0) grid.addWidget(self.language, 2, 1) app.translateUI(self) self.loadSettings() self.window().finished.connect(self.saveSettings) def translateUI(self): self.setTitle(_("Instrument names")) self.firstSystemLabel.setText(_("First system:")) self.otherSystemsLabel.setText(_("Other systems:")) self.languageLabel.setText(_("Language:")) self.firstSystem.setToolTip( _("Use long or short instrument names before the first system.")) self.otherSystems.setToolTip( _("Use short, long or no instrument names before the next systems." )) self.language.setToolTip( _("Which language to use for the instrument names.")) self.firstSystem.model().update() self.otherSystems.model().update() self.language.model().update() def getLanguage(self): """Returns the language the user has set. '' means: default (use same translation as system) 'C' means: English (untranslated) or a language code that is available in Frescobaldi's translation. """ return self._langs[self.language.currentIndex()] def loadSettings(self): s = QSettings() s.beginGroup('scorewiz/instrumentnames') self.setChecked(s.value('enabled', True, bool)) allow = ['long', 'short'] first = s.value('first', '', type("")) self.firstSystem.setCurrentIndex( allow.index(first) if first in allow else 0) allow = ['long', 'short', 'none'] other = s.value('other', '', type("")) self.otherSystems.setCurrentIndex( allow.index(other) if other in allow else 2) language = s.value('language', '', type("")) self.language.setCurrentIndex( self._langs.index(language) if language in self._langs else 0) def saveSettings(self): s = QSettings() s.beginGroup('scorewiz/instrumentnames') s.setValue('enable', self.isChecked()) s.setValue('first', ('long', 'short')[self.firstSystem.currentIndex()]) s.setValue('other', ('long', 'short', 'none')[self.otherSystems.currentIndex()]) s.setValue('language', self._langs[self.language.currentIndex()])
class OWImportImages(widget.OWWidget): name = "Import Images" description = "Import images from a directory(s)" icon = "icons/ImportImages.svg" priority = 110 outputs = [("Data", Orange.data.Table)] #: list of recent paths recent_paths = settings.Setting([]) # type: List[RecentPath] currentPath = settings.Setting(None) want_main_area = False resizing_enabled = False Modality = Qt.ApplicationModal # Modality = Qt.WindowModal MaxRecentItems = 20 def __init__(self): super().__init__() #: widget's runtime state self.__state = State.NoState self._imageMeta = [] self._imageCategories = {} self.__invalidated = False self.__pendingTask = None vbox = gui.vBox(self.controlArea) hbox = gui.hBox(vbox) self.recent_cb = QComboBox( sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, minimumContentsLength=16, ) self.recent_cb.activated[int].connect(self.__onRecentActivated) icons = standard_icons(self) browseaction = QAction( "Open/Load Images", self, iconText="\N{HORIZONTAL ELLIPSIS}", icon=icons.dir_open_icon, toolTip="Select a directory from which to load the images" ) browseaction.triggered.connect(self.__runOpenDialog) reloadaction = QAction( "Reload", self, icon=icons.reload_icon, toolTip="Reload current image set" ) reloadaction.triggered.connect(self.reload) self.__actions = namespace( browse=browseaction, reload=reloadaction, ) browsebutton = QPushButton( browseaction.iconText(), icon=browseaction.icon(), toolTip=browseaction.toolTip(), clicked=browseaction.trigger ) reloadbutton = QPushButton( reloadaction.iconText(), icon=reloadaction.icon(), clicked=reloadaction.trigger, default=True, ) hbox.layout().addWidget(self.recent_cb) hbox.layout().addWidget(browsebutton) hbox.layout().addWidget(reloadbutton) self.addActions([browseaction, reloadaction]) reloadaction.changed.connect( lambda: reloadbutton.setEnabled(reloadaction.isEnabled()) ) box = gui.vBox(vbox, "Info") self.infostack = QStackedWidget() self.info_area = QLabel( text="No image set selected", wordWrap=True ) self.progress_widget = QProgressBar( minimum=0, maximum=0 ) self.cancel_button = QPushButton( "Cancel", icon=icons.cancel_icon, ) self.cancel_button.clicked.connect(self.cancel) w = QWidget() vlayout = QVBoxLayout() vlayout.setContentsMargins(0, 0, 0, 0) hlayout = QHBoxLayout() hlayout.setContentsMargins(0, 0, 0, 0) hlayout.addWidget(self.progress_widget) hlayout.addWidget(self.cancel_button) vlayout.addLayout(hlayout) self.pathlabel = TextLabel() self.pathlabel.setTextElideMode(Qt.ElideMiddle) self.pathlabel.setAttribute(Qt.WA_MacSmallSize) vlayout.addWidget(self.pathlabel) w.setLayout(vlayout) self.infostack.addWidget(self.info_area) self.infostack.addWidget(w) box.layout().addWidget(self.infostack) self.__initRecentItemsModel() self.__invalidated = True self.__executor = ThreadExecutor(self) QApplication.postEvent(self, QEvent(RuntimeEvent.Init)) def __initRecentItemsModel(self): if self.currentPath is not None and \ not os.path.isdir(self.currentPath): self.currentPath = None recent_paths = [] for item in self.recent_paths: if os.path.isdir(item.abspath): recent_paths.append(item) recent_paths = recent_paths[:OWImportImages.MaxRecentItems] recent_model = self.recent_cb.model() for pathitem in recent_paths: item = RecentPath_asqstandarditem(pathitem) recent_model.appendRow(item) self.recent_paths = recent_paths if self.currentPath is not None and \ os.path.isdir(self.currentPath) and self.recent_paths and \ os.path.samefile(self.currentPath, self.recent_paths[0].abspath): self.recent_cb.setCurrentIndex(0) else: self.currentPath = None self.recent_cb.setCurrentIndex(-1) self.__actions.reload.setEnabled(self.currentPath is not None) def customEvent(self, event): """Reimplemented.""" if event.type() == RuntimeEvent.Init: if self.__invalidated: try: self.start() finally: self.__invalidated = False super().customEvent(event) def __runOpenDialog(self): startdir = os.path.expanduser("~/") if self.recent_paths: startdir = self.recent_paths[0].abspath if OWImportImages.Modality == Qt.WindowModal: dlg = QFileDialog( self, "Select Top Level Directory", startdir, acceptMode=QFileDialog.AcceptOpen, modal=True, ) dlg.setFileMode(QFileDialog.Directory) dlg.setOption(QFileDialog.ShowDirsOnly) dlg.setDirectory(startdir) dlg.setAttribute(Qt.WA_DeleteOnClose) @dlg.accepted.connect def on_accepted(): dirpath = dlg.selectedFiles() if dirpath: self.setCurrentPath(dirpath[0]) self.start() dlg.open() else: dirpath = QFileDialog.getExistingDirectory( self, "Select Top Level Directory", startdir ) if dirpath: self.setCurrentPath(dirpath) self.start() def __onRecentActivated(self, index): item = self.recent_cb.itemData(index) if item is None: return assert isinstance(item, RecentPath) self.setCurrentPath(item.abspath) self.start() def __updateInfo(self): if self.__state == State.NoState: text = "No image set selected" elif self.__state == State.Processing: text = "Processing" elif self.__state == State.Done: nvalid = sum(imeta.isvalid for imeta in self._imageMeta) ncategories = len(self._imageCategories) if ncategories < 2: text = "{} images".format(nvalid) else: text = "{} images / {} categories".format(nvalid, ncategories) elif self.__state == State.Cancelled: text = "Cancelled" elif self.__state == State.Error: text = "Error state" else: assert False self.info_area.setText(text) if self.__state == State.Processing: self.infostack.setCurrentIndex(1) else: self.infostack.setCurrentIndex(0) def setCurrentPath(self, path): """ Set the current root image path to path If the path does not exists or is not a directory the current path is left unchanged Parameters ---------- path : str New root import path. Returns ------- status : bool True if the current root import path was successfully changed to path. """ if self.currentPath is not None and path is not None and \ os.path.isdir(self.currentPath) and os.path.isdir(path) and \ os.path.samefile(self.currentPath, path): return True if not os.path.exists(path): warnings.warn("'{}' does not exist".format(path), UserWarning) return False elif not os.path.isdir(path): warnings.warn("'{}' is not a directory".format(path), UserWarning) return False newindex = self.addRecentPath(path) self.recent_cb.setCurrentIndex(newindex) if newindex >= 0: self.currentPath = path else: self.currentPath = None self.__actions.reload.setEnabled(self.currentPath is not None) if self.__state == State.Processing: self.cancel() return True def addRecentPath(self, path): """ Prepend a path entry to the list of recent paths If an entry with the same path already exists in the recent path list it is moved to the first place Parameters ---------- path : str """ existing = None for pathitem in self.recent_paths: if os.path.samefile(pathitem.abspath, path): existing = pathitem break model = self.recent_cb.model() if existing is not None: selected_index = self.recent_paths.index(existing) assert model.item(selected_index).data(Qt.UserRole) is existing self.recent_paths.remove(existing) row = model.takeRow(selected_index) self.recent_paths.insert(0, existing) model.insertRow(0, row) else: item = RecentPath(path, None, None) self.recent_paths.insert(0, item) model.insertRow(0, RecentPath_asqstandarditem(item)) return 0 def __setRuntimeState(self, state): assert state in State self.setBlocking(state == State.Processing) message = "" if state == State.Processing: assert self.__state in [State.Done, State.NoState, State.Error, State.Cancelled] message = "Processing" elif state == State.Done: assert self.__state == State.Processing elif state == State.Cancelled: assert self.__state == State.Processing message = "Cancelled" elif state == State.Error: message = "Error during processing" elif state == State.NoState: message = "" else: assert False self.__state = state if self.__state == State.Processing: self.infostack.setCurrentIndex(1) else: self.infostack.setCurrentIndex(0) self.setStatusMessage(message) self.__updateInfo() def reload(self): """ Restart the image scan task """ if self.__state == State.Processing: self.cancel() self._imageMeta = [] self._imageCategories = {} self.start() def start(self): """ Start/execute the image indexing operation """ self.error() self.__invalidated = False if self.currentPath is None: return if self.__state == State.Processing: assert self.__pendingTask is not None log.info("Starting a new task while one is in progress. " "Cancel the existing task (dir:'{}')" .format(self.__pendingTask.startdir)) self.cancel() startdir = self.currentPath self.__setRuntimeState(State.Processing) report_progress = methodinvoke( self, "__onReportProgress", (object,)) task = ImageScan(startdir, report_progress=report_progress) # collect the task state in one convenient place self.__pendingTask = taskstate = namespace( task=task, startdir=startdir, future=None, watcher=None, cancelled=False, cancel=None, ) def cancel(): # Cancel the task and disconnect if taskstate.future.cancel(): pass else: taskstate.task.cancelled = True taskstate.cancelled = True try: taskstate.future.result(timeout=3) except UserInterruptError: pass except TimeoutError: log.info("The task did not stop in in a timely manner") taskstate.watcher.finished.disconnect(self.__onRunFinished) taskstate.cancel = cancel def run_image_scan_task_interupt(): try: return task.run() except UserInterruptError: # Suppress interrupt errors, so they are not logged return taskstate.future = self.__executor.submit(run_image_scan_task_interupt) taskstate.watcher = FutureWatcher(taskstate.future) taskstate.watcher.finished.connect(self.__onRunFinished) @Slot() def __onRunFinished(self): assert QThread.currentThread() is self.thread() assert self.__state == State.Processing assert self.__pendingTask is not None assert self.sender() is self.__pendingTask.watcher assert self.__pendingTask.future.done() task = self.__pendingTask self.__pendingTask = None try: image_meta = task.future.result() except Exception as err: sys.excepthook(*sys.exc_info()) state = State.Error image_meta = [] self.error(traceback.format_exc()) else: state = State.Done self.error() categories = {} for imeta in image_meta: # derive categories from the path relative to the starting dir dirname = os.path.dirname(imeta.path) relpath = os.path.relpath(dirname, task.startdir) categories[dirname] = relpath self._imageMeta = image_meta self._imageCategories = categories self.__setRuntimeState(state) self.commit() def cancel(self): """ Cancel current pending task (if any). """ if self.__state == State.Processing: assert self.__pendingTask is not None self.__pendingTask.cancel() self.__pendingTask = None self.__setRuntimeState(State.Cancelled) @Slot(object) def __onReportProgress(self, arg): # report on scan progress from a worker thread # arg must be a namespace(count: int, lastpath: str) assert QThread.currentThread() is self.thread() if self.__state == State.Processing: self.pathlabel.setText(prettyfypath(arg.lastpath)) def commit(self): """ Create and commit a Table from the collected image meta data. """ if self._imageMeta: categories = self._imageCategories if len(categories) > 1: cat_var = Orange.data.DiscreteVariable( "category", values=list(sorted(categories.values())) ) else: cat_var = None # Image name (file basename without the extension) imagename_var = Orange.data.StringVariable("image name") # Full fs path image_var = Orange.data.StringVariable("image") image_var.attributes["type"] = "image" # file size/width/height size_var = Orange.data.ContinuousVariable( "size", number_of_decimals=0) width_var = Orange.data.ContinuousVariable( "width", number_of_decimals=0) height_var = Orange.data.ContinuousVariable( "height", number_of_decimals=0) domain = Orange.data.Domain( [], [cat_var] if cat_var is not None else [], [imagename_var, image_var, size_var, width_var, height_var] ) cat_data = [] meta_data = [] for imgmeta in self._imageMeta: if imgmeta.isvalid: if cat_var is not None: category = categories.get(os.path.dirname(imgmeta.path)) cat_data.append([cat_var.to_val(category)]) else: cat_data.append([]) basename = os.path.basename(imgmeta.path) imgname, _ = os.path.splitext(basename) meta_data.append( [imgname, imgmeta.path, imgmeta.size, imgmeta.width, imgmeta.height] ) cat_data = numpy.array(cat_data, dtype=float) meta_data = numpy.array(meta_data, dtype=object) table = Orange.data.Table.from_numpy( domain, numpy.empty((len(cat_data), 0), dtype=float), cat_data, meta_data ) else: table = None self.send("Data", table) def onDeleteWidget(self): self.cancel() self.__executor.shutdown(wait=True)
class QuestionDlg(QDialog): def __init__(self, parent=None): super(QuestionDlg,self).__init__(parent) # self.setStyleSheet("background-image:url('image/panelbg.jpg'); border: 2px; border-radius 2px;") # self.createDb() # return self.db = QSqlDatabase.addDatabase("QSQLITE"); self.db.setDatabaseName("studentNew.db") if not self.db.open(): QMessageBox.warning(None, "错误", "数据库连接失败: %s" % self.db.lastError().text()) sys.exit(1) self.g_curClassName = "" self.deleteTmpdata() self.setWindowFlags(Qt.CustomizeWindowHint) # self.setStyleSheet("border: 2px; border-radius 2px;") # self.setWindowFlags(Qt.FramelessWindowHint) self.setStyleSheet("background-color: rgba(132, 171, 208, 200);") self.tabWidget=QTabWidget(self) self.tabWidget.currentChanged.connect(self.changeTab) # tabWidget.setTabShape(QTabWidget.Triangular) self.tabWidget.setStyleSheet("QTabWidget::pane{border-width:1px;border-color:rgb(48, 104, 151);\ border-style: outset;background-color: rgb(132, 171, 208);\ background: transparent;} \ QTabWidget::tab-bar{border-width:0px;}\ QTabBar::tab { height: 60px; width: 260px; color:rgb(0, 0, 255); font-size:20px; font-weight:bold;} \ QTabBar::tab:hover{background:rgb(255,255, 255, 100);} \ QTabBar::tab:selected{border-color:green;background-color:white;color:green;}") # tabWidget.setStyleSheet("QTabBar::tab:hover{background:rgb(255,255, 255, 100);}") self.btngroup = QButtonGroup() self.popMenu = QMenu(self) entry1 = self.popMenu.addAction("正确") self.connect(entry1,SIGNAL('triggered()'), lambda : self.answerRight()) entry2 = self.popMenu.addAction("错误") self.connect(entry2,SIGNAL('triggered()'), lambda : self.answerWrong()) entry3 = self.popMenu.addAction("替换") self.connect(entry3,SIGNAL('triggered()'), lambda : self.resetStudent()) # Create the first tab page. self.w1=QWidget() self.w1.setAccessibleName("w1tab") self.genOneTab() # Create the second tab page. self.w2=QWidget() self.w2.setAccessibleName("w2tab") self.genTwoTab() self.tabWidget.addTab(self.w1,"") self.tabWidget.addTab(self.w2,"班级学生信息管理") self.tabWidget.resize(940,700) btnclose = QPushButton(self) btnclose.setToolTip("关闭") btnclose.setText("╳") btnclose.setGeometry(915, 5, 20, 20) btnclose.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)") btnclose.clicked.connect(self.close) btnMinimized = QPushButton(self) btnMinimized.setToolTip("最小化") btnMinimized.setText("▁") btnMinimized.setGeometry(890, 5, 20, 20) btnMinimized.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255)") btnMinimized.clicked.connect(lambda: self.showMinimized()) self.btnSysMenu = QPushButton(self) # self.btnSysMenu.setText("▼") self.btnSysMenu.setGeometry(865, 5, 20, 20) self.btnSysMenu.setToolTip("系统设置") self.btnSysMenu.clicked.connect(lambda: self.showMinimized()) menufont = QFont("宋体", 10) popMenu = QMenu(self) entry1 = popMenu.addAction("所有学生提问信息清零") entry1.setFont(menufont) self.connect(entry1,SIGNAL('triggered()'), self.initStudent) entry2 = popMenu.addAction("清除本堂课提问人员") entry2.setFont(menufont) self.connect(entry2,SIGNAL('triggered()'), self.deleteTmpdata) entry3 = popMenu.addAction("关于...") entry3.setFont(menufont) self.connect(entry3,SIGNAL('triggered()'), self.aboutMe) entry4 = popMenu.addAction("导出...") entry4.setFont(menufont) self.connect(entry4,SIGNAL('triggered()'), self.exportNotice) self.btnSysMenu.setMenu(popMenu) self.btnSysMenu.setStyleSheet("QPushButton::menu-indicator {image: url('image/sysmenu.png');subcontrol-position: right center;} ") # self.btnSysMenu.setStyleSheet("background-color:rgb(0,100,0); color:rgb(255,255,255);") authorinfo = QLabel(self.tabWidget) # authorinfo.setToolTip("关闭") authorinfo.setText("程序设计:汕头市大华路第一小学 赵小娜,有任何问题请反馈至[email protected]。") authorinfo.setGeometry(20, 665, 470, 26) authorinfo.setFont(QFont('Courier New')) authorinfo.setStyleSheet("background-color:rgba(255, 255, 255,160); font-size:12px;border: 1px solid rgb(60,200,255,200);color:rgba(0,0,0,220);border-radius:12px;") self.setWindowTitle("课堂随机提问") self.setWindowIcon(QIcon("image/start.ico")) self.setGeometry(100, 20, 940, 700) # self.changeTab() screen = QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2) self.btn_start.setMyarg('start') # print(self.btn_start.getMyarg()) self.connect(self.btn_start, SIGNAL("clicked()"), self.startChoice) # self.connect(self.w1title, SIGNAL("currentIndexChanged(int)"), self.changeTitle) # self.connect(self.btn_start2, SIGNAL("clicked()"), self.startChoice) # self.connect(self.w2title, SIGNAL("currentIndexChanged(int)"), self.changeTitle) self.btngroup.buttonClicked[int].connect(self.btns_click) # self.connect(self.btn_start, SIGNAL("myslot(PyQt_PyObject)"), self.myslot) # self.connect(self.btngroup, SIGNAL("buttonClicked(int)"), lambda:self.btns_click()) def myslot(self, text): # print(text, self.dict_choices) self.g_curbtn = text if self.g_curbtn not in self.dict_choices: self.btnSysMenu.setFocus() return # print(self.btngroup.button(int(self.g_curbtn)).parent()) # print(type(self.btngroup.button(int(self.g_curbtn)).parentWidget())) pos = self.btngroup.button(int(self.g_curbtn)).parent().mapToGlobal(self.btngroup.button(int(self.g_curbtn)).pos()) width = self.btngroup.button(int(self.g_curbtn)).rect().height() # print("-----", pos, width) pos.setY(pos.y()+width-5) indx = 0 for istate in self.dict_choices[self.g_curbtn]: if istate == '1': self.popMenu.actions()[indx].setEnabled(True) elif istate == '0': self.popMenu.actions()[indx].setEnabled(False) indx += 1 self.popMenu.exec_(pos) self.btnSysMenu.setFocus() # def on_context_menu(self, point): # print(point) # self.popMenu.exec_(self.button.mapToGlobal(point)) def btns_click(self, btnid): # curclassname = self.tabWidget.tabText(0) query = QSqlQuery(self.db) # cur = conn.cursor() today = datetime.date.today() self.g_curbtn = str(btnid).zfill(2) if self.g_curbtn not in self.dict_choices: self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_new) query.exec_("select count(*) from tmprecord where stusn='" + str(self.g_curbtn) + "'") query.next() if query.value(0) == 0: query.prepare("insert into tmprecord (classname, stusn, datequestion) values (:classname, :stusn, :datequestion)") query.bindValue(":classname", self.g_curClassName) query.bindValue(":stusn", self.g_curbtn) query.bindValue(":datequestion", today) query.exec_() self.dict_choices[self.g_curbtn] = "111" else: self.btngroup.button(int(self.g_curbtn)).setStyleSheet(stylesheetstr_old) self.btngroup.button(int(self.g_curbtn)).setIcon(QIcon()) query.exec_("delete from tmprecord where stusn='"+ str(self.g_curbtn) + "'") self.dict_choices.pop(self.g_curbtn) self.btnSysMenu.setFocus() def exportNotice(self): query = QSqlQuery(self.db) query.exec_("select stusn, stuname, classname, rightquestions, wrongquestions from student" ) lstInfo = [["学号","姓名", "班级", "回答正确次数", "回答错误次数"]] while(query.next()): lstInfo.append([query.value(0),query.value(1),query.value(2),query.value(3),query.value(4)]) from xlwt import Workbook,easyxf book = Workbook(encoding='ascii') # 'pattern: pattern solid, fore_colour white;' style = easyxf( 'font: height 280, name 黑体;' 'align: vertical center, horizontal center;' ) style2 = easyxf('font: height 260, name 仿宋_GB2312, bold True; align: vertical center, horizontal left;') style3 = easyxf('font: height 260, name 仿宋_GB2312, bold True; align: vertical center, horizontal left, wrap True;') sheet1 = book.add_sheet('学生提问情况汇总',cell_overwrite_ok=True) # sheet1.write(0,7,flagtxt, easyxf('font: height 200, name 黑体;align: vertical center, horizontal right;')) sheet1.write_merge(0,0,0,4, '学生提问情况汇总表',style) sheet1.row(0).height_mismatch = 1 sheet1.row(0).height = 5*256 sheet1.col(0).width = 10*256 sheet1.col(1).width = 25*256 sheet1.col(2).width = 25*256 sheet1.col(3).width = 20*256 sheet1.col(4).width = 20*256 tmprows = 1 for item in lstInfo: stusn = item[0] stuname = item[1] classname = item[2] rightquestions = item[3] wrongquestions = item[4] sheet1.write(tmprows,0,stusn, style2) sheet1.write(tmprows,1,stuname, style2) sheet1.write(tmprows,2,classname, style2) sheet1.write(tmprows,3,rightquestions, style2) sheet1.write(tmprows,4,wrongquestions, style2) tmprows += 1 # print(tmprows) sheet1.header_str = "".encode() sheet1.footer_str = "".encode() # book.save('d:/simple.xls') # print(QDir.home().dirName() , QDir.homePath ()) filename = QDir.homePath () + "\学生提问情况汇总表.xls" try: book.save(filename) except Exception as e: QMessageBox.warning(self, "写入错误", "错误号:"+str(e.errno)+"\n错误描述:"+e.strerror+"\n请关闭已经打开的%s文档!" % filename) QMessageBox.about (self, "导出成功", "请查看文档:%s" % filename) def aboutMe(self): strinfo = """本软件采用python3.4编写,界面采用qt4.8的python绑定。 \n版本所有:汕头市大华路第一小学赵小娜老师。 \n有任何问题请反馈至[email protected]。 """ QMessageBox.information(None, "关于", strinfo) def initStudent(self): query = QSqlQuery(self.db) ret = query.exec_("update student set wrongquestions=0") ret = query.exec_("update student set rightquestions=0") QMessageBox.information(None, "提示", "已清除所有学生的累计提问情况。") def deleteTmpdata(self): query = QSqlQuery(self.db) ret = query.exec_("delete from tmprecord where 1=1" ) if self.g_curClassName != "": QMessageBox.information(None, "提示", "已清除本次软件启动后的所有已提问过的学生。") def changeTab(self): # pass curtab = self.tabWidget.currentIndex() # print(curtab, "-") if curtab == 1: ## when click the second tab page ,then pass. return # cur = conn.cursor() query = QSqlQuery(self.db) ## if current classname is null, then set current tabpage display the first class of classtable if self.g_curClassName == "": ret = query.exec_("select classname from classtable") query.next() self.g_curClassName = query.value(0) self.tabWidget.setTabText(0, self.g_curClassName) # print(1) strwhere = " and classname like '" + self.g_curClassName + "' ORDER BY stusn" self.g_curbtn = "" self.dict_choices = {} self.studentSnlst = [] ## clearn the question data of temp record . ret= query.exec_("delete from tmprecord where 1=1") ret = query.exec_("select stusn, stuname from student where 1=1 " + strwhere) ## now update the global data "self.btngroup" for indx in range(0, 56): self.btngroup.button(indx+1).setText("") self.btngroup.button(indx+1).setMyarg(None) self.btngroup.button(indx+1).setStyleSheet(stylesheetstr_old) self.btngroup.button(indx+1).setIcon(QIcon()) self.btngroup.button(indx+1).setEnabled(False) self.studentSnlst.append([indx+1,]) inum = 0 while (query.next()): inum += 1 self.btngroup.button(inum).setText(query.value(1)) self.btngroup.button(inum).setMyarg(query.value(0)) self.btngroup.button(inum).setStyleSheet(stylesheetstr_old) self.btngroup.button(inum).setIcon(QIcon()) self.btngroup.button(inum).setEnabled(True) # print(inum, len(self.btngroup.buttons())) self.group_animation = groupAnimation(self.studentSnlst, self.btngroup) def mousePressEvent(self, event): # print('a') if event.button() == Qt.RightButton: QDialog.mousePressEvent(self,event) return # print(event.sender(), event.button()) self.offset = event.pos() # print(self.offset) def mouseMoveEvent(self, event): # print('sss') if hasattr(self, 'offset'): x=event.globalX() y=event.globalY() x_w = self.offset.x() y_w = self.offset.y() self.move(x-x_w, y-y_w) else: pass #######======= studentModel ============############### def newStudent(self): # Calc the missing number: row = self.StudentModel.rowCount() if row > 0: oldNumList = [] for i in range(0, row): oldNumList.append(int(self.StudentModel.index(i,2).data())) allNumberList = list(range(1, oldNumList[-1]+1)) for i in range(0, allNumberList[-1]): if oldNumList[i] != allNumberList[i]: missingNum = allNumberList[i] break if len(oldNumList) == len(allNumberList): missingNum = allNumberList[i] +1 else: missingNum = 1 self.StudentModel.insertRow(row) self.StudentView.scrollToBottom() self.StudentModel.setData(self.StudentModel.index(row, 1), self.g_curClassName) self.StudentModel.setData(self.StudentModel.index(row, 2), str(missingNum).zfill(2)) self.StudentModel.setData(self.StudentModel.index(row, 4), 0) self.StudentModel.setData(self.StudentModel.index(row, 5), 0) def removeStudent(self): index = self.StudentView.currentIndex() row = index.row() if QMessageBox.question(self, "删除确认", "是否要删除当前选中记录?", "确定", "取消") == 0: self.StudentModel.removeRows(row, 1) self.StudentModel.submitAll() self.StudentModel.database().commit() def revertStudent(self): self.StudentModel.revertAll() self.StudentModel.database().rollback() def saveStudent(self): self.StudentModel.database().transaction() if self.StudentModel.submitAll(): self.StudentModel.database().commit() # print("save success! ->commit") else: self.StudentModel.revertAll() self.StudentModel.database().rollback() #######======= classModel ============############### def newClass(self): row = self.ClassnameModel.rowCount() self.ClassnameModel.insertRow(row) def removeClass(self): index = self.ClassnameView.currentIndex() row = index.row() curClassname = index.sibling(index.row(),0).data() strwhere = "classname like '" + curClassname + "'" self.StudentModel.setFilter(strwhere) self.StudentModel.select() # print(self.StudentModel.rowCount(), "----", ) if QMessageBox.question(self, "删除确认", "删除班级意味着会删除本班所有人员信息。是否要删除当前选中记录?", "确定", "取消") == 0: self.ClassnameModel.removeRows(row, 1) self.ClassnameModel.submitAll() self.ClassnameModel.database().commit() self.StudentModel.removeRows(0, self.StudentModel.rowCount()) self.StudentModel.submitAll() self.StudentModel.database().commit() def revertClass(self): self.ClassnameModel.revertAll() self.ClassnameModel.database().rollback() def saveClass(self): query = QSqlQuery(self.db) # record the old class name lstOldClassName = {} lstOldClassid = [] query.exec_("select rowid, classname from classtable" ) while(query.next()): lstOldClassName[query.value(0)] = query.value(1) lstOldClassid.append(query.value(0)) # print(lstOldClassName) # Update the class Table self.ClassnameModel.database().transaction() if self.ClassnameModel.submitAll(): self.ClassnameModel.database().commit() # print("save success! ->commit") else: QMessageBox.warning(None, "错误", "请检查班级中名称,不能出现同名班级!") self.ClassnameModel.revertAll() self.ClassnameModel.database().rollback() # print(lstOldClassid) lstNewClassName = {} query.exec_("select rowid, classname from classtable where rowid in " + str(tuple(lstOldClassid)) ) while(query.next()): lstNewClassName[query.value(0)] = query.value(1) # print(lstOldClassName, '=========') # print(lstNewClassName, '~~~~~~~~~') for i in lstOldClassName: oldclassname = lstOldClassName[i] newclassname = lstNewClassName[i] if oldclassname != newclassname: # print(oldclassname, newclassname, '++++++++') # print("update student set classname=" + newclassname + " where classname='" + oldclassname + "'") query.exec_("update student set classname='" + newclassname + "' where classname='" + oldclassname + "'") self.StudentModel.setFilter("classname = '" + newclassname + "'") self.StudentModel.select() lstClassName = [] query.exec_("select classname from classtable" ) while(query.next()): lstClassName.append(query.value(0)) self.StudentView.setItemDelegateForColumn(1, ComboBoxDelegate(self, lstClassName, self.db)) def dbclick(self, indx): if type(indx.sibling(indx.row(),0).data()) != QPyNullVariant: classname = indx.sibling(indx.row(),0).data() strwhere = "classname like '" + classname + "'" self.StudentModel.setFilter(strwhere) self.StudentModel.setSort(2, Qt.AscendingOrder) self.StudentModel.select() self.g_curClassName = classname self.tabWidget.setTabText(0, self.g_curClassName) def dbclick2(self, indx): if indx.column() == 2: self.StudentView.setEditTriggers(QAbstractItemView.NoEditTriggers) else: self.StudentView.setEditTriggers(QAbstractItemView.DoubleClicked) def genTwoTab(self, tabtitle=""): # Create the tab title sytle. tabtitle = QLabel() tabtitle.setFont(QFont('Courier New', 20)) tabtitle.setText("班级学生信息管理") tabtitle.setStyleSheet("border: 1px solid blue; color:rgba(0,0,255, 220);\ background-color:rgba(201,201,201,60);\ border-radius: 6px; \ padding: 1px 18px 1px 20px;\ min-width: 8em;") tabtitle.setMinimumHeight(50); titleLayout = QHBoxLayout() titleLayout.addWidget(tabtitle) titleLayout.setAlignment(tabtitle, Qt.AlignCenter) # Create the classnameView self.ClassnameView = QTableView() self.ClassnameModel = QSqlTableModel(self.ClassnameView) self.ClassnameModel.setTable("classtable") # self.ClassnameModel.setRelation(2, QSqlRelation("mentalmodel", "id", "name")); self.ClassnameModel.setEditStrategy(QSqlTableModel.OnManualSubmit) self.ClassnameModel.select() self.ClassnameModel.setHeaderData(0, Qt.Horizontal, "班级名称") # for indx, iheader in enumerate(["classid", "classname"]): # self.ClassnameModel.setHeaderData(indx+1, Qt.Horizontal, iheader) self.ClassnameView.setModel(self.ClassnameModel) # self.ClassnameView.setColumnHidden(0, True) # self.ClassnameView.show() self.ClassnameView.verticalHeader().setFixedWidth(30) self.ClassnameView.verticalHeader().setStyleSheet("color: red;font-size:20px; "); self.ClassnameView.setStyleSheet("QTableView{background-color: rgb(250, 250, 200, 0);" "alternate-background-color: rgb(141, 163, 0);}" "QTableView::item:hover {background-color: rgba(100,200,220,100);} ") self.ClassnameView.setStyleSheet("font-size:16px; "); self.ClassnameView.setSelectionMode(QAbstractItemView.SingleSelection) # self.ClassnameView.dataChanged.connect(self.dataChanged) # self.ClassnameView.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # the second list self.StudentView = QTableView() self.StudentModel = QSqlTableModel(self.StudentView) self.StudentModel.setTable("student") # self.StudentModel.setRelation(2, QSqlRelation("mentalmodel", "id", "name")); self.StudentModel.setEditStrategy(QSqlTableModel.OnManualSubmit) # self.StudentModel.select() query = QSqlQuery(self.db) strwhere = " 1=1 " if self.g_curClassName == "": ret = query.exec_("select classname from classtable") query.next() firstClassName = query.value(0) strwhere += " and classname like '" + firstClassName + "'" self.StudentModel.setFilter(strwhere) self.StudentModel.select() for indx, iheader in enumerate(["班级名称", "学生编号", "学生姓名", "答对次数", "答错次数"]): self.StudentModel.setHeaderData(indx+1, Qt.Horizontal, iheader) self.StudentView.setModel(self.StudentModel) self.StudentView.setColumnHidden(0, True) # query = QSqlQuery(self.db) lstClassName = [] query.exec_("select classname from classtable" ) while(query.next()): lstClassName.append(query.value(0)) self.StudentView.setItemDelegateForColumn(1, ComboBoxDelegate(self, lstClassName, self.db)) # self.StudentView.show() self.StudentView.verticalHeader().setFixedWidth(30) self.StudentView.verticalHeader().setStyleSheet("color: red;font-size:20px; background-color: rgb(250, 250, 200, 100)"); self.StudentView.setStyleSheet("QTableView{background-color: rgb(250, 250, 200, 0);" "alternate-background-color: rgb(141, 163, 250);}" "QTableView::item:hover {background-color: rgba(10,200,100,200);} " ) self.StudentView.setStyleSheet("font-size:16px;") self.StudentView.setSelectionMode(QAbstractItemView.SingleSelection) self.StudentView.doubleClicked.connect(self.dbclick2) btn_lst1_layout = QGridLayout() newusrbtn = QPushButton("新增") savebtn = QPushButton("保存") revertbtn = QPushButton("撤销") removebtn = QPushButton("删除") btn_lst1_layout.addWidget(newusrbtn, 0, 0) btn_lst1_layout.addWidget(savebtn, 0, 1) btn_lst1_layout.addWidget(revertbtn, 1, 0) btn_lst1_layout.addWidget(removebtn, 1, 1) newusrbtn.clicked.connect(self.newClass) savebtn.clicked.connect(self.saveClass) revertbtn.clicked.connect(self.revertClass) removebtn.clicked.connect(self.removeClass) self.ClassnameView.doubleClicked.connect(self.dbclick) btnbox2 = QDialogButtonBox(Qt.Horizontal) newusrbtn2 = QPushButton("新增") savebtn2 = QPushButton("保存") revertbtn2 = QPushButton("撤销") removebtn2 = QPushButton("删除") btnbox2.addButton(newusrbtn2, QDialogButtonBox.ActionRole); btnbox2.addButton(savebtn2, QDialogButtonBox.ActionRole); btnbox2.addButton(revertbtn2, QDialogButtonBox.ActionRole); btnbox2.addButton(removebtn2, QDialogButtonBox.ActionRole); newusrbtn2.clicked.connect(self.newStudent) savebtn2.clicked.connect(self.saveStudent) revertbtn2.clicked.connect(self.revertStudent) removebtn2.clicked.connect(self.removeStudent) # left list layout lst_layout_1 = QVBoxLayout() lst_layout_1.addWidget(self.ClassnameView) lst_layout_1.addLayout(btn_lst1_layout) lst_layout_2 = QVBoxLayout() lst_layout_2.addWidget(self.StudentView) lst_layout_2.addWidget(btnbox2) lstlayout = QHBoxLayout() lstlayout.setMargin(5) # lstlayout.addLayout(findbox) lstlayout.addLayout(lst_layout_1, 2) lstlayout.setMargin(5) lstlayout.addLayout(lst_layout_2, 5) labelClass = QLabel("") labelClass.setStyleSheet("background-color:rgba(255, 255, 255,0); color:rgba(0,0,0,0);") labelClass.setFixedHeight(40) # labelClass.setFixedWidth(100) # labelClass.setFont(QFont('宋体', 10)) bottomlayout = QHBoxLayout() bottomlayout.addWidget(labelClass) tab2layout = QVBoxLayout() tab2layout.addLayout(titleLayout) tab2layout.addLayout(lstlayout) tab2layout.addLayout(bottomlayout) self.w2.setLayout(tab2layout) self.w2.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);") def genOneTab(self): tabtitle = QLabel() # tabtitle.setFixedHeight(40) # tabtitle.setFixedWidth(160) self.btn_start = MyButton("开始") self.choicenum_text = QComboBox() self.choicenum_text.setObjectName('w1combonums') # self.w1title.setStyleSheet("background-image:url('image/panelbg.jpg');") # Set the title style tabtitle.setFont(QFont('Courier New', 20)) tabtitle.setText("随堂提问演板") tabtitle.setStyleSheet("border: 1px solid blue; color:rgba(0,0,255, 220);\ background-color:rgba(201,201,201,60);\ border-radius: 6px; \ padding: 1px 18px 1px 20px;\ min-width: 8em;") tabtitle.setMinimumHeight(50); titleLayout = QHBoxLayout() titleLayout.addWidget(tabtitle) titleLayout.setAlignment(tabtitle, Qt.AlignCenter) btnlayout = QGridLayout() tmpnum = 0 for inum in range(0,56): irow = tmpnum // g_cols icol = tmpnum % g_cols tmpnum += 1 btnlayout.setRowMinimumHeight(irow, 80) tmpbtn = MyButton("") tmpbtn.setMyarg(None) # tmpbtn.setFixedHeight(20) tmpbtn.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding)) tmpbtn.setStyleSheet("border: 1px solid rgb(55,55,255,100);background-color: rgba(255,255,255,20);font-size:16px;") self.connect(tmpbtn, SIGNAL("myslot(PyQt_PyObject)"), self.myslot) tmpbtn.setAutoDefault(False) self.btngroup.addButton(tmpbtn, inum+1) # stusn is from 1 start btnlayout.addWidget(tmpbtn, irow, icol) self.btn_start.setIcon(QIcon("image/start.png")) self.btn_start.setStyleSheet("border: 1px solid yellow;") self.btn_start.setFixedHeight(40) self.btn_start.setFixedWidth(100) self.btn_start.setFont(QFont('宋体', 18)) # self.choicenum_text.setFixedHeight(45) # self.choicenum_text.setFixedWidth(60) ## Set the combox number style self.choicenum_text.setFont(QFont('Courier New', 20)) self.choicenum_text.setFixedHeight(45) self.choicenum_text.setStyleSheet("border: 2px solid blue; color:red;font-weight:light;font-size:26px;\ border-radius: 6px; \ min-width: 2em; ") self.choicenum_text.setEditable(True) self.choicenum_text.lineEdit().setReadOnly(True); self.choicenum_text.lineEdit().setAlignment(Qt.AlignCenter); model = self.choicenum_text.model() for row in list(range(1, 7)): item = QStandardItem(str(row)) item.setTextAlignment(Qt.AlignCenter) item.setForeground(QColor('red')) item.setBackground(QColor(0,200,50, 130)) model.appendRow(item) self.choicenum_text.setCurrentIndex(2) # self.choicenum_text.setStyleSheet ("QComboBox::drop-down {border-width: 100px;}") # self.choicenum_text.setStyleSheet ("QComboBox::down-arrow {image: url(image/downarrow.png);top: 10px;left: 1px;}") bottomlayout = QHBoxLayout() bottomlayout.setSizeConstraint(QLayout.SetFixedSize) bottomlayout.addStretch(10) bottomlayout.addWidget(self.btn_start) bottomlayout.setSpacing(5) bottomlayout.addWidget(self.choicenum_text) tab1layout = QVBoxLayout() tab1layout.addLayout(titleLayout) tab1layout.addLayout(btnlayout) tab1layout.addLayout(bottomlayout) self.w1.setLayout(tab1layout) self.w1.setStyleSheet("background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #ffffff, stop: 1 #228888);") def startChoice(self, usernum="", oldbtn=""): # print(oldbtn, 1) if oldbtn == "": self.dict_choices = {} strwhere = " and classname like '" + self.g_curClassName + "'" allstudent = [] lstrecord = [] query = QSqlQuery(self.db) query.exec_("select stusn from tmprecord where 1=1 " + strwhere) while(query.next()): lstrecord.append(query.value(0)) # print(lstrecord, 'record', "select stusn from student where stusn not in " + str(tuple(lstrecord))) query.exec_("select stusn from student where stusn not in " + str(tuple(lstrecord)) + strwhere) while(query.next()): allstudent.append(query.value(0)) if usernum == "": nums = int(self.choicenum_text.currentText()) else: nums = usernum if nums >= len(allstudent): query.exec_("delete from tmprecord where 1=1 " + strwhere) #delete tmp date no today allstudent = [] query.exec_("select stusn from student where 1=1 " + strwhere) while(query.next()): allstudent.append(query.value(0)) if oldbtn == "": random.seed() lstchoices = random.sample(allstudent, nums) for ibtn in lstchoices: self.dict_choices[ibtn] = "111" self.group_animation.start() QTimer.singleShot(1200, self.stopmovie) else: random.seed() otherbtn = random.sample(allstudent, 1)[0] # self.btngroup.button(int(otherbtn)).setFocus() self.dict_choices.pop(oldbtn) self.dict_choices[otherbtn] = '111' self.stopmovie() self.btnSysMenu.setFocus() def stopmovie(self): self.group_animation.stop() for isn in self.studentSnlst: # print(isn) self.btngroup.button(int(isn[0])).setStyleSheet(stylesheetstr_old) self.btngroup.button(int(isn[0])).setIcon(QIcon()) classname = self.tabWidget.tabText(0) query = QSqlQuery(self.db) today = datetime.date.today() for ibtn in self.dict_choices: self.btngroup.button(int(ibtn)).setStyleSheet(stylesheetstr_new) query.exec_("select count(*) from tmprecord where stusn='" + str(ibtn) + "'") query.next() if query.value(0) == 0: query.prepare("insert into tmprecord (classname, stusn, datequestion) values (:classname, :stusn, :datequestion)") query.bindValue(":classname", classname) query.bindValue(":stusn", ibtn) query.bindValue(":datequestion", today) query.exec_() def answerRight(self): # print(self.g_curbtn) value = self.g_curbtn if value not in self.dict_choices: return self.btngroup.button(int(value)).setIcon(QIcon("image/smile.png")) self.btngroup.button(int(value)).setIconSize(QSize(20,20)) query = QSqlQuery(self.db) query.exec_("select rightquestions from student where stusn='" + value + "'") query.next() studentRightQuestions = query.value(0) + 1 query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'") ########### if self.dict_choices[value] == "101": query.exec_("select wrongquestions from student where stusn='" + value + "'") query.next() studentWrongQuestions = query.value(0) - 1 query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'") self.dict_choices[value] = "011" def answerWrong(self): value = self.g_curbtn if value not in self.dict_choices: return self.btngroup.button(int(value)).setIcon(QIcon("image/cry.png")) self.btngroup.button(int(value)).setIconSize(QSize(20,20)) # self.btngroup.button(int(value)).setStyleSheet("border-image: url(image/ex_stu.png);") query = QSqlQuery(self.db) query.exec_("select wrongquestions from student where stusn='" + value + "'") query.next() studentWrongQuestions = query.value(0) + 1 query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'") if self.dict_choices[value] == "011": query.exec_("select rightquestions from student where stusn='" + value + "'") query.next() studentRightQuestions = query.value(0) - 1 query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'") self.dict_choices[value] = "101" def resetStudent(self): value = self.g_curbtn if value not in self.dict_choices: return query = QSqlQuery(self.db) if self.dict_choices[value] == "011": query.exec_("select rightquestions from student where stusn='" + value + "'") query.next() studentRightQuestions = query.value(0) - 1 query.exec_("update student set rightquestions=" + str(studentRightQuestions) + " where stusn='" + value + "'") if self.dict_choices[value] == "101": query.exec_("select wrongquestions from student where stusn='" + value + "'") query.next() studentWrongQuestions = query.value(0) - 1 query.exec_("update student set wrongquestions=" + str(studentWrongQuestions) + " where stusn='" + value + "'") self.startChoice(usernum=1, oldbtn=value) # print("---reset___") # curmenu.actions()[0].setEnabled(True) # curmenu.actions()[1].setEnabled(True) # self.choiceOneStudent(value) def createDb(self): conn = sqlite3.connect("studentNew.db") cur = conn.cursor() sqlstr = 'create table student (id integer primary key, \ classname varchar(20), \ stusn varchar(20), \ stuname varchar(20), \ rightquestions integer, \ wrongquestions integer, \ FOREIGN KEY(classname) REFERENCES classtable(classname))' # print(sqlstr) sqlstr2 = 'create table tmprecord (id integer primary key, \ classname varchar(20), \ stusn varchar(20), \ datequestion date)' sqlstr3 = 'create table classtable (classname varchar(20) PRIMARY KEY)' cur.execute(sqlstr3) conn.commit() cur.execute(sqlstr2) conn.commit() cur.execute(sqlstr) conn.commit() strdelete = "delete from student where 1=1" cur.execute(strdelete) conn.commit() strdelete = "delete from tmprecord where 1=1" cur.execute(strdelete) conn.commit() # print(sqlstr2) # cur.execute(sqlstr) # conn.commit() # cur.execute(sqlstr2) # conn.commit() # insert example data strsql = "insert into classtable values (?)" cur.execute(strsql, ("三(3)班",)) conn.commit() cur.execute(strsql, ("三(4)班",)) conn.commit() a03lst = ["曾忆谊","赵佳泉","翁文秀","林珑","郑铭洁","林泽思","吴崇霖","陈思嘉","欧阳月孜","郭展羽","詹伟哲","黄佳仪","杨秋霞","周奕子","林楚杰","欧伊涵","许腾誉","陈唯凯","陈树凯","林彦君","张钰佳","高锴","杨博凯","林妙菲","林楚鸿","陈展烯","姚静茵","吴欣桐","范思杰","肖佳","马思广","许一帆","姚奕帆","陈海珣","吴黛莹","吴育桐","肖凯帆","林欣阳","叶茂霖","姚楷臻","陈嘉豪","陈琦","杨子楷","陈炎宏","陈幸仪","杨景畅","罗暖婷","郑馨"] a04lst = ["罗恩琪","王可","曾祥威","谢濡婷","温嘉凯","许洁仪","肖欣淇","陈凯佳","林天倩","李乐海","吴文慧","黄文婷","万誉","陈进盛","张裕涵","陈振嘉","王巧玲","林珮琪","陈炜楷","杨健","赵泽锴","张凤临","蔡子丹","陈烨杰","廖妍希","林树超","夏培轩","陈锦森","李星","蔡依婷","姚容创","姚凯扬","沈嘉克","周凡","张玉川","邱金迅","陈菲敏","陈星翰","朱煜楷","郑泽洪","钱剑非","罗奕丰","陈杜炜","林知钦"] strsql = "insert into student values (?, ?, ?, ?,?,?)" for i in list(range(0,len(a03lst))): cur.execute(strsql, (None, "三(3)班", str(i+1).zfill(2), a03lst[i], 0, 0)) conn.commit() strsql = "insert into student values (?, ?, ?, ?,?,?)" for i in list(range(0,len(a04lst))): cur.execute(strsql, (None, "三(4)班", str(i+1).zfill(2), a04lst[i], 0, 0)) conn.commit() cur.close()
class TablaturePart(_base.Part): """Base class for tablature instrument part types.""" octave = 0 clef = None transposition = None tunings = () # may contain a list of tunings. tabFormat = "" # can contain a tablatureFormat value. def createWidgets(self, layout): self.staffTypeLabel = QLabel() self.staffType = QComboBox() self.staffTypeLabel.setBuddy(self.staffType) self.staffType.setModel(listmodel.ListModel(tablatureStaffTypes, self.staffType, display=listmodel.translate)) box = QHBoxLayout() layout.addLayout(box) box.addWidget(self.staffTypeLabel) box.addWidget(self.staffType) if self.tunings: self.createTuningWidgets(layout) self.staffType.activated.connect(self.slotTabEnable) self.slotTabEnable(0) def createTuningWidgets(self, layout): self.tuningLabel = QLabel() self.tuning = QComboBox() self.tuningLabel.setBuddy(self.tuning) tunings = [("", lambda: _("Default"))] tunings.extend(self.tunings) self.tuning.setModel(listmodel.ListModel(tunings, self.tuning, display=listmodel.translate_index(1))) self.tuning.setCurrentIndex(1) box = QHBoxLayout() layout.addLayout(box) box.addWidget(self.tuningLabel) box.addWidget(self.tuning) def translateWidgets(self): self.staffTypeLabel.setText(_("Staff type:")) self.staffType.model().update() if self.tunings: self.translateTuningWidgets() def translateTuningWidgets(self): self.tuningLabel.setText(_("Tuning:")) self.tuning.model().update() def slotTabEnable(self, enable): """Called when the user changes the staff type. Non-zero if the user wants a TabStaff. """ self.tuning.setEnabled(bool(enable)) def voiceCount(self): """Returns the number of voices. Inherit to make this user-settable. """ return 1 def build(self, data, builder): # First make assignments for the voices we want to create numVoices = self.voiceCount() if numVoices == 1: voices = (ly.util.mkid(data.name()),) elif numVoices == 2: order = 1, 2 voices = "upper", "lower" elif numVoices == 3: order = 1, 3, 2 voices = "upper", "middle", "lower" else: order = 1, 2, 3, 4 voices = [ly.util.mkid(data.name(), "voice") + ly.util.int2text(i) for i in order] assignments = [data.assignMusic(name, self.octave, self.transposition) for name in voices] staffType = self.staffType.currentIndex() if staffType in (0, 2): # create a normal staff staff = ly.dom.Staff() seq = ly.dom.Seqr(staff) if self.clef: ly.dom.Clef(self.clef, seq) mus = ly.dom.Simr(seq) for a in assignments[:-1]: ly.dom.Identifier(a.name, mus) ly.dom.VoiceSeparator(mus) ly.dom.Identifier(assignments[-1].name, mus) builder.setMidiInstrument(staff, self.midiInstrument) if staffType in (1, 2): # create a tab staff tabstaff = ly.dom.TabStaff() if self.tabFormat: tabstaff.getWith()["tablatureFormat"] = ly.dom.Scheme(self.tabFormat) self.setTunings(tabstaff) sim = ly.dom.Simr(tabstaff) if numVoices == 1: ly.dom.Identifier(assignments[0].name, sim) else: for num, a in zip(order, assignments): s = ly.dom.Seq(ly.dom.TabVoice(parent=sim)) ly.dom.Text("\\voice" + ly.util.int2text(num), s) ly.dom.Identifier(a.name, s) if staffType == 0: # only a normal staff p = staff elif staffType == 1: # only a TabStaff builder.setMidiInstrument(tabstaff, self.midiInstrument) p = tabstaff else: # both TabStaff and normal staff p = ly.dom.StaffGroup() s = ly.dom.Sim(p) s.append(staff) s.append(tabstaff) builder.setInstrumentNamesFromPart(p, self, data) data.nodes.append(p) def setTunings(self, tab): if self.tunings and self.tuning.currentIndex() > 0: tuning = self.tunings[self.tuning.currentIndex() - 1][0] tab.getWith()["stringTunings"] = ly.dom.Scheme(tuning)
class InstrumentNames(QGroupBox): def __init__(self, parent): super(InstrumentNames, self).__init__(parent, checkable=True, checked=True) grid = QGridLayout() self.setLayout(grid) self.firstSystemLabel = QLabel() self.firstSystem = QComboBox() self.firstSystemLabel.setBuddy(self.firstSystem) self.otherSystemsLabel = QLabel() self.otherSystems = QComboBox() self.otherSystemsLabel.setBuddy(self.otherSystems) self.languageLabel = QLabel() self.language = QComboBox() self.languageLabel.setBuddy(self.language) self.firstSystem.setModel(listmodel.ListModel( (lambda: _("Long"), lambda: _("Short")), self.firstSystem, display = listmodel.translate)) self.otherSystems.setModel(listmodel.ListModel( (lambda: _("Long"), lambda: _("Short"), lambda: _("None")), self.otherSystems, display = listmodel.translate)) self._langs = l = ['','C'] l.extend(sorted(po.available())) def display(lang): if lang == 'C': return _("English (untranslated)") elif not lang: return _("Default") return language_names.languageName(lang, po.setup.current()) self.language.setModel(listmodel.ListModel(l, self.language, display=display)) grid.addWidget(self.firstSystemLabel, 0, 0) grid.addWidget(self.firstSystem, 0, 1) grid.addWidget(self.otherSystemsLabel, 1, 0) grid.addWidget(self.otherSystems, 1, 1) grid.addWidget(self.languageLabel, 2, 0) grid.addWidget(self.language, 2, 1) app.translateUI(self) self.loadSettings() self.window().finished.connect(self.saveSettings) def translateUI(self): self.setTitle(_("Instrument names")) self.firstSystemLabel.setText(_("First system:")) self.otherSystemsLabel.setText(_("Other systems:")) self.languageLabel.setText(_("Language:")) self.firstSystem.setToolTip(_( "Use long or short instrument names before the first system.")) self.otherSystems.setToolTip(_( "Use short, long or no instrument names before the next systems.")) self.language.setToolTip(_( "Which language to use for the instrument names.")) self.firstSystem.model().update() self.otherSystems.model().update() self.language.model().update() def getLanguage(self): """Returns the language the user has set. '' means: default (use same translation as system) 'C' means: English (untranslated) or a language code that is available in Frescobaldi's translation. """ return self._langs[self.language.currentIndex()] def loadSettings(self): s = QSettings() s.beginGroup('scorewiz/instrumentnames') self.setChecked(s.value('enabled', True, bool)) allow = ['long', 'short'] first = s.value('first', '', type("")) self.firstSystem.setCurrentIndex(allow.index(first) if first in allow else 0) allow = ['long', 'short', 'none'] other = s.value('other', '', type("")) self.otherSystems.setCurrentIndex(allow.index(other) if other in allow else 2) language = s.value('language', '', type("")) self.language.setCurrentIndex(self._langs.index(language) if language in self._langs else 0) def saveSettings(self): s = QSettings() s.beginGroup('scorewiz/instrumentnames') s.setValue('enable', self.isChecked()) s.setValue('first', ('long', 'short')[self.firstSystem.currentIndex()]) s.setValue('other', ('long', 'short', 'none')[self.otherSystems.currentIndex()]) s.setValue('language', self._langs[self.language.currentIndex()])
class Choir(VocalPart): @staticmethod def title(_=_base.translate): return _("Choir") def createWidgets(self, layout): self.label = QLabel(wordWrap=True) self.voicingLabel = QLabel() self.voicing = QComboBox(editable=True) self.voicingLabel.setBuddy(self.voicing) self.voicing.setCompleter(None) self.voicing.setValidator(QRegExpValidator( QRegExp("[SATB]+(-[SATB]+)*", Qt.CaseInsensitive), self.voicing)) self.voicing.addItems(( 'SA-TB', 'S-A-T-B', 'SA', 'S-A', 'SS-A', 'S-S-A', 'TB', 'T-B', 'TT-B', 'T-T-B', 'SS-A-T-B', 'S-A-TT-B', 'SS-A-TT-B', 'S-S-A-T-T-B', 'S-S-A-A-T-T-B-B', )) self.lyricsLabel = QLabel() self.lyrics = QComboBox() self.lyricsLabel.setBuddy(self.lyrics) self.lyrics.setModel(listmodel.ListModel(lyricStyles, self.lyrics, display=listmodel.translate_index(0), tooltip=listmodel.translate_index(1))) self.lyrics.setCurrentIndex(0) self.pianoReduction = QCheckBox() self.rehearsalMidi = QCheckBox() layout.addWidget(self.label) box = QHBoxLayout() layout.addLayout(box) box.addWidget(self.voicingLabel) box.addWidget(self.voicing) self.createStanzaWidget(layout) box = QHBoxLayout() layout.addLayout(box) box.addWidget(self.lyricsLabel) box.addWidget(self.lyrics) self.createAmbitusWidget(layout) layout.addWidget(self.pianoReduction) layout.addWidget(self.rehearsalMidi) def translateWidgets(self): self.translateStanzaWidget() self.translateAmbitusWidget() self.lyrics.model().update() self.label.setText('<p>{0} <i>({1})</i></p>'.format( _("Please select the voices for the choir. " "Use the letters S, A, T, or B. A hyphen denotes a new staff."), _("Hint: For a double choir you can use two choir parts."))) self.voicingLabel.setText(_("Voicing:")) self.lyricsLabel.setText(_("Lyrics:")) self.pianoReduction.setText(_("Piano reduction")) self.pianoReduction.setToolTip(_( "Adds an automatically generated piano reduction.")) self.rehearsalMidi.setText(_("Rehearsal MIDI files")) self.rehearsalMidi.setToolTip(_( "Creates a rehearsal MIDI file for every voice, " "even if no MIDI output is generated for the main score.")) def build(self, data, builder): # normalize voicing staves = self.voicing.currentText().upper() # remove unwanted characters staves = re.sub(r'[^SATB-]+', '', staves) # remove double hyphens, and from begin and end staves = re.sub('-+', '-', staves).strip('-') if not staves: return splitStaves = staves.split('-') numStaves = len(splitStaves) staffCIDs = collections.defaultdict(int) # number same-name staff Context-IDs voiceCounter = collections.defaultdict(int) # dict to number same voice types maxNumVoices = max(map(len, splitStaves)) # largest number of voices numStanzas = self.stanzas.value() lyrics = collections.defaultdict(list) # lyrics grouped by stanza number pianoReduction = collections.defaultdict(list) rehearsalMidis = [] p = ly.dom.ChoirStaff() choir = ly.dom.Sim(p) data.nodes.append(p) # print main instrumentName if there are more choirs, and we # have more than one staff. if numStaves > 1 and data.num: builder.setInstrumentNames(p, builder.instrumentName(lambda _: _("Choir"), data.num), builder.instrumentName(lambda _: _("abbreviation for Choir", "Ch."), data.num)) # get the preferred way of adding lyrics lyrAllSame, lyrEachSame, lyrEachDiff, lyrSpread = ( self.lyrics.currentIndex() == i for i in range(4)) lyrEach = lyrEachSame or lyrEachDiff # stanzas to print (0 = don't print stanza number): if numStanzas == 1: allStanzas = [0] else: allStanzas = list(range(1, numStanzas + 1)) # Which stanzas to print where: if lyrSpread and numStanzas > 1 and numStaves > 2: spaces = numStaves - 1 count, rest = divmod(max(numStanzas, spaces), spaces) stanzaSource = itertools.cycle(allStanzas) stanzaGroups = (itertools.islice(stanzaSource, num) for num in itertools.chain( itertools.repeat(count + 1, rest), itertools.repeat(count, numStaves - rest))) else: stanzaGroups = itertools.repeat(allStanzas, numStaves) # a function to set staff affinity (in LilyPond 2.13.4 and above): if builder.lyVersion >= (2, 13, 4): def setStaffAffinity(context, affinity): ly.dom.Line("\\override VerticalAxisGroup " "#'staff-affinity = #" + affinity, context.getWith()) else: def setStaffAffinity(lyricsContext, affinity): pass # a function to make a column markup: if builder.lyVersion >= (2, 11, 57): columnCommand = 'center-column' else: columnCommand = 'center-align' def makeColumnMarkup(names): node = ly.dom.Markup() column = ly.dom.MarkupEnclosed(columnCommand, node) for name in names: ly.dom.QuotedString(name, column) return node stavesLeft = numStaves for staff, stanzas in zip(splitStaves, stanzaGroups): # are we in the last staff? stavesLeft -= 1 # the number of voices in this staff numVoices = len(staff) # sort the letters in order SATB staff = ''.join(i * staff.count(i) for i in 'SATB') # Create the staff for the voices s = ly.dom.Staff(parent=choir) builder.setMidiInstrument(s, self.midiInstrument) # Build a list of the voices in this staff. # Each entry is a tuple(name, num). # name is one of 'S', 'A', 'T', or 'B' # num is an integer: 0 when a voice occurs only once, or >= 1 when # there are more voices of the same type (e.g. Soprano I and II) voices = [] for voice in staff: if staves.count(voice) > 1: voiceCounter[voice] += 1 voices.append((voice, voiceCounter[voice])) # Add the instrument names to the staff: if numVoices == 1: voice, num = voices[0] longName = builder.instrumentName(voice2Voice[voice].title, num) shortName = builder.instrumentName(voice2Voice[voice].short, num) builder.setInstrumentNames(s, longName, shortName) else: # stack instrument names (long and short) in a markup column. # long names longNames = makeColumnMarkup( builder.instrumentName(voice2Voice[voice].title, num) for voice, num in voices) shortNames = makeColumnMarkup( builder.instrumentName(voice2Voice[voice].short, num) for voice, num in voices) builder.setInstrumentNames(s, longNames, shortNames) # Make the { } or << >> holder for this staff's children. # If *all* staves have only one voice, addlyrics is used. # In that case, don't remove the braces. staffMusic = (ly.dom.Seq if lyrEach and maxNumVoices == 1 else ly.dom.Seqr if numVoices == 1 else ly.dom.Simr)(s) # Set the clef for this staff: if 'B' in staff: ly.dom.Clef('bass', staffMusic) elif 'T' in staff: ly.dom.Clef('treble_8', staffMusic) # Determine voice order (\voiceOne, \voiceTwo etc.) if numVoices == 1: order = (0,) elif numVoices == 2: order = 1, 2 elif staff in ('SSA', 'TTB'): order = 1, 3, 2 elif staff in ('SAA', 'TBB'): order = 1, 2, 4 elif staff in ('SSAA', 'TTBB'): order = 1, 3, 2, 4 else: order = range(1, numVoices + 1) # What name would the staff get if we need to refer to it? # If a name (like 's' or 'sa') is already in use in this part, # just add a number ('ss2' or 'sa2', etc.) staffCIDs[staff] += 1 cid = ly.dom.Reference(staff.lower() + str(staffCIDs[staff] if staffCIDs[staff] > 1 else "")) # Create voices and their lyrics: for (voice, num), voiceNum in zip(voices, order): name = voice2id[voice] if num: name += ly.util.int2text(num) a = data.assignMusic(name, voice2Voice[voice].octave) lyrName = name + 'Verse' if lyrEachDiff else 'verse' # Use \addlyrics if all staves have exactly one voice. if lyrEach and maxNumVoices == 1: for verse in stanzas: lyrics[verse].append((ly.dom.AddLyrics(s), lyrName)) ly.dom.Identifier(a.name, staffMusic) else: voiceName = voice2id[voice] + str(num or '') v = ly.dom.Voice(voiceName, parent=staffMusic) voiceMusic = ly.dom.Seqr(v) if voiceNum: ly.dom.Text('\\voice' + ly.util.int2text(voiceNum), voiceMusic) ly.dom.Identifier(a.name, voiceMusic) if stanzas and (lyrEach or (voiceNum <= 1 and (stavesLeft or numStaves == 1))): # Create the lyrics. If they should be above the staff, # give the staff a suitable name, and use alignAbove- # Context to align the Lyrics above the staff. above = voiceNum & 1 if lyrEach else False if above and s.cid is None: s.cid = cid for verse in stanzas: l = ly.dom.Lyrics(parent=choir) if above: l.getWith()['alignAboveContext'] = cid setStaffAffinity(l, "DOWN") elif not lyrEach and stavesLeft: setStaffAffinity(l, "CENTER") lyrics[verse].append((ly.dom.LyricsTo(voiceName, l), lyrName)) # Add ambitus: if self.ambitus.isChecked(): ambitusContext = (s if numVoices == 1 else v).getWith() ly.dom.Line('\\consists "Ambitus_engraver"', ambitusContext) if voiceNum > 1: ly.dom.Line("\\override Ambitus #'X-offset = #{0}".format( (voiceNum - 1) * 2.0), ambitusContext) pianoReduction[voice].append(a.name) rehearsalMidis.append((voice, num, a.name, lyrName)) # Assign the lyrics, so their definitions come after the note defs. # (These refs are used again below in the midi rehearsal routine.) refs = {} for verse in allStanzas: for node, name in lyrics[verse]: if (name, verse) not in refs: refs[(name, verse)] = self.assignLyrics(data, name, verse).name ly.dom.Identifier(refs[(name, verse)], node) # Create the piano reduction if desired if self.pianoReduction.isChecked(): a = data.assign('pianoReduction') data.nodes.append(ly.dom.Identifier(a.name)) piano = ly.dom.PianoStaff(parent=a) sim = ly.dom.Sim(piano) rightStaff = ly.dom.Staff(parent=sim) leftStaff = ly.dom.Staff(parent=sim) right = ly.dom.Seq(rightStaff) left = ly.dom.Seq(leftStaff) # Determine the ordering of voices in the staves upper = pianoReduction['S'] + pianoReduction['A'] lower = pianoReduction['T'] + pianoReduction['B'] preferUpper = 1 if not upper: # Male choir upper = pianoReduction['T'] lower = pianoReduction['B'] ly.dom.Clef("treble_8", right) ly.dom.Clef("bass", left) preferUpper = 0 elif not lower: # Female choir upper = pianoReduction['S'] lower = pianoReduction['A'] else: ly.dom.Clef("bass", left) # Otherwise accidentals can be confusing ly.dom.Line("#(set-accidental-style 'piano)", right) ly.dom.Line("#(set-accidental-style 'piano)", left) # Move voices if unevenly spread if abs(len(upper) - len(lower)) > 1: voices = upper + lower half = (len(voices) + preferUpper) // 2 upper = voices[:half] lower = voices[half:] for staff, voices in (ly.dom.Simr(right), upper), (ly.dom.Simr(left), lower): if voices: for v in voices[:-1]: ly.dom.Identifier(v, staff) ly.dom.VoiceSeparator(staff).after = 1 ly.dom.Identifier(voices[-1], staff) # Make the piano part somewhat smaller ly.dom.Line("fontSize = #-1", piano.getWith()) ly.dom.Line("\\override StaffSymbol #'staff-space = #(magstep -1)", piano.getWith()) # Nice to add Mark engravers ly.dom.Line('\\consists "Mark_engraver"', rightStaff.getWith()) ly.dom.Line('\\consists "Metronome_mark_engraver"', rightStaff.getWith()) # Keep piano reduction out of the MIDI output if builder.midi: ly.dom.Line('\\remove "Staff_performer"', rightStaff.getWith()) ly.dom.Line('\\remove "Staff_performer"', leftStaff.getWith()) # Create MIDI files if desired if self.rehearsalMidi.isChecked(): a = data.assign('rehearsalMidi') rehearsalMidi = a.name func = ly.dom.SchemeList(a) func.pre = '#\n(' # hack ly.dom.Text('define-music-function', func) ly.dom.Line('(parser location name midiInstrument lyrics) ' '(string? string? ly:music?)', func) choir = ly.dom.Sim(ly.dom.Command('unfoldRepeats', ly.dom.SchemeLily(func))) data.afterblocks.append(ly.dom.Comment(_("Rehearsal MIDI files:"))) for voice, num, ref, lyrName in rehearsalMidis: # Append voice to the rehearsalMidi function name = voice2id[voice] + str(num or '') seq = ly.dom.Seq(ly.dom.Voice(name, parent=ly.dom.Staff(name, parent=choir))) if builder.lyVersion < (2, 18, 0): ly.dom.Text('<>\\f', seq) # add one dynamic ly.dom.Identifier(ref, seq) # add the reference to the voice book = ly.dom.Book() # Append score to the aftermath (stuff put below the main score) suffix = "choir{0}-{1}".format(data.num, name) if data.num else name if builder.lyVersion < (2, 12, 0): data.afterblocks.append( ly.dom.Line('#(define output-suffix "{0}")'.format(suffix))) else: ly.dom.Line('\\bookOutputSuffix "{0}"'.format(suffix), book) data.afterblocks.append(book) data.afterblocks.append(ly.dom.BlankLine()) score = ly.dom.Score(book) # TODO: make configurable midiInstrument = voice2Midi[voice] cmd = ly.dom.Command(rehearsalMidi, score) ly.dom.QuotedString(name, cmd) ly.dom.QuotedString(midiInstrument, cmd) ly.dom.Identifier(refs[(lyrName, allStanzas[0])], cmd) ly.dom.Midi(score) ly.dom.Text("\\context Staff = $name", choir) seq = ly.dom.Seq(choir) ly.dom.Line("\\set Score.midiMinimumVolume = #0.5", seq) ly.dom.Line("\\set Score.midiMaximumVolume = #0.5", seq) ly.dom.Line("\\set Score.tempoWholesPerMinute = #" + data.scoreProperties.schemeMidiTempo(), seq) ly.dom.Line("\\set Staff.midiMinimumVolume = #0.8", seq) ly.dom.Line("\\set Staff.midiMaximumVolume = #1.0", seq) ly.dom.Line("\\set Staff.midiInstrument = $midiInstrument", seq) lyr = ly.dom.Lyrics(parent=choir) lyr.getWith()['alignBelowContext'] = ly.dom.Text('$name') ly.dom.Text("\\lyricsto $name $lyrics", lyr)
class ScoreProperties(object): """This is only the base class, it should be mixed in with a widget or a different way.""" def createWidgets(self): """Creates all widgets.""" self.createKeySignatureWidget() self.createTimeSignatureWidget() self.createPickupWidget() self.createMetronomeWidget() self.createTempoWidget() def layoutWidgets(self, layout): """Adds all widgets to a vertical layout.""" self.layoutKeySignatureWidget(layout) self.layoutTimeSignatureWidget(layout) self.layoutPickupWidget(layout) self.layoutMetronomeWidget(layout) self.layoutTempoWidget(layout) def translateWidgets(self): self.translateKeySignatureWidget() self.translateTimeSignatureWidget() self.translatePickupWidget() self.tranlateMetronomeWidget() self.translateTempoWidget() def ly(self, node, builder): """Adds appropriate LilyPond command nodes to the parent node. Settings from the builder are used where that makes sense. All widgets must be present. """ self.lyKeySignature(node, builder) self.lyTimeSignature(node, builder) self.lyPickup(node, builder) self.lyTempo(node, builder) def globalSection(self, builder): """Returns a sequential expression between { } containing the output of ly().""" seq = ly.dom.Seq() self.ly(seq, builder) return seq # Key signature def createKeySignatureWidget(self): self.keySignatureLabel = QLabel() self.keyNote = QComboBox() self.keyNote.setModel( listmodel.ListModel(keyNames['nederlands'], self.keyNote)) self.keyMode = QComboBox() self.keyMode.setModel( listmodel.ListModel(modes, self.keyMode, display=listmodel.translate_index(1))) self.keySignatureLabel.setBuddy(self.keyNote) def translateKeySignatureWidget(self): self.keySignatureLabel.setText(_("Key signature:")) self.keyMode.model().update() def layoutKeySignatureWidget(self, layout): """Adds our widgets to a layout, assuming it is a QVBoxLayout.""" box = QHBoxLayout() box.addWidget(self.keySignatureLabel) box.addWidget(self.keyNote) box.addWidget(self.keyMode) layout.addLayout(box) def setPitchLanguage(self, language='nederlands'): self.keyNote.model()._data = keyNames[language or 'nederlands'] self.keyNote.model().update() def lyKeySignature(self, node, builder): """Adds the key signature to the ly.dom node parent.""" note, alter = keys[self.keyNote.currentIndex()] alter = fractions.Fraction(alter, 2) mode = modes[self.keyMode.currentIndex()][0] ly.dom.KeySignature(note, alter, mode, node).after = 1 # Time signature def createTimeSignatureWidget(self): self.timeSignatureLabel = QLabel() self.timeSignature = QComboBox(editable=True) icons = { '(4/4)': symbols.icon('time_c44'), '(2/2)': symbols.icon('time_c22'), } self.timeSignature.setModel( listmodel.ListModel(timeSignaturePresets, self.timeSignature, icon=icons.get)) self.timeSignature.setCompleter(None) self.timeSignatureLabel.setBuddy(self.timeSignature) def translateTimeSignatureWidget(self): self.timeSignatureLabel.setText(_("Time signature:")) def layoutTimeSignatureWidget(self, layout): """Adds our widgets to a layout, assuming it is a QVBoxLayout.""" box = QHBoxLayout() box.addWidget(self.timeSignatureLabel) box.addWidget(self.timeSignature) layout.addLayout(box) def lyTimeSignature(self, node, builder): """Adds the time signature to the ly.dom node parent.""" sig = self.timeSignature.currentText().strip() if '+' in sig: pass # TODO: implement support for \compoundMeter else: if sig == '(2/2)': ly.dom.TimeSignature(2, 2, node).after = 1 elif sig == '(4/4)': ly.dom.TimeSignature(4, 4, node).after = 1 else: match = re.search(r'(\d+).*?(\d+)', sig) if match: if builder.lyVersion >= (2, 11, 44): ly.dom.Line(r"\numericTimeSignature", node) else: ly.dom.Line( r"\override Staff.TimeSignature #'style = #'()", node) num, beat = map(int, match.group(1, 2)) ly.dom.TimeSignature(num, beat, node).after = 1 # Pickup bar def createPickupWidget(self): self.pickupLabel = QLabel() self.pickup = QComboBox() pickups = [''] pickups.extend(durations) self.pickup.setModel( listmodel.ListModel(pickups, self.pickup, display=lambda item: item or _("None"), icon=lambda item: symbols.icon( 'note_{0}'.format(item.replace('.', 'd'))) if item else None)) self.pickup.view().setIconSize(QSize(22, 22)) self.pickupLabel.setBuddy(self.pickup) def translatePickupWidget(self): self.pickupLabel.setText(_("Pickup measure:")) self.pickup.model().update() def layoutPickupWidget(self, layout): box = QHBoxLayout() box.addWidget(self.pickupLabel) box.addWidget(self.pickup) layout.addLayout(box) def lyPickup(self, node, builder): if self.pickup.currentIndex() > 0: dur, dots = partialDurations[self.pickup.currentIndex() - 1] ly.dom.Partial(dur, dots, parent=node) # Metronome value def createMetronomeWidget(self): self.metronomeLabel = QLabel() self.metronomeNote = QComboBox() self.metronomeNote.setModel( listmodel.ListModel( durations, display=None, icon=lambda item: symbols.icon('note_{0}'.format( item.replace('.', 'd'))))) self.metronomeNote.setCurrentIndex(durations.index('4')) self.metronomeNote.view().setIconSize(QSize(22, 22)) self.metronomeEqualSign = QLabel('=') self.metronomeEqualSign.setFixedWidth( self.metronomeEqualSign.minimumSizeHint().width()) self.metronomeValue = QComboBox(editable=True) self.metronomeValue.setModel( listmodel.ListModel(metronomeValues, self.metronomeValue, display=format)) self.metronomeValue.setCompleter(None) self.metronomeValue.setValidator( QIntValidator(0, 999, self.metronomeValue)) self.metronomeValue.setCurrentIndex(metronomeValues.index(100)) self.metronomeTempo = widgets.tempobutton.TempoButton() self.metronomeTempo.tempo.connect(self.setMetronomeValue) self.metronomeLabel.setBuddy(self.metronomeNote) self.metronomeRound = QCheckBox() def layoutMetronomeWidget(self, layout): grid = QGridLayout() grid.addWidget(self.metronomeLabel, 0, 0) box = QHBoxLayout(spacing=0) box.addWidget(self.metronomeNote) box.addWidget(self.metronomeEqualSign) box.addWidget(self.metronomeValue) box.addWidget(self.metronomeTempo) grid.addLayout(box, 0, 1) grid.addWidget(self.metronomeRound, 1, 1) layout.addLayout(grid) def tranlateMetronomeWidget(self): self.metronomeLabel.setText(_("Metronome mark:")) self.metronomeRound.setText(_("Round tap tempo value")) self.metronomeRound.setToolTip( _("Round the entered tap tempo to a common value.")) def setMetronomeValue(self, bpm): """ Tap the tempo tap button """ if self.metronomeRound.isChecked(): l = [abs(t - bpm) for t in metronomeValues] m = min(l) if m < 6: self.metronomeValue.setCurrentIndex(l.index(m)) else: self.metronomeValue.setEditText(str(bpm)) # Tempo indication def createTempoWidget(self): self.tempoLabel = QLabel() self.tempo = widgets.lineedit.LineEdit() completionmodel.complete(self.tempo, "scorewiz/completion/scoreproperties/tempo") self.tempo.completer().setCaseSensitivity(Qt.CaseInsensitive) self.tempoLabel.setBuddy(self.tempo) def layoutTempoWidget(self, layout): box = QHBoxLayout() box.addWidget(self.tempoLabel) box.addWidget(self.tempo) layout.addLayout(box) def translateTempoWidget(self): self.tempoLabel.setText(_("Tempo indication:")) def lyTempo(self, node, builder): """Returns an appropriate tempo indication.""" text = self.tempo.text().strip() if builder.showMetronomeMark: dur = durations[self.metronomeNote.currentIndex()] val = self.metronomeValue.currentText() or '60' elif text: dur = None val = None else: return tempo = ly.dom.Tempo(dur, val, node) if text: ly.dom.QuotedString(text, tempo) def lyMidiTempo(self, node): """Sets the configured tempo in the tempoWholesPerMinute variable.""" node['tempoWholesPerMinute'] = ly.dom.Scheme(self.schemeMidiTempo()) def schemeMidiTempo(self): """Returns a string with the tempo like '(ly:make-moment 100 4)' from the settings.""" base, mul = midiDurations[self.metronomeNote.currentIndex()] val = int(self.metronomeValue.currentText() or '60') * mul return "(ly:make-moment {0} {1})".format(val, base) def lySimpleMidiTempo(self, node): r"""Return a simple \tempo x=y node for the currently set tempo.""" dur = durations[self.metronomeNote.currentIndex()] val = self.metronomeValue.currentText() or '60' return ly.dom.Tempo(dur, val, node)
class OWImportImages(widget.OWWidget): name = "Import Images" description = "Import images from a directory(s)" icon = "icons/ImportImages.svg" priority = 110 outputs = [("Data", Orange.data.Table)] #: list of recent paths recent_paths = settings.Setting([]) # type: List[RecentPath] currentPath = settings.Setting(None) want_main_area = False resizing_enabled = False Modality = Qt.ApplicationModal # Modality = Qt.WindowModal MaxRecentItems = 20 def __init__(self): super().__init__() #: widget's runtime state self.__state = State.NoState self._imageMeta = [] self._imageCategories = {} self.__invalidated = False self.__pendingTask = None vbox = gui.vBox(self.controlArea) hbox = gui.hBox(vbox) self.recent_cb = QComboBox( sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLengthWithIcon, minimumContentsLength=16, ) self.recent_cb.activated[int].connect(self.__onRecentActivated) icons = standard_icons(self) browseaction = QAction( "Open/Load Images", self, iconText="\N{HORIZONTAL ELLIPSIS}", icon=icons.dir_open_icon, toolTip="Select a directory from which to load the images") browseaction.triggered.connect(self.__runOpenDialog) reloadaction = QAction("Reload", self, icon=icons.reload_icon, toolTip="Reload current image set") reloadaction.triggered.connect(self.reload) self.__actions = namespace( browse=browseaction, reload=reloadaction, ) browsebutton = QPushButton(browseaction.iconText(), icon=browseaction.icon(), toolTip=browseaction.toolTip(), clicked=browseaction.trigger) reloadbutton = QPushButton( reloadaction.iconText(), icon=reloadaction.icon(), clicked=reloadaction.trigger, default=True, ) hbox.layout().addWidget(self.recent_cb) hbox.layout().addWidget(browsebutton) hbox.layout().addWidget(reloadbutton) self.addActions([browseaction, reloadaction]) reloadaction.changed.connect( lambda: reloadbutton.setEnabled(reloadaction.isEnabled())) box = gui.vBox(vbox, "Info") self.infostack = QStackedWidget() self.info_area = QLabel(text="No image set selected", wordWrap=True) self.progress_widget = QProgressBar(minimum=0, maximum=0) self.cancel_button = QPushButton( "Cancel", icon=icons.cancel_icon, ) self.cancel_button.clicked.connect(self.cancel) w = QWidget() vlayout = QVBoxLayout() vlayout.setContentsMargins(0, 0, 0, 0) hlayout = QHBoxLayout() hlayout.setContentsMargins(0, 0, 0, 0) hlayout.addWidget(self.progress_widget) hlayout.addWidget(self.cancel_button) vlayout.addLayout(hlayout) self.pathlabel = TextLabel() self.pathlabel.setTextElideMode(Qt.ElideMiddle) self.pathlabel.setAttribute(Qt.WA_MacSmallSize) vlayout.addWidget(self.pathlabel) w.setLayout(vlayout) self.infostack.addWidget(self.info_area) self.infostack.addWidget(w) box.layout().addWidget(self.infostack) self.__initRecentItemsModel() self.__invalidated = True self.__executor = ThreadExecutor(self) QApplication.postEvent(self, QEvent(RuntimeEvent.Init)) def __initRecentItemsModel(self): if self.currentPath is not None and \ not os.path.isdir(self.currentPath): self.currentPath = None recent_paths = [] for item in self.recent_paths: if os.path.isdir(item.abspath): recent_paths.append(item) recent_paths = recent_paths[:OWImportImages.MaxRecentItems] recent_model = self.recent_cb.model() for pathitem in recent_paths: item = RecentPath_asqstandarditem(pathitem) recent_model.appendRow(item) self.recent_paths = recent_paths if self.currentPath is not None and \ os.path.isdir(self.currentPath) and self.recent_paths and \ os.path.samefile(self.currentPath, self.recent_paths[0].abspath): self.recent_cb.setCurrentIndex(0) else: self.currentPath = None self.recent_cb.setCurrentIndex(-1) self.__actions.reload.setEnabled(self.currentPath is not None) def customEvent(self, event): """Reimplemented.""" if event.type() == RuntimeEvent.Init: if self.__invalidated: try: self.start() finally: self.__invalidated = False super().customEvent(event) def __runOpenDialog(self): startdir = os.path.expanduser("~/") if self.recent_paths: startdir = self.recent_paths[0].abspath if OWImportImages.Modality == Qt.WindowModal: dlg = QFileDialog( self, "Select Top Level Directory", startdir, acceptMode=QFileDialog.AcceptOpen, modal=True, ) dlg.setFileMode(QFileDialog.Directory) dlg.setOption(QFileDialog.ShowDirsOnly) dlg.setDirectory(startdir) dlg.setAttribute(Qt.WA_DeleteOnClose) @dlg.accepted.connect def on_accepted(): dirpath = dlg.selectedFiles() if dirpath: self.setCurrentPath(dirpath[0]) self.start() dlg.open() else: dirpath = QFileDialog.getExistingDirectory( self, "Select Top Level Directory", startdir) if dirpath: self.setCurrentPath(dirpath) self.start() def __onRecentActivated(self, index): item = self.recent_cb.itemData(index) if item is None: return assert isinstance(item, RecentPath) self.setCurrentPath(item.abspath) self.start() def __updateInfo(self): if self.__state == State.NoState: text = "No image set selected" elif self.__state == State.Processing: text = "Processing" elif self.__state == State.Done: nvalid = sum(imeta.isvalid for imeta in self._imageMeta) ncategories = len(self._imageCategories) if ncategories < 2: text = "{} images".format(nvalid) else: text = "{} images / {} categories".format(nvalid, ncategories) elif self.__state == State.Cancelled: text = "Cancelled" elif self.__state == State.Error: text = "Error state" else: assert False self.info_area.setText(text) if self.__state == State.Processing: self.infostack.setCurrentIndex(1) else: self.infostack.setCurrentIndex(0) def setCurrentPath(self, path): """ Set the current root image path to path If the path does not exists or is not a directory the current path is left unchanged Parameters ---------- path : str New root import path. Returns ------- status : bool True if the current root import path was successfully changed to path. """ if self.currentPath is not None and path is not None and \ os.path.isdir(self.currentPath) and os.path.isdir(path) and \ os.path.samefile(self.currentPath, path): return True if not os.path.exists(path): warnings.warn("'{}' does not exist".format(path), UserWarning) return False elif not os.path.isdir(path): warnings.warn("'{}' is not a directory".format(path), UserWarning) return False newindex = self.addRecentPath(path) self.recent_cb.setCurrentIndex(newindex) if newindex >= 0: self.currentPath = path else: self.currentPath = None self.__actions.reload.setEnabled(self.currentPath is not None) if self.__state == State.Processing: self.cancel() return True def addRecentPath(self, path): """ Prepend a path entry to the list of recent paths If an entry with the same path already exists in the recent path list it is moved to the first place Parameters ---------- path : str """ existing = None for pathitem in self.recent_paths: if os.path.samefile(pathitem.abspath, path): existing = pathitem break model = self.recent_cb.model() if existing is not None: selected_index = self.recent_paths.index(existing) assert model.item(selected_index).data(Qt.UserRole) is existing self.recent_paths.remove(existing) row = model.takeRow(selected_index) self.recent_paths.insert(0, existing) model.insertRow(0, row) else: item = RecentPath(path, None, None) self.recent_paths.insert(0, item) model.insertRow(0, RecentPath_asqstandarditem(item)) return 0 def __setRuntimeState(self, state): assert state in State self.setBlocking(state == State.Processing) message = "" if state == State.Processing: assert self.__state in [ State.Done, State.NoState, State.Error, State.Cancelled ] message = "Processing" elif state == State.Done: assert self.__state == State.Processing elif state == State.Cancelled: assert self.__state == State.Processing message = "Cancelled" elif state == State.Error: message = "Error during processing" elif state == State.NoState: message = "" else: assert False self.__state = state if self.__state == State.Processing: self.infostack.setCurrentIndex(1) else: self.infostack.setCurrentIndex(0) self.setStatusMessage(message) self.__updateInfo() def reload(self): """ Restart the image scan task """ if self.__state == State.Processing: self.cancel() self._imageMeta = [] self._imageCategories = {} self.start() def start(self): """ Start/execute the image indexing operation """ self.error() self.__invalidated = False if self.currentPath is None: return if self.__state == State.Processing: assert self.__pendingTask is not None log.info("Starting a new task while one is in progress. " "Cancel the existing task (dir:'{}')".format( self.__pendingTask.startdir)) self.cancel() startdir = self.currentPath self.__setRuntimeState(State.Processing) report_progress = methodinvoke(self, "__onReportProgress", (object, )) task = ImageScan(startdir, report_progress=report_progress) # collect the task state in one convenient place self.__pendingTask = taskstate = namespace( task=task, startdir=startdir, future=None, watcher=None, cancelled=False, cancel=None, ) def cancel(): # Cancel the task and disconnect if taskstate.future.cancel(): pass else: taskstate.task.cancelled = True taskstate.cancelled = True try: taskstate.future.result(timeout=3) except UserInterruptError: pass except TimeoutError: log.info("The task did not stop in in a timely manner") taskstate.watcher.finished.disconnect(self.__onRunFinished) taskstate.cancel = cancel def run_image_scan_task_interupt(): try: return task.run() except UserInterruptError: # Suppress interrupt errors, so they are not logged return taskstate.future = self.__executor.submit(run_image_scan_task_interupt) taskstate.watcher = FutureWatcher(taskstate.future) taskstate.watcher.finished.connect(self.__onRunFinished) @Slot() def __onRunFinished(self): assert QThread.currentThread() is self.thread() assert self.__state == State.Processing assert self.__pendingTask is not None assert self.sender() is self.__pendingTask.watcher assert self.__pendingTask.future.done() task = self.__pendingTask self.__pendingTask = None try: image_meta = task.future.result() except Exception as err: sys.excepthook(*sys.exc_info()) state = State.Error image_meta = [] self.error(traceback.format_exc()) else: state = State.Done self.error() categories = {} for imeta in image_meta: # derive categories from the path relative to the starting dir dirname = os.path.dirname(imeta.path) relpath = os.path.relpath(dirname, task.startdir) categories[dirname] = relpath self._imageMeta = image_meta self._imageCategories = categories self.__setRuntimeState(state) self.commit() def cancel(self): """ Cancel current pending task (if any). """ if self.__state == State.Processing: assert self.__pendingTask is not None self.__pendingTask.cancel() self.__pendingTask = None self.__setRuntimeState(State.Cancelled) @Slot(object) def __onReportProgress(self, arg): # report on scan progress from a worker thread # arg must be a namespace(count: int, lastpath: str) assert QThread.currentThread() is self.thread() if self.__state == State.Processing: self.pathlabel.setText(prettyfypath(arg.lastpath)) def commit(self): """ Create and commit a Table from the collected image meta data. """ if self._imageMeta: categories = self._imageCategories if len(categories) > 1: cat_var = Orange.data.DiscreteVariable( "category", values=list(sorted(categories.values()))) else: cat_var = None # Image name (file basename without the extension) imagename_var = Orange.data.StringVariable("image name") # Full fs path image_var = Orange.data.StringVariable("image") image_var.attributes["type"] = "image" # file size/width/height size_var = Orange.data.ContinuousVariable("size", number_of_decimals=0) width_var = Orange.data.ContinuousVariable("width", number_of_decimals=0) height_var = Orange.data.ContinuousVariable("height", number_of_decimals=0) domain = Orange.data.Domain( [], [cat_var] if cat_var is not None else [], [imagename_var, image_var, size_var, width_var, height_var]) cat_data = [] meta_data = [] for imgmeta in self._imageMeta: if imgmeta.isvalid: if cat_var is not None: category = categories.get(os.path.dirname( imgmeta.path)) cat_data.append([cat_var.to_val(category)]) else: cat_data.append([]) basename = os.path.basename(imgmeta.path) imgname, _ = os.path.splitext(basename) meta_data.append([ imgname, imgmeta.path, imgmeta.size, imgmeta.width, imgmeta.height ]) cat_data = numpy.array(cat_data, dtype=float) meta_data = numpy.array(meta_data, dtype=object) table = Orange.data.Table.from_numpy( domain, numpy.empty((len(cat_data), 0), dtype=float), cat_data, meta_data) else: table = None self.send("Data", table) def onDeleteWidget(self): self.cancel() self.__executor.shutdown(wait=True)
class TablaturePart(_base.Part): """Base class for tablature instrument part types.""" octave = 0 clef = None transposition = None tunings = () # may contain a list of tunings. tabFormat = '' # can contain a tablatureFormat value. def createWidgets(self, layout): self.staffTypeLabel = QLabel() self.staffType = QComboBox() self.staffTypeLabel.setBuddy(self.staffType) self.staffType.setModel(listmodel.ListModel(tablatureStaffTypes, self.staffType, display=listmodel.translate)) box = QHBoxLayout() layout.addLayout(box) box.addWidget(self.staffTypeLabel) box.addWidget(self.staffType) if self.tunings: self.createTuningWidgets(layout) self.staffType.activated.connect(self.slotTabEnable) self.slotTabEnable(0) def createTuningWidgets(self, layout): self.tuningLabel = QLabel() self.tuning = QComboBox() self.tuningLabel.setBuddy(self.tuning) tunings = [('', lambda: _("Default"))] tunings.extend(self.tunings) tunings.append(('', lambda: _("Custom tuning"))) self.tuning.setModel(listmodel.ListModel(tunings, self.tuning, display=listmodel.translate_index(1))) self.tuning.setCurrentIndex(1) self.customTuning = QLineEdit(enabled=False) completionmodel.complete(self.customTuning, "scorewiz/completion/plucked_strings/custom_tuning") self.tuning.currentIndexChanged.connect(self.slotCustomTuningEnable) box = QHBoxLayout() layout.addLayout(box) box.addWidget(self.tuningLabel) box.addWidget(self.tuning) layout.addWidget(self.customTuning) def translateWidgets(self): self.staffTypeLabel.setText(_("Staff type:")) self.staffType.model().update() if self.tunings: self.translateTuningWidgets() def translateTuningWidgets(self): self.tuningLabel.setText(_("Tuning:")) self.customTuning.setToolTip('<qt>' + _( "Select custom tuning in the combobox and " "enter a custom tuning here, e.g. <code>e, a d g b e'</code>. " "Use absolute note names in the same language as you want to use " "in your document (by default: \"nederlands\").")) try: self.customTuning.setPlaceholderText(_("Custom tuning...")) except AttributeError: pass # only in Qt 4.7+ self.tuning.model().update() def slotTabEnable(self, enable): """Called when the user changes the staff type. Non-zero if the user wants a TabStaff. """ self.tuning.setEnabled(bool(enable)) if enable: self.slotCustomTuningEnable(self.tuning.currentIndex()) else: self.customTuning.setEnabled(False) def slotCustomTuningEnable(self, index): self.customTuning.setEnabled(index > len(self.tunings)) def voiceCount(self): """Returns the number of voices. Inherit to make this user-settable. """ return 1 def build(self, data, builder): # First make assignments for the voices we want to create numVoices = self.voiceCount() if numVoices == 1: voices = (ly.util.mkid(data.name()),) elif numVoices == 2: order = 1, 2 voices = 'upper', 'lower' elif numVoices == 3: order = 1, 3, 2 voices = 'upper', 'middle', 'lower' else: order = 1, 2, 3, 4 voices = [ly.util.mkid(data.name(), "voice") + ly.util.int2text(i) for i in order] assignments = [data.assignMusic(name, self.octave, self.transposition) for name in voices] staffType = self.staffType.currentIndex() if staffType in (0, 2): # create a normal staff staff = ly.dom.Staff() seq = ly.dom.Seqr(staff) if self.clef: ly.dom.Clef(self.clef, seq) mus = ly.dom.Simr(seq) for a in assignments[:-1]: ly.dom.Identifier(a.name, mus) ly.dom.VoiceSeparator(mus) ly.dom.Identifier(assignments[-1].name, mus) builder.setMidiInstrument(staff, self.midiInstrument) if staffType in (1, 2): # create a tab staff tabstaff = ly.dom.TabStaff() if self.tabFormat: tabstaff.getWith()['tablatureFormat'] = ly.dom.Scheme(self.tabFormat) self.setTunings(tabstaff) sim = ly.dom.Simr(tabstaff) if numVoices == 1: ly.dom.Identifier(assignments[0].name, sim) else: for num, a in zip(order, assignments): s = ly.dom.Seq(ly.dom.TabVoice(parent=sim)) ly.dom.Text('\\voice' + ly.util.int2text(num), s) ly.dom.Identifier(a.name, s) if staffType == 0: # only a normal staff p = staff elif staffType == 1: # only a TabStaff builder.setMidiInstrument(tabstaff, self.midiInstrument) p = tabstaff else: # both TabStaff and normal staff p = ly.dom.StaffGroup() s = ly.dom.Sim(p) s.append(staff) s.append(tabstaff) builder.setInstrumentNamesFromPart(p, self, data) data.nodes.append(p) def setTunings(self, tab): if self.tunings: i = self.tuning.currentIndex() if i == 0: return elif i > len(self.tunings): value = ly.dom.Text("\\stringTuning <{0}>".format(self.customTuning.text())) else: tuning = self.tunings[self.tuning.currentIndex() - 1][0] value = ly.dom.Scheme(tuning) tab.getWith()['stringTunings'] = value
class SvgView(QWidget): def __init__(self, dockwidget): super(SvgView, self).__init__(dockwidget) self._document = None self._setting_zoom = False self.view = view.View(self) self.pageLabel = QLabel() self.pageCombo = QComboBox(sizeAdjustPolicy=QComboBox.AdjustToContents) layout = QVBoxLayout(spacing=0) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) hbox = QHBoxLayout(spacing=0) hbox.addWidget(self.pageLabel) hbox.addWidget(self.pageCombo) self.zoomInButton = QToolButton(autoRaise=True) self.zoomOutButton = QToolButton(autoRaise=True) self.zoomOriginalButton = QToolButton(autoRaise=True) self.zoomNumber = QSpinBox(minimum=10, maximum=1000, suffix='%') ac = dockwidget.actionCollection self.zoomInButton.setDefaultAction(ac.svg_zoom_in) self.zoomOutButton.setDefaultAction(ac.svg_zoom_out) self.zoomOriginalButton.setDefaultAction(ac.svg_zoom_original) hbox.addWidget(self.zoomInButton) hbox.addWidget(self.zoomNumber) hbox.addWidget(self.zoomOutButton) hbox.addWidget(self.zoomOriginalButton) self.resetButton = QPushButton("reload", self) self.resetButton.clicked.connect(self.reLoadDoc) hbox.addWidget(self.resetButton) self.saveButton = QPushButton("save edits", self) self.saveButton.clicked.connect(self.callSave) hbox.addWidget(self.saveButton) hbox.addStretch(1) layout.addLayout(hbox) layout.addWidget(self.view) app.jobFinished.connect(self.initSvg) app.documentClosed.connect(self.slotDocumentClosed) app.documentLoaded.connect(self.initSvg) self.pageCombo.currentIndexChanged.connect(self.changePage) self.zoomNumber.valueChanged.connect(self.slotZoomNumberChanged) self.view.zoomFactorChanged.connect(self.slotViewZoomChanged) dockwidget.mainwindow().currentDocumentChanged.connect(self.initSvg) self.zoomNumber.setValue(100) doc = dockwidget.mainwindow().currentDocument() if doc: self.initSvg(doc) app.translateUI(self) def translateUI(self): self.pageLabel.setText(_("Page:")) def mainwindow(self): return self.parent().mainwindow() def initSvg(self, doc): """Opens first page of score after compilation""" if doc == self.mainwindow().currentDocument(): files = svgfiles.SvgFiles.instance(doc) model = files.model() # forces update if files: self._document = doc with qutil.signalsBlocked(self.pageCombo): self.pageCombo.setModel(model) self.pageCombo.setCurrentIndex(files.current) self.view.load(files.url(files.current)) def reLoadDoc(self): """Reloads current document.""" if self._document: self.initSvg(self._document) def callSave(self): """Call save function""" self.view.evalSave() def getCurrent(self): files = svgfiles.SvgFiles.instance(self._document) return files.filename(files.current) def slotZoomNumberChanged(self, value): self._setting_zoom = True self.view.setZoomFactor(value / 100.0) self._setting_zoom = False def slotViewZoomChanged(self): if not self._setting_zoom: self.zoomNumber.setValue(int(self.view.zoomFactor() * 100)) def changePage(self, page_index): """change page of score""" doc = self._document if doc: files = svgfiles.SvgFiles.instance(doc) if files: files.current = page_index svg = files.url(page_index) self.view.load(svg) def slotDocumentClosed(self, doc): if doc == self._document: self._document = None if self.pageCombo.model(): self.pageCombo.model().deleteLater() self.pageCombo.clear() self.pageCombo.update() # otherwise it doesn't redraw self.view.clear()
class Drums(_base.Part): @staticmethod def title(_=_base.translate): return _("Drums") @staticmethod def short(_=_base.translate): return _("abbreviation for Drums", "Dr.") def createWidgets(self, layout): self.voicesLabel = QLabel() self.voices = QSpinBox(minimum=1, maximum=4, value=1) self.drumStyleLabel = QLabel() self.drumStyle = QComboBox() self.drumStyle.setModel(listmodel.ListModel(drumStyles, self.drumStyle, display=listmodel.translate)) self.drumStems = QCheckBox() box = QHBoxLayout() box.addWidget(self.voicesLabel) box.addWidget(self.voices) layout.addLayout(box) box = QHBoxLayout() box.addWidget(self.drumStyleLabel) box.addWidget(self.drumStyle) layout.addLayout(box) layout.addWidget(self.drumStems) def translateWidgets(self): self.voicesLabel.setText(_("Voices:")) self.drumStyleLabel.setText(_("Style:")) self.drumStems.setText(_("Remove stems")) self.drumStems.setToolTip(_("Remove the stems from the drum notes.")) self.drumStyle.model().update() def assignDrums(self, data, name = None): """Creates an empty name = \drummode assignment. Returns the assignment. """ a = data.assign(name) s = ly.dom.DrumMode(a) ly.dom.Identifier(data.globalName, s) ly.dom.LineComment(_("Drums follow here."), s) ly.dom.BlankLine(s) return a def build(self, data, builder): p = ly.dom.DrumStaff() s = ly.dom.Simr(p) if self.voices.value() > 1: for i in range(1, self.voices.value() + 1): q = ly.dom.Seq(ly.dom.DrumVoice(parent=s)) ly.dom.Text('\\voice' + ly.util.int2text(i), q) a = self.assignDrums(data, 'drum' + ly.util.int2text(i)) ly.dom.Identifier(a.name, q) else: a = self.assignDrums(data, 'drum') ly.dom.Identifier(a.name, s) builder.setInstrumentNamesFromPart(p, self, data) i = self.drumStyle.currentIndex() if i > 0: v = ('drums', 'timbales', 'congas', 'bongos', 'percussion')[i] p.getWith()['drumStyleTable'] = ly.dom.Scheme(v + '-style') v = (5, 2, 2, 2, 1)[i] ly.dom.Line("\\override StaffSymbol #'line-count = #{0}".format(v), p.getWith()) if self.drumStems.isChecked(): ly.dom.Line("\\override Stem #'stencil = ##f", p.getWith()) ly.dom.Line("\\override Stem #'length = #3 % " + _("keep some distance."), p.getWith()) data.nodes.append(p)