205 lines
7.9 KiB
Python
Executable File
205 lines
7.9 KiB
Python
Executable File
# This script is licensed CC 0 1.0, so that you can learn from it.
|
|
|
|
# ------ CC 0 1.0 ---------------
|
|
|
|
# The person who associated a work with this deed has dedicated the
|
|
# work to the public domain by waiving all of his or her rights to the
|
|
# work worldwide under copyright law, including all related and
|
|
# neighboring rights, to the extent allowed by law.
|
|
|
|
# You can copy, modify, distribute and perform the work, even for
|
|
# commercial purposes, all without asking permission.
|
|
|
|
# https://creativecommons.org/publicdomain/zero/1.0/legalcode
|
|
|
|
import krita
|
|
from . import documenttoolsdialog
|
|
from . import SpineExport
|
|
|
|
from PyQt5.QtCore import Qt, pyqtSignal, QObject, QByteArray
|
|
from PyQt5.QtWidgets import (QFormLayout, QListWidget, QAbstractItemView, QLineEdit, QFileDialog, QLabel,
|
|
QDialogButtonBox, QVBoxLayout, QFrame, QTabWidget, QSpinBox,
|
|
QPushButton, QAbstractScrollArea, QMessageBox, QHBoxLayout, QCheckBox)
|
|
import os
|
|
import krita
|
|
import importlib
|
|
import json
|
|
|
|
|
|
class UIDocumentTools(object):
|
|
|
|
def __init__(self):
|
|
self.mainDialog = documenttoolsdialog.DocumentToolsDialog()
|
|
self.spineExport = SpineExport.SpineExport()
|
|
self.mainLayout = QVBoxLayout(self.mainDialog)
|
|
self.formLayout = QFormLayout()
|
|
self.documentLayout = QVBoxLayout()
|
|
self.refreshButton = QPushButton(i18n("Refresh"))
|
|
self.widgetDocuments = QListWidget()
|
|
self.tabTools = QTabWidget()
|
|
self.buttonBox = QDialogButtonBox(
|
|
QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
|
self.outputField = QLabel()
|
|
|
|
# Output directory
|
|
self.directorySelectorLayout = QHBoxLayout()
|
|
self.directoryTextField = QLineEdit()
|
|
self.directoryDialogButton = QPushButton(i18n("..."))
|
|
|
|
# Bone length
|
|
self.boneLengthField = QSpinBox()
|
|
self.boneLengthField.setRange(0, 100)
|
|
|
|
self.includeHiddenCheckbox = QCheckBox(i18n("Include Hidden Layers"))
|
|
|
|
self.kritaInstance = krita.Krita.instance()
|
|
self.documentsList = []
|
|
|
|
self.refreshButton.clicked.connect(self.refreshButtonClicked)
|
|
self.buttonBox.accepted.connect(self.confirmButton)
|
|
self.buttonBox.rejected.connect(self.mainDialog.close)
|
|
self.directoryDialogButton.clicked.connect(self._selectDir)
|
|
self.widgetDocuments.clicked.connect(self._documentSelected)
|
|
|
|
self.mainDialog.setWindowModality(Qt.NonModal)
|
|
self.widgetDocuments.setSelectionMode(QAbstractItemView.SingleSelection)
|
|
self.widgetDocuments.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
|
|
|
|
def initialize(self):
|
|
self.loadTools()
|
|
|
|
self.documentLayout.addWidget(self.widgetDocuments)
|
|
self.documentLayout.addWidget(self.refreshButton)
|
|
self.directorySelectorLayout.addWidget(self.directoryTextField)
|
|
self.directorySelectorLayout.addWidget(self.directoryDialogButton)
|
|
|
|
self.formLayout.addRow(i18n("Documents:"), self.documentLayout)
|
|
self.formLayout.addRow(i18n("Output Directory:"), self.directorySelectorLayout)
|
|
self.formLayout.addRow(i18n("Bone Length:"), self.boneLengthField)
|
|
self.formLayout.addRow(self.includeHiddenCheckbox)
|
|
self.formLayout.addRow(self.tabTools)
|
|
|
|
self.line = QFrame()
|
|
self.line.setFrameShape(QFrame.HLine)
|
|
self.line.setFrameShadow(QFrame.Sunken)
|
|
|
|
self.mainLayout.addLayout(self.formLayout)
|
|
self.mainLayout.addWidget(self.line)
|
|
self.mainLayout.addWidget(self.outputField)
|
|
self.mainLayout.addWidget(self.buttonBox)
|
|
|
|
self.mainDialog.resize(500, 300)
|
|
self.mainDialog.setWindowTitle(i18n("Export to Spine"))
|
|
self.mainDialog.setSizeGripEnabled(True)
|
|
self.mainDialog.show()
|
|
self.mainDialog.activateWindow()
|
|
|
|
self.loadDocuments()
|
|
|
|
|
|
def loadTools(self):
|
|
modulePath = 'KritaToSpine.tools'
|
|
toolsModule = importlib.import_module(modulePath)
|
|
modules = []
|
|
|
|
for classPath in toolsModule.ToolClasses:
|
|
_module = classPath[:classPath.rfind(".")]
|
|
_klass = classPath[classPath.rfind(".") + 1:]
|
|
modules.append(dict(module='{0}.{1}'.format(modulePath, _module),
|
|
klass=_klass))
|
|
|
|
for module in modules:
|
|
m = importlib.import_module(module['module'])
|
|
toolClass = getattr(m, module['klass'])
|
|
obj = toolClass(self.mainDialog)
|
|
self.tabTools.addTab(obj, obj.objectName())
|
|
|
|
def loadDocuments(self):
|
|
self.widgetDocuments.clear()
|
|
|
|
self.documentsList = [
|
|
document for document in self.kritaInstance.documents()
|
|
if document.fileName()
|
|
]
|
|
|
|
for document in self.documentsList:
|
|
self.widgetDocuments.addItem(document.fileName())
|
|
|
|
if self.documentsList:
|
|
self.widgetDocuments.setCurrentItem(self.widgetDocuments.item(0))
|
|
self._documentSelected()
|
|
|
|
def refreshButtonClicked(self):
|
|
self.outputField.clear()
|
|
self.loadDocuments()
|
|
|
|
def confirmButton(self):
|
|
self.outputField.setText(i18n("Exporting..."))
|
|
|
|
doc = self._selectedDocuments()[0]
|
|
|
|
if doc:
|
|
widget = self.tabTools.currentWidget()
|
|
|
|
#Krita seems to have a bug where invisible guides in a cloned document get scaled incorrectly
|
|
#Bug: https://bugs.kde.org/show_bug.cgi?id=463713
|
|
oldGuideVis = doc.guidesVisible()
|
|
doc.setGuidesVisible(True)
|
|
cloneDoc = doc.clone()
|
|
doc.setGuidesVisible(oldGuideVis)
|
|
|
|
widget.adjust(cloneDoc)
|
|
# Save the json from the clone
|
|
self.spineExport.exportDocument(cloneDoc, self.directoryTextField.text(), self.boneLengthField.value(), self.includeHiddenCheckbox.isChecked())
|
|
# Clone no longer needed
|
|
cloneDoc.close()
|
|
|
|
self.outputField.setText(i18n("Saving settings..."))
|
|
j = json.dumps({
|
|
"outDir": self.directoryTextField.text(),
|
|
"boneLength": self.boneLengthField.value(),
|
|
"includeHidden": self.includeHiddenCheckbox.isChecked()
|
|
})
|
|
doc.setAnnotation(f'krita2spine', f"krita2spine settings", QByteArray(j.encode()))
|
|
|
|
self.outputField.setText(i18n("The selected document has been exported."))
|
|
else:
|
|
self.outputField.setText(i18n("Please select a document."))
|
|
|
|
|
|
def _selectDir(self):
|
|
doc = self._selectedDocuments()
|
|
if doc[0]:
|
|
initialDir = os.path.dirname(doc[0].fileName())
|
|
else:
|
|
initialDir = os.path.expanduser("~")
|
|
|
|
directory = QFileDialog.getExistingDirectory(self.mainDialog, i18n("Select a Folder"), initialDir, QFileDialog.ShowDirsOnly)
|
|
self.directoryTextField.setText(directory)
|
|
|
|
def _documentSelected(self):
|
|
doc = self._selectedDocuments()
|
|
fileName = doc[0].fileName()
|
|
widget = self.tabTools.currentWidget()
|
|
|
|
q = doc[0].annotation("krita2spine") #type: QByteArray
|
|
if not q.isEmpty():
|
|
docData = json.loads(bytes(q).decode())
|
|
self.directoryTextField.setText(docData["outDir"])
|
|
self.includeHiddenCheckbox.setChecked(docData["includeHidden"])
|
|
widget.updateFields(doc[0], docData)
|
|
else:
|
|
self.directoryTextField.setText(os.path.dirname(fileName))
|
|
# TODO have this loop through the tabs and set them up
|
|
# Tell the widget to update itself to the current settings
|
|
self.outputField.clear()
|
|
|
|
def _selectedDocuments(self):
|
|
selectedPaths = [
|
|
item.text() for item in self.widgetDocuments.selectedItems()]
|
|
selectedDocuments = [
|
|
document for document in self.documentsList
|
|
for path in selectedPaths if path == document.fileName()]
|
|
return selectedDocuments
|
|
|