From ce3ed11f12679c9038b54c3dcee424fb6ef4cbaf Mon Sep 17 00:00:00 2001 From: Ivan Holmes Date: Wed, 15 Sep 2021 22:09:40 +0100 Subject: [PATCH] add MDI --- gui.py | 140 +++++++++++--- preview.pdf | Bin 20738 -> 11872 bytes requirements.txt | 3 + ui/blocks.ui | 392 +++++++++++++++++++++---------------- ui/chords.ui | 243 +++++++++++++---------- ui/docinfo.ui | 22 ++- ui/document.ui | 2 +- ui/new.ui | 63 +++++- ui/preview.ui | 13 +- ui/psetup.ui | 493 +++++++++++++++++++++++++---------------------- ui/sections.ui | 214 +++++++++++--------- 11 files changed, 972 insertions(+), 613 deletions(-) create mode 100644 requirements.txt diff --git a/gui.py b/gui.py index dc81a3d..baa08c7 100755 --- a/gui.py +++ b/gui.py @@ -14,9 +14,9 @@ import os import time from copy import copy -from PyQt5.QtWidgets import QApplication, QAction, QLabel, QDialogButtonBox, QDialog, QFileDialog, QMessageBox, QPushButton, QLineEdit, QCheckBox, QSpinBox, QDoubleSpinBox, QTableWidgetItem, QTabWidget, QComboBox, QWidget, QScrollArea, QMainWindow, QShortcut, QMdiSubWindow +from PyQt5.QtWidgets import QApplication, QAction, QLabel, QDialogButtonBox, QDialog, QFileDialog, QMessageBox, QPushButton, QLineEdit, QCheckBox, QFontComboBox, QSpinBox, QDoubleSpinBox, QTableWidgetItem, QTabWidget, QComboBox, QWidget, QScrollArea, QMainWindow, QShortcut, QMdiSubWindow from PyQt5.QtCore import QFile, QObject, Qt, pyqtSlot, QSettings -from PyQt5.QtGui import QPixmap, QImage, QKeySequence +from PyQt5.QtGui import QPixmap, QImage, QKeySequence, QFontInfo, QFont, QRawFont from PyQt5 import uic from chordsheet.tableView import ChordTableView, BlockTableView from chordsheet.comboBox import MComboBox @@ -76,6 +76,9 @@ class MainWindow(QMainWindow): self.setCentralWidget(self.window.centralWidget) self.setMenuBar(self.window.menuBar) self.setWindowTitle("Chordsheet") + + self.lastSubWindow = None + self.currentSection = None if filename: try: @@ -113,6 +116,14 @@ class MainWindow(QMainWindow): self.addDockWidget(Qt.RightDockWidgetArea, self.chordsw) self.addDockWidget(Qt.RightDockWidgetArea, self.sectionsw) self.addDockWidget(Qt.RightDockWidgetArea, self.blocksw) + + # Check all the boxes in the window menu + self.window.actionDocument_information.setChecked(True) + self.window.actionPage_setup.setChecked(True) + self.window.actionChords.setChecked(True) + self.window.actionSections.setChecked(True) + self.window.actionBlocks.setChecked(True) + self.window.actionPreview.setChecked(True) # link all the UI elements self.window.mdiArea.subWindowActivated.connect(self.switchDocument) @@ -145,6 +156,14 @@ class MainWindow(QMainWindow): self.window.actionCopy.setShortcut(QKeySequence.Copy) self.window.actionPaste.setShortcut(QKeySequence.Paste) + self.window.actionDocument_information.triggered.connect(self.menuWindowDocInfoAction) + self.window.actionPage_setup.triggered.connect(self.menuWindowPageSetupAction) + self.window.actionChords.triggered.connect(self.menuWindowChordsAction) + self.window.actionSections.triggered.connect(self.menuWindowSectionsAction) + self.window.actionBlocks.triggered.connect(self.menuWindowBlocksAction) + self.window.actionPreview.triggered.connect(self.menuWindowPreviewAction) + + self.psetup.widget().pageSizeComboBox.currentIndexChanged.connect( self.pageSizeAction) self.psetup.widget().documentUnitsComboBox.currentIndexChanged.connect( @@ -157,7 +176,8 @@ class MainWindow(QMainWindow): self.psetup.widget().documentUnitsComboBox.addItems(list(unitDict.keys())) self.psetup.widget().documentUnitsComboBox.setCurrentText( list(unitDict.keys())[0]) - + + self.psetup.widget().fontComboBox.currentFontChanged.connect(self.fontChangeAction) self.psetup.widget().includedFontCheckBox.stateChanged.connect( self.includedFontAction) @@ -210,13 +230,17 @@ class MainWindow(QMainWindow): self.chordsw.widget().chordTableView.populate(doc.chordList) self.sectionsw.widget().sectionTableView.populate(doc.sectionList) + + self.updateChordDict(doc) + self.updateSectionDict(doc) # populate the block table with the first section, account for a document with no sections - self.currentSection = doc.sectionList[0] if len( - doc.sectionList) else None + if self.currentSection is None: + self.currentSection = doc.sectionList[0] if doc.sectionList else None + else: + self.blocksw.widget().blockSectionComboBox.setCurrentText( + self.currentSection.name) self.blocksw.widget().blockTableView.populate( self.currentSection.blockList if self.currentSection else []) - self.updateChordDict(doc) - self.updateSectionDict(doc) def UIInitStyle(self, style): """ @@ -235,8 +259,7 @@ class MainWindow(QMainWindow): self.psetup.widget().topMarginLineEdit.setText(str(style.topMargin)) self.psetup.widget().bottomMarginLineEdit.setText(str(style.bottomMargin)) - - self.psetup.widget().fontComboBox.setDisabled(True) + # self.psetup.widget().fontComboBox.setDisabled(True) self.psetup.widget().includedFontCheckBox.setChecked(True) self.psetup.widget().beatWidthLineEdit.setText(str(style.unitWidth)) @@ -258,11 +281,28 @@ class MainWindow(QMainWindow): self.blocksw.widget().blockSectionComboBox.clear() self.blocksw.widget().blockSectionComboBox.addItems( list(self.sectionDict.keys())) - - def switchDocument(self): + + def fontChangeAction(self): if self.window.mdiArea.currentSubWindow() is not None: - self.UIInitDocument(self.window.mdiArea.currentSubWindow().doc) - self.UIInitStyle(self.window.mdiArea.currentSubWindow().style) + qFont = self.psetup.widget().fontComboBox.currentFont() + qFontReal = QRawFont.fromFont(qFont) + #fontInfo = QFontInfo(qFont) + #qFontReal = QRawFont(fontInfo.family()) + print(qFont.rawName()) + + + def switchDocument(self, curWindow): + if curWindow is not None: + if self.lastSubWindow is not None: + self.lastSubWindow.currentSection = self.currentSection + + self.UIInitDocument(curWindow.doc) + self.UIInitStyle(curWindow.style) + self.currentSection = curWindow.currentSection + if self.currentSection is not None: + self.blocksw.widget().blockSectionComboBox.setCurrentText( + self.currentSection.name) + self.lastSubWindow = curWindow def generateAction(self): if self.window.mdiArea.currentSubWindow() is not None: @@ -287,7 +327,7 @@ class MainWindow(QMainWindow): b.chord = None self.blocksw.widget().blockTableView.populate(self.currentSection.blockList) self.clearChordLineEdits() - self.window.mdiArea.currentSubWindow().updateChordDict() + self.updateChordDict(self.window.mdiArea.currentSubWindow().doc) def addChordAction(self): success = False # initialise @@ -319,7 +359,7 @@ class MainWindow(QMainWindow): if success == True: # if chord was parsed properly self.chordsw.widget().chordTableView.populate(self.window.mdiArea.currentSubWindow().doc.chordList) self.clearChordLineEdits() - self.window.mdiArea.currentSubWindow().updateChordDict() + self.updateChordDict(self.window.mdiArea.currentSubWindow().doc) def updateChordAction(self): success = False # see comments above @@ -351,7 +391,7 @@ class MainWindow(QMainWindow): ChordNameWarningMessageBox().exec() if success == True: - self.window.mdiArea.currentSubWindow().updateChordDict() + self.updateChordDict(self.window.mdiArea.currentSubWindow().doc) self.chordsw.widget().chordTableView.populate(self.window.mdiArea.currentSubWindow().doc.chordList) # update the names of chords in all blocklists in case they've already been used for s in self.window.mdiArea.currentSubWindow().doc.sectionList: @@ -372,7 +412,7 @@ class MainWindow(QMainWindow): self.sectionsw.widget().sectionTableView.populate(self.window.mdiArea.currentSubWindow().doc.sectionList) self.clearSectionLineEdits() - self.window.mdiArea.currentSubWindow().updateSectionDict() + self.updateSectionDict(self.window.mdiArea.currentSubWindow().doc) def addSectionAction(self): self.window.mdiArea.currentSubWindow().updateSections() @@ -382,7 +422,7 @@ class MainWindow(QMainWindow): self.window.mdiArea.currentSubWindow().doc.sectionList.append(Section(name=sName)) self.sectionsw.widget().sectionTableView.populate(self.window.mdiArea.currentSubWindow().doc.sectionList) self.clearSectionLineEdits() - self.window.mdiArea.currentSubWindow().updateSectionDict() + self.updateSectionDict(self.window.mdiArea.currentSubWindow().doc) else: # Section has no name or non unique, warn user SectionNameWarningMessageBox().exec() @@ -397,7 +437,7 @@ class MainWindow(QMainWindow): self.window.mdiArea.currentSubWindow().doc.sectionList[row].name = sName self.sectionsw.widget().sectionTableView.populate(self.window.mdiArea.currentSubWindow().doc.sectionList) self.clearSectionLineEdits() - self.window.mdiArea.currentSubWindow().updateSectionDict() + self.updateSectionDict(self.window.mdiArea.currentSubWindow().doc) else: # Section has no name or non unique, warn user SectionNameWarningMessageBox().exec() @@ -495,10 +535,11 @@ class MainWindow(QMainWindow): if sName: if self.window.mdiArea.currentSubWindow() is not None: self.currentSection = self.sectionDict.get(sName, None) + # self.window.mdiArea.currentSubWindow().currentSection = self.currentSection if self.currentSection is not None: self.blocksw.widget().blockTableView.populate(self.currentSection.blockList) else: - self.currentSection = None + pass # self.currentSection = None def blockClickedAction(self, index): # set the controls to the values from the selected block @@ -537,7 +578,7 @@ class MainWindow(QMainWindow): self.window.mdiArea.addSubWindow(dw) self.UIInitDocument(dw.doc) self.UIInitStyle(dw.style) - self.currentSection = None + # self.currentSection = None dw.show() @@ -618,6 +659,54 @@ class MainWindow(QMainWindow): except Exception: pass + + # self.docinfo = DocInfoDockWidget() + # self.psetup = PageSetupDockWidget() + # self.chordsw = ChordsDockWidget() + # self.sectionsw = SectionsDockWidget() + # self.blocksw = BlocksDockWidget() + # self.previeww = PreviewDockWidget() + + def menuWindowDocInfoAction(self): + if self.window.actionDocument_information.isChecked(): + self.docinfo.show() + else: + self.docinfo.hide() + + def menuWindowPageSetupAction(self): + if self.window.actionPage_setup.isChecked(): + self.psetup.show() + else: + self.psetup.hide() + + def menuWindowChordsAction(self): + if self.window.actionChords.isChecked(): + self.chordsw.show() + else: + self.chordsw.hide() + + + def menuWindowSectionsAction(self): + if self.window.actionSections.isChecked(): + self.sectionsw.show() + else: + self.sectionsw.hide() + + + def menuWindowBlocksAction(self): + if self.window.actionBlocks.isChecked(): + self.blocksw.show() + else: + self.blocksw.hide() + + + def menuWindowPreviewAction(self): + if self.window.actionPreview.isChecked(): + self.previeww.show() + else: + self.previeww.hide() + + def guitarVoicingAction(self): gdialog = GuitarDialog() @@ -666,9 +755,10 @@ class DocumentWindow(QMdiSubWindow): self.lastDoc = copy(self.doc) self.currentFilePath = filename + self.currentSection = None + mw.updateChordDict(self.doc) mw.updateSectionDict(self.doc) - self.currentSection = None def UIFileLoader(self, ui_file): ui_file = QFile(ui_file) @@ -696,13 +786,17 @@ class DocumentWindow(QMdiSubWindow): else: # if fileExt in [".xml", ".cml"]: self.doc.loadXML(self.currentFilePath) + self.updatePreview() + self.lastDoc = copy(self.doc) mw.setPath("workingPath", self.currentFilePath) mw.updateChordDict(self.doc) mw.updateSectionDict(self.doc) + + self.currentSection = (self.doc.sectionList[0] if self.doc.sectionList else None) + self.updateTitleBar() - self.updatePreview() def saveFile(self, filePath): """ diff --git a/preview.pdf b/preview.pdf index b51a7e93b53f0120accccce4066996b2d34af76c..e946d380a29238f2cb1782bce30714ad7473f321 100644 GIT binary patch delta 10000 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

