Compare commits

..

9 Commits

3 changed files with 54 additions and 234 deletions

View File

@ -2,40 +2,25 @@
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets
from chordpro.renderers.html import get_options, get_option_groups
from ukatali.util import coerce_bool, convert_units
SUPPORTED_SIZES = {
QtGui.QPageSize.A4: 'A4',
QtGui.QPageSize.A5: 'A5',
QtGui.QPageSize.B5: 'B5',
QtGui.QPageSize.B6: 'B6',
QtGui.QPageSize.Letter: 'Letter',
QtGui.QPageSize.Legal: 'Legal',
QtGui.QPageSize.ExecutiveStandard: 'Executive'
}
SUPPORTED_UNITS = {
QtGui.QPageSize.Millimeter: 'mm',
QtGui.QPageSize.Point: 'pt',
QtGui.QPageSize.Inch: 'in'
}
SUPPORTED_ORIENTATIONS = {
'Portrait': QtGui.QPageLayout.Portrait,
'Landscape': QtGui.QPageLayout.Landscape
}
def _coerce_bool(value):
"""Coerce a value to be a boolean"""
if isinstance(value, str):
return value[0].lower() in ['t', 'y', '1']
else:
return bool(value)
class ConfigureDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.settings = QtCore.QSettings()
self.option_widgets = {}
self.option_values = {}
self.editor_values = {}
self.export_values = {}
self.setup_ui()
self.setup_options()
self.editor_values = {}
def setup_ui(self):
self.setObjectName('ConfigureDialog')
@ -47,7 +32,7 @@ class ConfigureDialog(QtWidgets.QDialog):
self.configure_layout.addLayout(self.category_layout)
self.category_list_widget = QtWidgets.QListWidget(self)
self.category_list_widget.setFixedWidth(100)
self.category_list_widget.addItems(['', '', '', ''])
self.category_list_widget.addItems(['', '', ''])
self.category_list_widget.setObjectName('category_list_widget')
self.category_layout.addWidget(self.category_list_widget)
self.category_stack = QtWidgets.QStackedWidget(self)
@ -83,56 +68,6 @@ class ConfigureDialog(QtWidgets.QDialog):
self.render_options_stack = QtWidgets.QStackedWidget(self)
self.render_options_stack.setObjectName("render_options_stack")
self.render_layout.addWidget(self.render_options_stack)
# Export settings
self.export_page = QtWidgets.QWidget()
self.export_page.setObjectName('export_page')
self.category_stack.addWidget(self.export_page)
self.export_layout = QtWidgets.QFormLayout(self.export_page)
self.export_layout.setObjectName('export_layout')
self.export_size_combobox = QtWidgets.QComboBox(self.export_page)
for idx, (size_id, size_name) in enumerate(SUPPORTED_SIZES.items()):
self.export_size_combobox.addItem(size_name)
self.export_size_combobox.setItemData(idx, size_id)
self.export_size_combobox.setCurrentIndex(0)
self.export_size_combobox.setObjectName('export_size_combobox')
self.export_layout.addRow('Page size', self.export_size_combobox)
self.export_orientation_layout = QtWidgets.QHBoxLayout()
self.export_orientation_layout.setObjectName('export_orientation_layout')
self.export_orientation_portrait_radio = QtWidgets.QRadioButton(self.export_page)
self.export_orientation_portrait_radio.setChecked(True)
self.export_orientation_portrait_radio.setObjectName('export_orientation_portrait_radio')
self.export_orientation_layout.addWidget(self.export_orientation_portrait_radio)
self.export_orientation_landscape_radio = QtWidgets.QRadioButton(self.export_page)
self.export_orientation_landscape_radio.setObjectName('export_orientation_landscape_radio')
self.export_orientation_layout.addWidget(self.export_orientation_landscape_radio)
self.export_layout.addRow('Orientation', self.export_orientation_layout)
self.export_unit_combobox = QtWidgets.QComboBox(self.export_page)
for idx, (unit_id, unit_name) in enumerate(SUPPORTED_UNITS.items()):
self.export_unit_combobox.addItem(unit_name)
self.export_unit_combobox.setItemData(idx, unit_id)
self.export_unit_combobox.setCurrentIndex(0)
self.export_unit_combobox.setObjectName('export_unit_combobox')
self.export_layout.addRow('Unit', self.export_unit_combobox)
self.export_margin_top_spinbox = QtWidgets.QDoubleSpinBox(self.export_page)
self.export_margin_top_spinbox.setValue(20)
self.export_margin_top_spinbox.setSuffix(self.export_unit_combobox.currentText())
self.export_margin_top_spinbox.setObjectName('export_margin_top_spinbox')
self.export_layout.addRow('Top margin', self.export_margin_top_spinbox)
self.export_margin_left_spinbox = QtWidgets.QDoubleSpinBox(self.export_page)
self.export_margin_left_spinbox.setValue(20)
self.export_margin_left_spinbox.setSuffix(self.export_unit_combobox.currentText())
self.export_margin_left_spinbox.setObjectName('export_margin_left_spinbox')
self.export_layout.addRow('Left margin', self.export_margin_left_spinbox)
self.export_margin_right_spinbox = QtWidgets.QDoubleSpinBox(self.export_page)
self.export_margin_right_spinbox.setValue(20)
self.export_margin_right_spinbox.setSuffix(self.export_unit_combobox.currentText())
self.export_margin_right_spinbox.setObjectName('export_margin_right_spinbox')
self.export_layout.addRow('Right margin', self.export_margin_right_spinbox)
self.export_margin_bottom_spinbox = QtWidgets.QDoubleSpinBox(self.export_page)
self.export_margin_bottom_spinbox.setValue(20)
self.export_margin_bottom_spinbox.setSuffix(self.export_unit_combobox.currentText())
self.export_margin_bottom_spinbox.setObjectName('export_margin_bottom_spinbox')
self.export_layout.addRow('Bottom margin', self.export_margin_bottom_spinbox)
# Buttons
self.button_box = QtWidgets.QDialogButtonBox(self)
self.button_box.setOrientation(QtCore.Qt.Horizontal)
@ -146,23 +81,8 @@ class ConfigureDialog(QtWidgets.QDialog):
self.button_box.rejected.connect(self.reject)
self.category_list_widget.currentRowChanged.connect(self.category_stack.setCurrentIndex)
self.render_options_combobox.activated.connect(self.render_options_stack.setCurrentIndex)
on_editor_font_changed = partial(self._set_editor_value, 'font')
self.editor_font_combobox.currentFontChanged.connect(on_editor_font_changed)
on_editor_size_changed = partial(self._set_editor_value, 'size')
self.editor_size_spinbox.valueChanged.connect(on_editor_size_changed)
on_export_size_changed = partial(self._set_export_value, 'page_size')
self.export_size_combobox.currentIndexChanged.connect(on_export_size_changed)
self.export_unit_combobox.currentIndexChanged.connect(self.on_export_unit_changed)
on_export_margin_left_changed = partial(self._set_export_value, 'margin_left')
self.export_margin_left_spinbox.valueChanged.connect(on_export_margin_left_changed)
on_export_margin_right_changed = partial(self._set_export_value, 'margin_right')
self.export_margin_right_spinbox.valueChanged.connect(on_export_margin_right_changed)
on_export_margin_top_changed = partial(self._set_export_value, 'margin_top')
self.export_margin_top_spinbox.valueChanged.connect(on_export_margin_top_changed)
on_export_margin_bottom_changed = partial(self._set_export_value, 'margin_bottom')
self.export_margin_bottom_spinbox.valueChanged.connect(on_export_margin_bottom_changed)
on_export_orientation_portait_clicked = partial(self._set_export_value, 'orientation')
self.export_orientation_portrait_radio.toggled.connect(on_export_orientation_portait_clicked)
self.editor_font_combobox.currentFontChanged.connect(self.on_editor_font_changed)
self.editor_size_spinbox.valueChanged.connect(self.on_editor_size_changed)
def retranslate_ui(self):
_translate = QtCore.QCoreApplication.translate
@ -170,29 +90,14 @@ class ConfigureDialog(QtWidgets.QDialog):
self.category_list_widget.item(0).setText(_translate('ConfigureDialog', 'General'))
self.category_list_widget.item(1).setText(_translate('ConfigureDialog', 'Editor'))
self.category_list_widget.item(2).setText(_translate('ConfigureDialog', 'Render'))
self.category_list_widget.item(3).setText(_translate('ConfigureDialog', 'PDF'))
self.export_orientation_portrait_radio.setText(_translate('ConfigureDialog', 'Portrait'))
self.export_orientation_landscape_radio.setText(_translate('ConfigureDialog', 'Landscape'))
def _set_option_value(self, name, value):
def _set_value(self, name, value):
"""Set an option value"""
self.option_values[name] = value
def _set_editor_value(self, name, value):
"""Set an editor value"""
self.editor_values[name] = value
def _set_export_value(self, name, value):
"""Set an export value"""
if name == 'page_size':
value = self.export_size_combobox.itemData(value)
elif name == 'units':
value = self.export_unit_combobox.itemData(value)
elif name == 'orientation':
value = QtGui.QPageLayout.Portrait if value else QtGui.QPageLayout.Landscape
self.export_values[name] = value
def setup_options(self):
self.option_widgets = {}
self.option_values = {}
for group in get_option_groups():
pretty_group = group.replace('_', ' ').title()
self.render_options_combobox.addItem(pretty_group)
@ -202,7 +107,7 @@ class ConfigureDialog(QtWidgets.QDialog):
pretty_name = name.replace(group, '').replace('_', ' ').title()
self.option_values[name] = details['default']
widget = None
set_value = partial(self._set_option_value, name)
set_value = partial(self._set_value, name)
if details["type"] is int:
widget = QtWidgets.QSpinBox(page_widget)
if details['default']:
@ -210,7 +115,7 @@ class ConfigureDialog(QtWidgets.QDialog):
widget.valueChanged.connect(set_value)
elif details["type"] is bool:
widget = QtWidgets.QCheckBox(page_widget)
widget.setChecked(coerce_bool(details['default']))
widget.setChecked(_coerce_bool(details['default']))
widget.toggled.connect(set_value)
elif 'font' in name:
widget = QtWidgets.QFontComboBox(page_widget)
@ -237,13 +142,13 @@ class ConfigureDialog(QtWidgets.QDialog):
# Editor settings
self.settings.beginGroup('editor')
if self.settings.contains('font'):
value = QtGui.QFont(self.settings.value('font'))
value = self.settings.value('font')
self.editor_values['font'] = value
self.editor_font_combobox.setCurrentFont(value)
self.editor_font_combobox.setCurrentFont(QtGui.QFont(value))
if self.settings.contains('size'):
value = int(self.settings.value('size'))
self.editor_values['size'] = value
self.editor_size.setValue(value)
value = self.settings.value('size')
self.editor_values['size'] = int(value)
self.editor_size.setValue(int(value))
self.settings.endGroup()
# Renderer settings
self.settings.beginGroup('render')
@ -256,7 +161,7 @@ class ConfigureDialog(QtWidgets.QDialog):
value = int(value)
self.option_widgets[name].setValue(value)
elif details['type'] is bool:
value = coerce_bool(value)
value = _coerce_bool(value)
self.option_widgets[name].setChecked(value)
elif 'font' in name:
value = QtGui.QFont(value)
@ -265,32 +170,6 @@ class ConfigureDialog(QtWidgets.QDialog):
self.option_widgets[name].setText(value)
self.option_values[name] = value
self.settings.endGroup()
# PDF settings
self.settings.beginGroup('export')
if self.settings.contains('page_size'):
value = int(self.settings.value('page_size'))
self.export_values['page_size'] = value
self.export_size_combobox.setCurrentText(SUPPORTED_SIZES[value])
if self.settings.contains('unit'):
value = int(self.settings.value('unit'))
self.export_values['unit'] = value
self.export_unit_combobox.setCurrentText(SUPPORTED_UNITS[value])
if self.settings.contains('orientation'):
value = int(self.settings.value('orientation'))
self.export_values['orientation'] = value
self.export_orientation_portrait_radio.setChecked(value == QtGui.QPageLayout.Portrait)
margins = [
('margin_left', self.export_margin_left_spinbox),
('margin_right', self.export_margin_right_spinbox),
('margin_top', self.export_margin_top_spinbox),
('margin_bottom', self.export_margin_bottom_spinbox),
]
for name, spinbox in margins:
if self.settings.contains(name):
value = float(self.settings.value(name))
self.export_values[name] = value
spinbox.setValue(value)
self.settings.endGroup()
def save_settings(self):
"""Save the settings"""
@ -308,11 +187,6 @@ class ConfigureDialog(QtWidgets.QDialog):
value = value.family()
self.settings.setValue(name, value)
self.settings.endGroup()
# Export settings
self.settings.beginGroup('export')
for name, value in self.export_values.items():
self.settings.setValue(name, value)
self.settings.endGroup()
def exec(self):
"""Execute the dialog"""
@ -324,15 +198,10 @@ class ConfigureDialog(QtWidgets.QDialog):
self.save_settings()
return super().accept()
def on_export_unit_changed(self, value):
self._set_export_value('unit', self.export_unit_combobox.itemData(value))
new_suffix = self.export_unit_combobox.itemText(value)
for spinbox in [self.export_margin_bottom_spinbox, self.export_margin_left_spinbox,
self.export_margin_right_spinbox, self.export_margin_top_spinbox]:
old_suffix = spinbox.suffix()
spinbox.setSuffix(new_suffix)
spinbox.setValue(convert_units(spinbox.value(), old_suffix, new_suffix))
if new_suffix == 'in':
spinbox.setSingleStep(0.1)
else:
spinbox.setSingleStep(1.0)
def on_editor_font_changed(self, font):
"""Set the new font if the font has changed"""
self.editor_values['font'] = font.family()
def on_editor_size_changed(self, size):
"""Set the new size if the size has changed"""
self.editor_values['size'] = size

