Exemple #1
0
class UISpritesheetExporter(object):
    def __init__(self):
        # here we don't need super().__init__(parent)
        # maybe it's only for who inherits extensions?
        self.app = krita.Krita.instance()
        self.exp = spritesheetexporter.SpritesheetExporter()

        # the main window
        self.mainDialog = QDialog()

        # the window is not modal and does not block input to other windows
        self.mainDialog.setWindowModality(Qt.NonModal)

        self.mainDialog.setMinimumSize(500, 100)

        # the box holding everything
        self.outerLayout = QVBoxLayout(self.mainDialog)

        self.topLayout = QVBoxLayout()

        # the user should choose the export name of the final spritesheet
        self.exportName = QLineEdit()

        # and the export directory
        self.exportDirTx = QLineEdit()
        self.exportDirButt = QPushButton("Change export directory")
        self.exportDirResetButt = QPushButton("Reset to current directory")
        self.exportDirResetButt.setToolTip(
            "Reset export directory to current .kra document's directory")
        self.exportDirButt.clicked.connect(self.changeExportDir)
        self.exportDirResetButt.clicked.connect(self.resetExportDir)
        self.exportDir = QHBoxLayout()

        # and the sprites export directory
        self.spritesExportDirWidget = QWidget()
        self.spritesExportDirTx = QLineEdit()
        self.spritesExportDirButt = QPushButton("Change sprites directory")
        self.spritesExportDirButt.clicked.connect(self.changeSpritesExportDir)
        self.spritesExportDirTx.setToolTip("Leave empty for default")
        self.spritesExportDir = QHBoxLayout(self.spritesExportDirWidget)

        self.customSettings = QCheckBox()
        self.customSettings.setChecked(False)
        self.customSettings.stateChanged.connect(self.toggleHideable)

        self.hideableWidget = QFrame()  # QFrames are a type of widget
        self.hideableWidget.setFrameShape(QFrame.Panel)
        self.hideableWidget.setFrameShadow(QFrame.Sunken)
        self.hideableLayout = QVBoxLayout(self.hideableWidget)

        # we let people export each layer as an animation frame if they wish
        self.layersAsAnimation = QCheckBox()
        self.layersAsAnimation.setChecked(False)

        # We want to let the user choose if they want the final spritesheet
        # to be horizontally- or vertically-oriented.
        # There is a nifty thing called QButtonGroup() but
        # it doesn't seem to let you add names between each checkbox somehow?
        self.horDir = QCheckBox()
        self.horDir.setChecked(True)
        self.vertDir = QCheckBox()
        self.vertDir.setChecked(False)
        self.vertDir.stateChanged.connect(self.exclusiveVertToHor)
        self.horDir.stateChanged.connect(self.exclusiveHorToVert)
        self.direction = QHBoxLayout()

        self.spinBoxesWidget = QFrame()
        self.spinBoxesWidget.setFrameShape(QFrame.Panel)
        self.spinBoxesWidget.setFrameShadow(QFrame.Sunken)

        # a box holding the boxes with rows columns and start end
        self.spinBoxes = QHBoxLayout(self.spinBoxesWidget)

        self.rows = QSpinBox(minimum=self.exp.defaultSpace)
        self.columns = QSpinBox(minimum=self.exp.defaultSpace)
        self.rows.setValue(self.exp.defaultSpace)
        self.columns.setValue(self.exp.defaultSpace)

        self.start = QSpinBox(minimum=self.exp.defaultTime)
        self.end = QSpinBox(minimum=self.exp.defaultTime)
        self.step = QSpinBox(minimum=1)
        self.start.setValue(self.exp.defaultTime)
        self.end.setValue(self.exp.defaultTime)
        self.step.setValue(1)

        # to be placed outside of spinBoxes, still in outerLayout
        self.hiddenCheckbox = QWidget()
        self.hiddenCheckboxLayout = QVBoxLayout(self.hiddenCheckbox)
        self.line = QFrame()
        self.line.setFrameShape(QFrame.HLine)
        self.line.setFrameShadow(QFrame.Sunken)
        self.checkBoxes = QHBoxLayout()
        self.forceNew = QCheckBox()
        self.forceNew.setChecked(False)
        self.removeTmp = QCheckBox()
        self.removeTmp.setChecked(True)

        self.line2 = QFrame()
        self.line2.setFrameShape(QFrame.HLine)
        self.line2.setFrameShadow(QFrame.Sunken)
        self.OkCancelButtonBox = \
            QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.OkCancelButtonBox.accepted.connect(self.confirmButton)
        self.OkCancelButtonBox.rejected.connect(self.mainDialog.close)

        self.space = 10

        self.spacer = QSpacerItem(self.space, self.space)
        self.spacerBig = QSpacerItem(self.space * 2, self.space * 2)

        self.exportPath = Path.home()

        self.initialize_export()

    # I would have used QFormLayout's addRow
    # except it doesn't let you add a tooltip to the row's name
    # (adding a tooltip to the whole layout would have been best
    #  but doesn't seem possible)
    def addDescribedWidget(self, parent, listWidgets, align=Qt.AlignLeft):
        layout = QGridLayout()
        row = 0
        for widget in listWidgets:
            label = QLabel(widget.descri)
            label.setBuddy(widget.widget)
            layout.addWidget(label, row, 0)
            layout.addWidget(widget.widget, row, 1)
            if widget.tooltip != "":
                widget.widget.setToolTip(widget.tooltip)
                label.setToolTip(widget.tooltip)
            row += 1
        layout.setAlignment(align)
        parent.addLayout(layout)
        return layout

    def initialize_export(self):
        # putting stuff in boxes
        # and boxes in bigger boxes
        self.exportName.setText(self.exp.exportName)
        self.addDescribedWidget(
            parent=self.topLayout,
            listWidgets=[
                describedWidget(
                    widget=self.exportName,
                    descri="Export name:",
                    tooltip="The name of the exported spritesheet file")
            ])
        self.addDescribedWidget(
            parent=self.topLayout,
            listWidgets=[
                describedWidget(
                    widget=self.exportDirTx,
                    descri="Export Directory:",
                    tooltip="The directory the spritesheet will be exported to"
                )
            ])

        self.exportDir.addWidget(self.exportDirButt)
        self.exportDir.addWidget(self.exportDirResetButt)
        self.topLayout.addLayout(self.exportDir)

        self.addDescribedWidget(
            parent=self.topLayout,
            listWidgets=[
                describedWidget(
                    widget=self.customSettings,
                    descri="Use Custom export Settings:",
                    tooltip="" +
                    "Whether to set yourself the number of rows, columns,\n" +
                    "first and last frame, etc. (checked)\n" +
                    "or use the default values (unchecked) ")
            ])

        self.outerLayout.addLayout(self.topLayout, 0)

        # all this stuff will be hideable
        self.addDescribedWidget(
            parent=self.hideableLayout,
            listWidgets=[
                describedWidget(
                    descri="use layers as animation frames ",
                    widget=self.layersAsAnimation,
                    tooltip="Rather than exporting a spritesheet " +
                    "using as frames\n" + "each frame of the timeline " +
                    "(all visible layers merged down),\n" +
                    "export instead a spritesheet " + "using as frames\n" +
                    "the current frame of each visible layer")
            ])

        self.hideableLayout.addItem(self.spacer)

        self.direction.addWidget(QLabel("sprites placement direction: \t"))
        self.addDescribedWidget(
            parent=self.direction,
            listWidgets=[
                describedWidget(widget=self.horDir,
                                descri="Horizontal:",
                                tooltip="like so:\n1, 2, 3\n4, 5, 6\n7, 8, 9")
            ])

        self.addDescribedWidget(
            parent=self.direction,
            listWidgets=[
                describedWidget(widget=self.vertDir,
                                descri="Vertical:",
                                tooltip="like so:\n1, 4, 7\n2, 5, 8\n3, 6, 9")
            ])

        self.hideableLayout.addLayout(self.direction)

        self.hideableLayout.addItem(self.spacerBig)

        defaultsHint = QLabel(
            "Leave any parameter at 0 to get a default value:")
        defaultsHint.setToolTip(
            "For example with 16 sprites, " +
            "leaving both rows and columns at 0\n" +
            "will set their defaults to 4 each\n" +
            "while leaving only columns at 0 and rows at 1\n" +
            "will set columns default at 16")
        self.hideableLayout.addWidget(defaultsHint)

        self.addDescribedWidget(
            parent=self.spinBoxes,
            listWidgets=[
                describedWidget(
                    widget=self.rows,
                    descri="Rows:",
                    tooltip="Number of rows of the spritesheet;\n" +
                    "default is assigned depending on columns number\n" +
                    "or if 0 columns tries to form a square "),
                describedWidget(
                    widget=self.columns,
                    descri="Columns:",
                    tooltip="Number of columns of the spritesheet;\n" +
                    "default is assigned depending on rows number\n" +
                    "or if 0 rows tries to form a square")
            ])

        self.addDescribedWidget(
            parent=self.spinBoxes,
            listWidgets=[
                describedWidget(
                    widget=self.start,
                    descri="Start:",
                    tooltip="" +
                    "First frame of the animation timeline (included) " +
                    "to be added to the spritesheet;\n" +
                    "default is first keyframe after " +
                    "the Start frame of the Animation docker"),
                describedWidget(
                    widget=self.end,
                    descri="End:",
                    tooltip="Last frame of the animation timeline (included) "
                    + "to be added to the spritesheet;\n" +
                    "default is last keyframe before " +
                    "the End frame of the Animation docker"),
                describedWidget(widget=self.step,
                                descri="Step:",
                                tooltip="only consider every 'step' frame " +
                                "to be added to the spritesheet;\n" +
                                "default is 1 (use every frame)")
            ])

        self.hideableLayout.addWidget(self.spinBoxesWidget)

        self.addDescribedWidget(
            parent=self.checkBoxes,
            listWidgets=[
                describedWidget(
                    descri="Remove individual sprites?",
                    widget=self.removeTmp,
                    tooltip="Once the spritesheet export is done,\n" +
                    "whether to remove the individual exported sprites")
            ])

        self.forceNewLayout = self.addDescribedWidget(
            parent=self.hiddenCheckboxLayout,
            listWidgets=[
                describedWidget(
                    descri="Force new folder?",
                    widget=self.forceNew,
                    tooltip="If there is already a folder " +
                    "with the same name as the individual " +
                    "sprites export folder,\n" +
                    "whether to create a new one (checked) " +
                    "or write the sprites in the existing folder,\n" +
                    "possibly overwriting other files (unchecked)")
            ])

        self.addDescribedWidget(
            parent=self.spritesExportDir,
            listWidgets=[
                describedWidget(
                    widget=self.spritesExportDirTx,
                    descri="Sprites export directory:",
                    tooltip="The directory the individual sprites " +
                    "will be exported to")
            ])
        self.spritesExportDir.addWidget(self.spritesExportDirButt)

        # have removeTmp toggle forceNew's and sprites export dir's visibility
        self.checkBoxes.addWidget(self.hiddenCheckbox)
        self.hideableLayout.addLayout(self.checkBoxes)
        self.hideableLayout.addWidget(self.spritesExportDirWidget)
        self.removeTmp.clicked.connect(self.toggleHiddenParams)

        self.outerLayout.addWidget(self.hideableWidget)

        self.outerLayout.addWidget(self.OkCancelButtonBox)
        self.toggleHiddenParams()
        self.toggleHideable()

    def exclusiveVertToHor(self):
        self.exclusiveCheckBoxUpdate(trigger=self.vertDir,
                                     triggered=self.horDir)

    def exclusiveHorToVert(self):
        self.exclusiveCheckBoxUpdate(trigger=self.horDir,
                                     triggered=self.vertDir)

    def exclusiveCheckBoxUpdate(self, trigger, triggered):
        if triggered.isChecked() == trigger.isChecked():
            triggered.setChecked(not trigger.isChecked())

    def toggleHideable(self):
        if self.customSettings.isChecked():
            self.hideableWidget.show()
            self.mainDialog.adjustSize()
        else:
            self.hideableWidget.hide()
            self.mainDialog.adjustSize()

    def toggleHiddenParams(self):
        if self.removeTmp.isChecked():
            self.forceNew.setChecked(False)
            self.spritesExportDirTx.setText("")
        self.hiddenCheckbox.setDisabled(self.removeTmp.isChecked())
        self.spritesExportDirWidget.setDisabled(self.removeTmp.isChecked())

    def showExportDialog(self):
        self.doc = self.app.activeDocument()
        if self.exportDirTx.text() == "":
            self.resetExportDir()
        self.mainDialog.setWindowTitle(i18n("SpritesheetExporter"))
        self.mainDialog.setSizeGripEnabled(True)
        self.mainDialog.show()
        self.mainDialog.activateWindow()
        self.mainDialog.setDisabled(False)

    def changeExportDir(self):
        self.exportDirDialog = QFileDialog()
        self.exportDirDialog.setWindowTitle(i18n("Choose Export Directory"))
        self.exportDirDialog.setSizeGripEnabled(True)
        self.exportDirDialog.setDirectory(str(self.exportPath))
        # we grab the output path on directory changed
        self.exportPath = self.exportDirDialog.getExistingDirectory()
        if self.exportPath != "":
            self.exportDirTx.setText(str(self.exportPath))

    # go back to the same folder where your .kra is
    def resetExportDir(self):
        if self.doc and self.doc.fileName():
            self.exportPath = Path(self.doc.fileName()).parents[0]
        self.exportDirTx.setText(str(self.exportPath))

    def changeSpritesExportDir(self):
        self.SpritesExportDirDialog = QFileDialog()
        self.SpritesExportDirDialog.setWindowTitle(
            i18n("Choose Sprites Export Directory"))
        self.SpritesExportDirDialog.setSizeGripEnabled(True)
        self.SpritesExportDirDialog.setDirectory(str(self.exportPath))
        # we grab the output path on directory changed
        self.spritesExportPath = \
            self.SpritesExportDirDialog.getExistingDirectory()
        if self.spritesExportPath != "":
            self.spritesExportDirTx.setText(str(self.spritesExportPath))

    def confirmButton(self):
        # if you double click it shouldn't interrupt
        # the first run of the function with a new one
        self.mainDialog.setDisabled(True)

        self.exp.exportName = self.exportName.text().split('.')[0]
        self.exp.exportDir = Path(self.exportPath)
        self.exp.layersAsAnimation = self.layersAsAnimation.isChecked()
        self.exp.isDirectionHorizontal = self.horDir.isChecked()
        self.exp.rows = self.rows.value()
        self.exp.columns = self.columns.value()
        self.exp.start = self.start.value()
        self.exp.end = self.end.value()
        self.exp.step = self.step.value()
        self.exp.removeTmp = self.removeTmp.isChecked()
        self.exp.forceNew = self.forceNew.isChecked()
        if self.spritesExportDirTx.text() != "":
            self.exp.spritesExportDir = Path(self.spritesExportDirTx.text())
        else:
            # important: we reset spritesheetexporter's spritesExportDir
            self.exp.spritesExportDir = self.exp.defaultPath
        self.exp.export()
        self.mainDialog.hide()