Browse Source

Add subtitle and tempo fields

Allow changing block width
master
Ivan Holmes 5 years ago
parent
commit
977817a293
  1. 16
      chordsheet/document.py
  2. 2
      chordsheet/primitives.py
  3. 22
      chordsheet/render.py
  4. 21
      gui.py
  5. 3
      ui/aboutdialog.ui
  6. 103
      ui/mainwindow.ui

16
chordsheet/document.py

@ -18,6 +18,7 @@ class Style:
self.font = kwargs.get('font', 'FreeSans')
self.lineSpacing = kwargs.get('lineSpacing', 1.15)
self.separatorSize = kwargs.get('separatorSize', 5)
self.unitWidth = kwargs.get('unitWidth', 10)
self.useIncludedFont = True
@ -25,7 +26,6 @@ class Style:
self.stringHzGap = 2*self.unit
self.stringHeight = 5*self.unit
self.unitWidth = 10*self.unit
self.unitHeight = 20*self.unit
self.beatsHeight = 5*self.unit
@ -58,17 +58,19 @@ class Block:
return NotImplemented
class Document:
def __init__(self, chordList=None, blockList=None, title=None, composer=None, arranger=None, timeSignature=defaultTimeSignature):
def __init__(self, chordList=None, blockList=None, title=None, subtitle=None, composer=None, arranger=None, timeSignature=defaultTimeSignature, tempo=None):
self.chordList = chordList or []
self.blockList = blockList or []
self.title = title or '' # Do not initialise title empty
self.subtitle = subtitle
self.composer = composer
self.arranger = arranger
self.timeSignature = timeSignature
self.tempo = tempo
def __eq__(self, other):
if isinstance(other, self.__class__):
textEqual = self.title == other.title and self.composer == other.composer and self.arranger == other.arranger and self.timeSignature == other.timeSignature # check all the text values for equality
textEqual = self.title == other.title and self.subtitle == other.subtitle and self.composer == other.composer and self.arranger == other.arranger and self.timeSignature == other.timeSignature and self.tempo == other.tempo # check all the text values for equality
return textEqual and self.chordList == other.chordList and self.blockList == other.blockList
return NotImplemented
@ -104,9 +106,11 @@ class Document:
self.blockList.append(Block(int(b.find('length').text), chord=blockChord, notes=blockNotes))
self.title = (root.find('title').text if root.find('title') is not None else '') # Do not initialise title empty
self.subtitle = (root.find('subtitle').text if root.find('subtitle') is not None else None)
self.composer = (root.find('composer').text if root.find('composer') is not None else None)
self.arranger = (root.find('arranger').text if root.find('arranger') is not None else None)
self.timeSignature = (int(root.find('timesignature').text) if root.find('timesignature') is not None else defaultTimeSignature)
self.tempo = (root.find('tempo').text if root.find('tempo') is not None else None)
def newFromXML(filepath):
"""
@ -124,6 +128,9 @@ class Document:
ET.SubElement(root, "title").text = self.title
if self.subtitle is not None:
ET.SubElement(root, "subtitle").text = self.subtitle
if self.arranger is not None:
ET.SubElement(root, "arranger").text = self.arranger
@ -132,6 +139,9 @@ class Document:
ET.SubElement(root, "timesignature").text = str(self.timeSignature)
if self.tempo is not None:
ET.SubElement(root, "tempo").text = self.tempo
chordsElement = ET.SubElement(root, "chords")
for c in self.chordList:

2
chordsheet/primitives.py

@ -6,7 +6,7 @@ from reportlab.graphics.shapes import *
def writeText(currentCanvas, style, string, size, vpos, **kwargs):
"""
Wrapper function to conveniently write text according to my requirements...
Wrapper function to conveniently write text and return how much vertical space it took up.
"""
margin = style.leftMargin*style.unit

22
chordsheet/render.py

@ -82,6 +82,7 @@ def guitarChart(currentCanvas, style, chordList, cur_pos):
def chordProgression(currentCanvas, style, document, cur_pos):
margin = style.leftMargin*style.unit
unitWidth = style.unitWidth*style.unit
pagesize = style.pageSize
title_height = writeText(currentCanvas, style, "Chord progression", 18, cur_pos, align="left")
@ -93,11 +94,14 @@ def chordProgression(currentCanvas, style, document, cur_pos):
h_loc = 0
v_loc = 0
maxWidth = int((((pagesize[0]-(2*margin))/style.unitWidth)//(document.timeSignature*2))*(document.timeSignature*2)) # use integer division to round maxWidth to nearest two bars
if (unitWidth * document.timeSignature * 2) >= ((pagesize[0]-(2*margin) + 1)): # adding 1 to allow for rounding errors
raise Exception("Beat width (unitWidth) is too high. It is {current} pt and can be a maximum of {max} pt".format(current = unitWidth, max = ((pagesize[0]-(2*margin)/(document.timeSignature * 2)))))
maxWidth = int((((pagesize[0]-(2*margin))/unitWidth)//(document.timeSignature*2))*(document.timeSignature*2)) # use integer division to round maxWidth to nearest two bars
for u in range(maxWidth+1):
s = 0
x = u*style.unitWidth+margin
x = u*unitWidth+margin
if u % document.timeSignature == 0:
e = -style.beatsHeight
else:
@ -105,7 +109,7 @@ def chordProgression(currentCanvas, style, document, cur_pos):
drawVertLine(currentCanvas, s, e, x, h_origin, v_origin)
if u == maxWidth: # Avoid writing beat number after the final line
break
writeText(currentCanvas, style, str((u % document.timeSignature)+1), style.beatsFontSize, v_origin-style.beatsHeight, hpos=x+style.unitWidth/2)
writeText(currentCanvas, style, str((u % document.timeSignature)+1), style.beatsFontSize, v_origin-style.beatsHeight, hpos=x+unitWidth/2)
parsedBlockList = splitBlocks(document.blockList, maxWidth)
@ -113,12 +117,12 @@ def chordProgression(currentCanvas, style, document, cur_pos):
if h_loc == maxWidth:
v_loc += 1
h_loc = 0
currentCanvas.rect(h_origin+(h_loc*style.unitWidth), v_origin+(v_loc*style.unitHeight), b.length*style.unitWidth, style.unitHeight)
currentCanvas.rect(h_origin+(h_loc*unitWidth), v_origin+(v_loc*style.unitHeight), b.length*unitWidth, style.unitHeight)
if b.notes is not None:
writeText(currentCanvas, style, b.notes, style.notesFontSize, v_origin+((v_loc+1)*style.unitHeight)-(1.3*style.notesFontSize), hpos=h_origin+((h_loc+b.length/2)*style.unitWidth))
writeText(currentCanvas, style, b.notes, style.notesFontSize, v_origin+((v_loc+1)*style.unitHeight)-(1.3*style.notesFontSize), hpos=h_origin+((h_loc+b.length/2)*unitWidth))
v_offset = ((v_loc*style.unitHeight)+style.unitHeight/2)-style.chordNameFontSize/2
if b.chord is not None:
writeText(currentCanvas, style, b.chord.name, style.chordNameFontSize, v_origin+v_offset, hpos=h_origin+((h_loc+b.length/2)*style.unitWidth))
writeText(currentCanvas, style, b.chord.name, style.chordNameFontSize, v_origin+v_offset, hpos=h_origin+((h_loc+b.length/2)*unitWidth))
h_loc += b.length
return v_origin + (v_loc+1)*style.unitHeight + style.beatsHeight + title_height # calculate the height of the generated chart
@ -140,12 +144,18 @@ def savePDF(document, style, pathToPDF):
if document.title is not None:
curPos += writeText(c, style, document.title, 24, curPos)
if document.subtitle is not None:
curPos += writeText(c, style, document.subtitle, 18, curPos)
if document.composer is not None:
curPos += writeText(c, style, "Composer: {c}".format(c = document.composer), 12, curPos)
if document.arranger is not None:
curPos += writeText(c, style, "Arranger: {a}".format(a = document.arranger), 12, curPos)
if document.tempo is not None:
curPos += writeText(c, style, "♩ = {t} bpm".format(t = document.tempo), 12, curPos, align = "left")
curPos += style.separatorSize*style.unit
if guitarChartCheck(document.chordList):

21
gui.py

@ -155,6 +155,7 @@ class DocumentWindow(QMainWindow):
self.window.composerLineEdit.setText(self.doc.composer)
self.window.arrangerLineEdit.setText(self.doc.arranger)
self.window.timeSignatureSpinBox.setValue(self.doc.timeSignature)
self.window.tempoLineEdit.setText(self.doc.tempo)
self.window.chordTableView.populate(self.doc.chordList)
self.window.blockTableView.populate(self.doc.blockList)
@ -178,6 +179,8 @@ class DocumentWindow(QMainWindow):
self.window.fontComboBox.setDisabled(True)
self.window.includedFontCheckBox.setChecked(True)
self.window.beatWidthLineEdit.setText(str(self.style.unitWidth))
def pageSizeAction(self, index):
self.pageSizeSelected = self.window.pageSizeComboBox.itemText(index)
@ -529,15 +532,25 @@ class DocumentWindow(QMainWindow):
Update the Document object by reading values from the UI.
"""
self.doc.title = self.window.titleLineEdit.text() # Title can be empty string but not None
self.doc.subtitle = (self.window.subtitleLineEdit.text() if self.window.subtitleLineEdit.text() else None)
self.doc.composer = (self.window.composerLineEdit.text() if self.window.composerLineEdit.text() else None)
self.doc.arranger = (self.window.arrangerLineEdit.text() if self.window.arrangerLineEdit.text() else None)
self.doc.tempo = (self.window.tempoLineEdit.text() if self.window.tempoLineEdit.text() else None)
self.doc.timeSignature = int(self.window.timeSignatureSpinBox.value()) if self.window.timeSignatureSpinBox.value() else self.doc.timeSignature
self.doc.timeSignature = int(self.window.timeSignatureSpinBox.value())
self.style.pageSize = pageSizeDict[self.pageSizeSelected]
self.style.unit = unitDict[self.unitSelected]
self.style.leftMargin = int(self.window.leftMarginLineEdit.text())
self.style.topMargin = int(self.window.topMarginLineEdit.text())
self.style.lineSpacing = float(self.window.lineSpacingDoubleSpinBox.value())
self.style.leftMargin = float(self.window.leftMarginLineEdit.text()) if self.window.leftMarginLineEdit.text() else self.style.leftMargin
self.style.topMargin = float(self.window.topMarginLineEdit.text()) if self.window.topMarginLineEdit.text() else self.style.topMargin
self.style.lineSpacing = float(self.window.lineSpacingDoubleSpinBox.value()) if self.window.lineSpacingDoubleSpinBox.value() else self.style.lineSpacing
# make sure the unit width isn't too wide to draw!
if self.window.beatWidthLineEdit.text():
if (self.style.pageSize[0] - 2 * self.style.leftMargin * mm) >= (float(self.window.beatWidthLineEdit.text()) * 2 * self.doc.timeSignature * mm):
self.style.unitWidth = float(self.window.beatWidthLineEdit.text())
else:
maxBeatWidth = (self.style.pageSize[0] - 2 * self.style.leftMargin * mm) / (2 * self.doc.timeSignature * mm)
warning = QMessageBox.warning(self, "Out of range", "Beat width is out of range. It can be a maximum of {}.".format(maxBeatWidth), buttons=QMessageBox.Ok, defaultButton=QMessageBox.Ok)
self.updateChords()
self.updateBlocks()