View File

@ -1,14 +1,11 @@
# -*- coding: utf-8 -*-
import os
from pathlib import Path
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets, Qsci, QtPrintSupport
from chordpro import Song
from chordpro.renderers.html import render, get_options
from chordpro import Song
from chordpro.renderers.html import render
from ukatali.configuredialog import ConfigureDialog
from ukatali.lexer import ChordProLexer
from ukatali.util import coerce_bool
CHORDPRO_FILTERS = 'ChordPro files (*.txt *.cho *.chordpro *.chopro);;All files (*)'
@ -17,7 +14,6 @@ class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setup_ui()
self.settings = QtCore.QSettings()
self.filename = None
self.configure_dialog = ConfigureDialog(self)
@ -237,8 +233,8 @@ class MainWindow(QtWidgets.QMainWindow):
def on_open_clicked(self):
"""Open the file"""
if self.settings.value('files/last-directory'):
last_directory = self.settings.value('files/last-directory')
if QtCore.QSettings().value('files/last-directory'):
last_directory = QtCore.QSettings().value('files/last-directory')
else:
last_directory = ''
filename = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', last_directory, filter=CHORDPRO_FILTERS)
@ -250,7 +246,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.filename = filename
file_path = Path(filename)
if file_path.exists():
self.settings.setValue('files/last-directory', str(file_path.parent))
QtCore.QSettings().setValue('files/last-directory', str(file_path.parent))
self.file_editor.setText(file_path.open().read())
def on_save_clicked(self):
@ -263,8 +259,8 @@ class MainWindow(QtWidgets.QMainWindow):
def on_save_as_clicked(self):
"""Save the file"""
if self.settings.value('files/last-directory'):
last_directory = self.settings.value('files/last-directory')
if QtCore.QSettings().value('files/last-directory'):
last_directory = QtCore.QSettings().value('files/last-directory')
else:
last_directory = ''
filename = QtWidgets.QFileDialog.getSaveFileName(self, 'Save file', last_directory, filter=CHORDPRO_FILTERS)
@ -274,29 +270,24 @@ class MainWindow(QtWidgets.QMainWindow):
return
self.filename = filename
self.settings.setValue('files/last-directory', str(Path(filename).parent))
QtCore.QSettings().setValue('files/last-directory', str(Path(filename).parent))
self.on_save_clicked()
def on_configure_clicked(self):
"""Show the configuration dialog"""
if self.configure_dialog.exec() == QtWidgets.QDialog.Accepted and self.file_editor.text():
if self.configure_dialog.exec() == QtWidgets.QDialog.Accepted:
self.on_text_changed()
def _get_render_options(self):
"""Get all the render options from the settings"""
options = {}
self.settings.beginGroup('render')
for name, details in get_options().items():
if self.settings.contains(name):
value = self.settings.value(name)
if value is None:
continue
if details['type'] is int:
value = int(value)
elif details['type'] is bool:
value = coerce_bool(value)
options[name] = value
self.settings.endGroup()
settings = QtCore.QSettings()
settings.beginGroup('render')
for key in settings.allKeys():
value = settings.value(key)
if value:
options[key] = value
settings.endGroup()
return options
def _render_song(self, extra_styles=None):
@ -305,10 +296,6 @@ class MainWindow(QtWidgets.QMainWindow):
text = self.file_editor.text()
song = Song()
song.parse(text)
if song.metadata.get('copyright'):
extra_styles = extra_styles or ''
extra_styles += os.linesep
extra_styles += '@page {{ @bottom-left {{ content: "{}"; }} }}'.format(song.metadata.get('copyright'))
return render(song, options, extra_styles)
def on_text_changed(self):
@ -320,8 +307,8 @@ class MainWindow(QtWidgets.QMainWindow):
"""Export the current song to PDF"""
if self.filename:
last_directory = str(Path(self.filename).with_suffix('.pdf'))
elif self.settings.value('files/last-directory'):
last_directory = self.settings.value('files/last-directory')
elif QtCore.QSettings().value('files/last-directory'):
last_directory = QtCore.QSettings().value('files/last-directory')
else:
last_directory = ''
filename = QtWidgets.QFileDialog.getSaveFileName(self, 'Export to PDF', last_directory,
@ -331,21 +318,10 @@ class MainWindow(QtWidgets.QMainWindow):
if not filename:
return
filename = Path(filename)
self.settings.setValue('files/last-directory', str(filename.parent))
# Load the page layout from settings
self.settings.beginGroup('export')
page_size = QtGui.QPageSize(int(self.settings.value('page_size', QtGui.QPageSize.A4)))
orientation = int(self.settings.value('orientation', QtGui.QPageLayout.Portrait))
unit = int(self.settings.value('unit', QtGui.QPageLayout.Millimeter))
margin_left = float(self.settings.value('margin_left', 20))
margin_right = float(self.settings.value('margin_right', 20))
margin_top = float(self.settings.value('margin_top', 20))
margin_bottom = float(self.settings.value('margin_bottom', 20))
self.settings.endGroup()
margins = QtCore.QMarginsF(QtCore.QMargins(margin_left, margin_top, margin_right, margin_bottom))
page_layout = QtGui.QPageLayout(page_size, orientation, margins, unit)
# Export to PDF
self.preview_view.page().printToPdf(str(filename), page_layout)
QtCore.QSettings().setValue('files/last-directory', str(filename.parent))
self.preview_view.page().printToPdf(str(filename), QtGui.QPageLayout(QtGui.QPageSize(QtGui.QPageSize.Letter),
QtGui.QPageLayout.Portrait,
QtCore.QMarginsF()))
def on_pdf_finished(self, filename, is_success):
"""A slot to notify the user when the PDF is done"""
@ -364,7 +340,7 @@ class MainWindow(QtWidgets.QMainWindow):
# print(QtPrintSupport.QPrinterInfo.defaultPrinterName())
# default_printer = QtPrintSupport.QPrinterInfo.defaultPrinter()
# print(default_printer)
printer = QtPrintSupport.QPrinter()
print_dialog = QtPrintSupport.QPrintDialog(printer, self.preview_view.page().view())
# printer = QtPrintSupport.QPrinter()
print_dialog = QtPrintSupport.QPrintDialog(QtPrintSupport.QPrinter(), self)
if print_dialog.exec() == QtWidgets.QDialog.Accepted:
self.preview_view.page().print(printer, _on_print_finished)
self.preview_view.page().print(print_dialog.printer(), _on_print_finished)

View File

@ -1,25 +0,0 @@
def coerce_bool(value):
"""Coerce a value to be a boolean"""
if isinstance(value, str):
return value[0].lower() in ['t', 'y', '1']
else:
return bool(value)
def convert_units(value, old_unit, new_unit):
"""Convert a value from one unit to another"""
if old_unit == 'in' and new_unit == 'mm':
return value * 25.4
if old_unit == 'mm' and new_unit == 'in':
return value / 25.4
if old_unit == 'in' and new_unit == 'pt':
return value * 72.0
if old_unit == 'pt' and new_unit == 'in':
return value / 72.0
if old_unit == 'mm' and new_unit == 'pt':
# Convert to in and then to pt
return (value / 25.4) * 72.0
if old_unit == 'pt' and new_unit == 'mm':
# Convert to in and then to mm
return (value / 72.0) * 25.4
return value