vV~t5~W$acS+|#w?ZQf{7~_&9luBqZ`ty!_V=bg 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 R*E%DaDDk6E_%ga5{{oqSOi%y- diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6971249 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +reportlab>=3.5.67 +PyMuPDF>=1.18.13 +PyQt5>=5.15.4 diff --git a/ui/blocks.ui b/ui/blocks.ui index 82ab355..5040468 100644 --- a/ui/blocks.ui +++ b/ui/blocks.ui @@ -6,193 +6,261 @@ 0 0 - 437 - 371 + 387 + 206 Blocks - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - - - QFormLayout::ExpandingFieldsGrow - - - - - Section - - - - - - - - 0 - 0 - - - - - + + + QFormLayout::ExpandingFieldsGrow + + + 6 + + + 6 + + + 6 + + + 6 + + + + + Section + + - - + + - + 0 0 - - QAbstractItemView::NoEditTriggers + + + + + + + + + 0 + 0 + + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + QAbstractItemView::InternalMove + + + Qt::TargetMoveAction + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + false + + + + + + + 6 + + + 6 + + + 6 + + + 6 + + + 6 + + + + + Length - - true + + + + + + + + + + 0 + 0 + - - false + + Notes - - QAbstractItemView::InternalMove + + + + + + Chord - - Qt::TargetMoveAction + + + + + + + 0 + 0 + + + + + 40 + 16777215 + + + + + + + + + 0 + 0 + - - QAbstractItemView::SingleSelection + + + + + + Qt::Horizontal - - QAbstractItemView::SelectRows + + QSizePolicy::MinimumExpanding - - false + + + 40 + 20 + - - false + + + + + + + + 6 + + + 6 + + + 0 + + + 6 + + + 6 + + + + + Remove block - - - - - Length - - - - - - - - - - - 0 - 0 - - - - Notes - - - - - - - Chord - - - - - - - - 0 - 0 - - - - - 40 - 16777215 - - - - - - - - - 0 - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::MinimumExpanding - - - - 40 - 20 - - - - - + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 40 + 20 + + + + + + + + Update block + + - - - - - Remove block - - - - - - - Qt::Horizontal - - - QSizePolicy::MinimumExpanding - - - - 40 - 20 - - - - - - - - Update block - - - - - - - Add block - - - - + + + true + + + Add block + + + false + + + false + + + false + + + false + + @@ -211,8 +279,6 @@ - blockSectionComboBox - blockTableView blockLengthLineEdit blockChordComboBox blockNotesLineEdit diff --git a/ui/chords.ui b/ui/chords.ui index 7f64fe4..40a4f67 100644 --- a/ui/chords.ui +++ b/ui/chords.ui @@ -6,65 +6,91 @@ 0 0 - 443 - 359 + 393 + 236 Chords - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - - - - 0 - 0 - - - - QAbstractItemView::NoEditTriggers - - - true - - - false - - - QAbstractItemView::InternalMove - - - Qt::IgnoreAction - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - false - - - false - - - false - - - + + + + 0 + 0 + + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + QAbstractItemView::InternalMove + + + Qt::IgnoreAction + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + false + + + false + + + + + + + 6 + + + 6 + + + 6 + + + 6 + + + 6 + - - - - Chord name - - - + + 6 + @@ -82,6 +108,9 @@ + + + @@ -98,22 +127,6 @@ - - - - - 16777215 - 16777215 - - - - Editor... - - - - - - @@ -121,44 +134,23 @@ - - - - - - + + - Remove chord + Chord name - - - - Qt::Horizontal - - - QSizePolicy::MinimumExpanding - - + + + - 40 - 20 + 16777215 + 16777215 - - - - - - Update chord - - - - - - Add chord + Editor... @@ -166,6 +158,62 @@ + + + + 6 + + + 6 + + + 0 + + + 6 + + + 6 + + + + + Remove chord + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 40 + 20 + + + + + + + + Update chord + + + + + + + Add chord + + + + + @@ -176,7 +224,6 @@ - chordTableView chordNameLineEdit guitarVoicingLineEdit guitarVoicingButton diff --git a/ui/docinfo.ui b/ui/docinfo.ui index 3f5b625..3c03418 100644 --- a/ui/docinfo.ui +++ b/ui/docinfo.ui @@ -9,8 +9,8 @@ 0 0 - 400 - 202 + 291 + 170 @@ -23,11 +23,29 @@ Document information + + 6 + + + 6 + + + 6 + + + 6 + QFormLayout::ExpandingFieldsGrow + + 6 + + + 6 + diff --git a/ui/document.ui b/ui/document.ui index 9ed6722..3577480 100644 --- a/ui/document.ui +++ b/ui/document.ui @@ -11,7 +11,7 @@ - Form + Unsaved diff --git a/ui/new.ui b/ui/new.ui index 60a8b94..eb82610 100644 --- a/ui/new.ui +++ b/ui/new.ui @@ -7,7 +7,7 @@ 0 0 1061 - 659 + 639 @@ -88,8 +88,21 @@ + + + Window + + + + + + + + + + @@ -166,6 +179,54 @@ About + + + true + + + Document information + + + + + true + + + Page setup + + + + + true + + + Chords + + + + + true + + + Sections + + + + + true + + + Blocks + + + + + true + + + Preview + + diff --git a/ui/preview.ui b/ui/preview.ui index 24e543a..712ac9d 100644 --- a/ui/preview.ui +++ b/ui/preview.ui @@ -6,7 +6,7 @@ 0 0 - 400 + 248 40 @@ -25,7 +25,10 @@ Preview - + + + 6 + 0 @@ -40,6 +43,12 @@ + + + 0 + 0 + + Update preview diff --git a/ui/psetup.ui b/ui/psetup.ui index 5ca2c8e..75ec37d 100644 --- a/ui/psetup.ui +++ b/ui/psetup.ui @@ -6,12 +6,12 @@ 0 0 - 400 - 500 + 257 + 271 - + 0 0 @@ -20,239 +20,262 @@ Page setup + + 6 + + + 6 + + + 6 + + + 6 + - - - - 0 - 0 - + + + 6 - - Page options - - - - - - - - Page size - - - - - - - - - - Document units - - - - - - - - - - Left margin - - - - - - - - 60 - 16777215 - - - - - - - - Top margin - - - - - - - - 60 - 16777215 - - - - - - - - Right margin - - - - - - - - 60 - 16777215 - - - - - - - - Bottom margin - - - - - - - - 60 - 16777215 - - - - - - - - - - - - - - 0 - 0 - - - - Font options - - - - - - - - - 40 - 16777215 - - - - Font - - - - - - - - 0 - 0 - - - - - - - - - - Use included FreeSans - - - - - - - - - - - 0 - 0 - - - - Text options - - - - - - - - Line spacing - - - - - - - - 70 - 0 - - - - - 70 - 16777215 - - - - - - - - - - - - - - 0 - 0 - - - - Block options - - - - - - - - Beat width - - - - - - - - 60 - 16777215 - - - - - - - - + + + + + 0 + 0 + + + + Line spacing + + + + + + + + 60 + 16777215 + + + + + + + + + 40 + 16777215 + + + + Font + + + + + + + + 60 + 16777215 + + + + + + + + + 60 + 16777215 + + + + + + + + + 70 + 0 + + + + + 70 + 16777215 + + + + + + + + + 60 + 16777215 + + + + + + + + + 70 + 26 + + + + true + + + true + + + + + + + + 0 + 0 + + + + + 16777215 + 16777194 + + + + Top margin + + + + + + + + 60 + 16777215 + + + + + + + + Page size + + + + + + + Units + + + + + + + + 0 + 0 + + + + Bottom margin + + + + + + + + 0 + 0 + + + + Left margin + + + + + + + + 0 + 0 + + + + Use FreeSans + + + true + + + + + + + + 0 + 0 + + + + Beat width + + + + + + + + 0 + 0 + + + + Right margin + + + + + + + true + + + + 70 + 26 + + + + true + + + true + + + + + + + + 16777215 + 26 + + + + + @@ -263,9 +286,9 @@ rightMarginLineEdit topMarginLineEdit bottomMarginLineEdit - lineSpacingDoubleSpinBox fontComboBox includedFontCheckBox + lineSpacingDoubleSpinBox beatWidthLineEdit diff --git a/ui/sections.ui b/ui/sections.ui index 9280c89..80d35d2 100644 --- a/ui/sections.ui +++ b/ui/sections.ui @@ -6,110 +6,148 @@ 0 0 - 431 - 325 + 405 + 170 Sections - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - - - - 0 - 0 - - - - QAbstractItemView::NoEditTriggers - - - true - - - false - - - QAbstractItemView::InternalMove - - - Qt::TargetMoveAction + + + + 0 + 0 + + + + QAbstractItemView::NoEditTriggers + + + true + + + false + + + QAbstractItemView::InternalMove + + + Qt::TargetMoveAction + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + false + + + false + + + + + + + QFormLayout::ExpandingFieldsGrow + + + 6 + + + 6 + + + 6 + + + 6 + + + 6 + + + + + Name - - QAbstractItemView::SingleSelection + + + + + + + + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + Remove section - - QAbstractItemView::SelectRows + + + + + + Qt::Horizontal - - false + + QSizePolicy::MinimumExpanding - - false + + + 0 + 20 + - + - - - QFormLayout::ExpandingFieldsGrow + + + Update section - - - - Name - - - - - - - + - - - - - Remove section - - - - - - - Qt::Horizontal - - - QSizePolicy::MinimumExpanding - - - - 0 - 20 - - - - - - - - Update section - - - - - - - Add section - - - - + + + Add section + +