3
ui/aboutdialog.ui

@ -51,6 +51,9 @@
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item>

103
ui/mainwindow.ui

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>761</width>
<height>513</height>
<width>1061</width>
<height>646</height>
</rect>
</property>
<property name="windowTitle">
@ -42,7 +42,7 @@
<property name="minimumSize">
<size>
<width>430</width>
<height>400</height>
<height>600</height>
</size>
</property>
<property name="maximumSize">
@ -104,13 +104,23 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="subtitleLabel">
<property name="text">
<string>Subtitle</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="subtitleLineEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="composerLabel">
<property name="text">
<string>Composer</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QLineEdit" name="composerLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
@ -120,14 +130,14 @@
</property>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QLabel" name="arrangerLabel">
<property name="text">
<string>Arranger</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="QLineEdit" name="arrangerLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
@ -137,18 +147,37 @@
</property>
</widget>
</item>
</layout>
<item row="4" column="0">
<widget class="QLabel" name="tempoLabel">
<property name="text">
<string>Tempo</string>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayoutTimeSignature">
<item row="0" column="0">
<item row="4" column="1">
<widget class="QLineEdit" name="tempoLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="timeSignatureLabel">
<property name="text">
<string>Time signature</string>
<string>Time</string>
</property>
</widget>
</item>
<item row="0" column="1">
<item row="5" column="1">
<widget class="QSpinBox" name="timeSignatureSpinBox">
<property name="maximumSize">
<size>
@ -190,6 +219,12 @@
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QGroupBox" name="pageGroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Page options</string>
</property>
@ -330,16 +365,46 @@
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="includedFontCheckBox">
<property name="text">
<string>Use included FreeSans</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item alignment="Qt::AlignRight">
<widget class="QCheckBox" name="includedFontCheckBox">
<item>
<widget class="QGroupBox" name="blockOptions">
<property name="title">
<string>Block options</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QFormLayout" name="formLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="beatWidthLabel">
<property name="text">
<string>Use included FreeSans</string>
<string>Beat width</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="beatWidthLineEdit">
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
@ -739,8 +804,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>298</width>
<height>465</height>
<width>598</width>
<height>598</height>
</rect>
</property>
<property name="autoFillBackground">
@ -787,7 +852,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>761</width>
<width>1061</width>
<height>22</height>
</rect>
</property>
@ -916,14 +981,12 @@
<tabstop>titleLineEdit</tabstop>
<tabstop>composerLineEdit</tabstop>
<tabstop>arrangerLineEdit</tabstop>
<tabstop>timeSignatureSpinBox</tabstop>
<tabstop>pageSizeComboBox</tabstop>
<tabstop>documentUnitsComboBox</tabstop>
<tabstop>leftMarginLineEdit</tabstop>
<tabstop>topMarginLineEdit</tabstop>
<tabstop>lineSpacingDoubleSpinBox</tabstop>
<tabstop>fontComboBox</tabstop>
<tabstop>includedFontCheckBox</tabstop>
<tabstop>chordTableView</tabstop>
<tabstop>chordNameLineEdit</tabstop>
<tabstop>guitarVoicingLineEdit</tabstop>

Loading…
Cancel
Save