diff --git a/plugins/python/documenttools/tools/canvassizetool/canvassizetool.py b/plugins/python/documenttools/tools/canvassizetool/canvassizetool.py index b459cc3637..5d26f7575c 100644 --- a/plugins/python/documenttools/tools/canvassizetool/canvassizetool.py +++ b/plugins/python/documenttools/tools/canvassizetool/canvassizetool.py @@ -1,52 +1,53 @@ ''' 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 ''' from PyQt5.QtWidgets import (QWidget, QSpinBox, QHBoxLayout, QVBoxLayout, QFormLayout) +import krita class CanvasSizeTool(QWidget): def __init__(self, mainDialog, parent=None): super(CanvasSizeTool, self).__init__(parent) self.setObjectName("Canvas Size") self.layout = QFormLayout() self.offsetLayout = QVBoxLayout() self.widthSpinBox = QSpinBox() self.heightSpinBox = QSpinBox() self.xOffsetSpinBox = QSpinBox() self.yOffsetSpinBox = QSpinBox() self.setLayout(self.layout) self.initialize() def initialize(self): self.widthSpinBox.setRange(1, 10000) self.heightSpinBox.setRange(1, 10000) self.xOffsetSpinBox.setRange(-10000, 10000) self.yOffsetSpinBox.setRange(-10000, 10000) self.offsetLayout.addWidget(self.xOffsetSpinBox) self.offsetLayout.addWidget(self.yOffsetSpinBox) - self.layout.addRow('Width', self.widthSpinBox) - self.layout.addRow('Height', self.heightSpinBox) - self.layout.addRow('Offset', self.offsetLayout) + self.layout.addRow(i18n("Width:"), self.widthSpinBox) + self.layout.addRow(i18n("Height:"), self.heightSpinBox) + self.layout.addRow(i18n("Offset:"), self.offsetLayout) def adjust(self, documents): for document in documents: document.resizeImage(self.xOffsetSpinBox.value(), self.yOffsetSpinBox.value(), self.widthSpinBox.value(), self.heightSpinBox.value()) diff --git a/plugins/python/documenttools/tools/rotatetool/rotatetool.py b/plugins/python/documenttools/tools/rotatetool/rotatetool.py index 19d55da8e5..ae3f1e20e0 100644 --- a/plugins/python/documenttools/tools/rotatetool/rotatetool.py +++ b/plugins/python/documenttools/tools/rotatetool/rotatetool.py @@ -1,39 +1,40 @@ ''' 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 ''' from PyQt5.QtWidgets import (QWidget, QSpinBox, QHBoxLayout, QVBoxLayout, QFormLayout) import math +import krita class RotateTool(QWidget): def __init__(self, mainDialog, parent=None): super(RotateTool, self).__init__(parent) self.setObjectName("Rotate") self.layout = QFormLayout() self.degreesSpinBox = QSpinBox() self.setLayout(self.layout) self.initialize() def initialize(self): self.degreesSpinBox.setRange(-180, 180) - self.degreesSpinBox.setToolTip("Negative degrees will rotate the image to the left") + self.degreesSpinBox.setToolTip(i18n("Negative degrees will rotate the image to the left")) - self.layout.addRow('Degrees', self.degreesSpinBox) + self.layout.addRow(i18n("Degrees:"), self.degreesSpinBox) def adjust(self, documents): for document in documents: document.rotateImage(math.radians(self.degreesSpinBox.value())) diff --git a/plugins/python/documenttools/tools/scaletool/scaletool.py b/plugins/python/documenttools/tools/scaletool/scaletool.py index d015354bc3..f71e59fe85 100644 --- a/plugins/python/documenttools/tools/scaletool/scaletool.py +++ b/plugins/python/documenttools/tools/scaletool/scaletool.py @@ -1,60 +1,61 @@ ''' 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 ''' from PyQt5.QtWidgets import (QWidget, QSpinBox, QHBoxLayout, QVBoxLayout, QFormLayout, QComboBox) +import krita class ScaleTool(QWidget): def __init__(self, mainDialog, parent=None): super(ScaleTool, self).__init__(parent) self.setObjectName("Scale") self.layout = QFormLayout() self.resolutionLayout = QVBoxLayout() self.widthSpinBox = QSpinBox() self.heightSpinBox = QSpinBox() self.xResSpinBox = QSpinBox() self.yResSpinBox = QSpinBox() self.strategyComboBox = QComboBox() self.strategyComboBox.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.setLayout(self.layout) self.initialize() def initialize(self): self.widthSpinBox.setRange(1, 10000) self.heightSpinBox.setRange(1, 10000) self.xResSpinBox.setRange(1, 10000) self.yResSpinBox.setRange(1, 10000) strategies = ['Hermite', 'Bicubic', 'Box', 'Bilinear', 'Bell', 'BSpline', 'Kanczos3', 'Mitchell'] self.strategyComboBox.addItems(strategies) self.resolutionLayout.addWidget(self.xResSpinBox) self.resolutionLayout.addWidget(self.yResSpinBox) - self.layout.addRow('Width', self.widthSpinBox) - self.layout.addRow('Height', self.heightSpinBox) - self.layout.addRow('Resolution', self.resolutionLayout) - self.layout.addRow('Filter', self.strategyComboBox) + self.layout.addRow(i18n("Width:"), self.widthSpinBox) + self.layout.addRow(i18n("Height:"), self.heightSpinBox) + self.layout.addRow(i18n("Resolution:"), self.resolutionLayout) + self.layout.addRow(i18n("Filter:"), self.strategyComboBox) def adjust(self, documents): for document in documents: document.scaleImage(self.widthSpinBox.value(), self.heightSpinBox.value(), self.xResSpinBox.value(), self.yResSpinBox.value(), self.strategyComboBox.currentText()) diff --git a/plugins/python/hello/hello.py b/plugins/python/hello/hello.py index 677d85af87..cf2c6b3c8a 100644 --- a/plugins/python/hello/hello.py +++ b/plugins/python/hello/hello.py @@ -1,88 +1,88 @@ ''' 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 ''' # # This is a simple example of a Python script for Krita. # It demonstrates how to set up a custom extension and a custom docker! # from PyQt5.QtWidgets import QWidget, QLabel, QMessageBox from krita import (Krita, Extension, DockWidget, DockWidgetFactory, DockWidgetFactoryBase) def hello(): """ Show a test message box. """ QMessageBox.information(QWidget(), i18n("Test"), i18n("Hello! This is Krita version %s") % Application.version()) class HelloExtension(Extension): """ HelloExtension is a small example extension demonstrating basic Python scripting support in Krita! """ def __init__(self, parent): """ Standard Krita Python extension constructor. Most of the initialization happens in :func:`setup` :param parent: Parent widget :type parent: :class:`QWidget` or None """ super(HelloExtension, self).__init__(parent) def setup(self): pass def createActions(self, window): """ This is where most of the setup takes place! """ - action = window.createAction("hello_python", "hello") + action = window.createAction("hello_python", i18n("Hello")) action.triggered.connect(hello) # Initialize and add the extension Scripter.addExtension(HelloExtension(Krita.instance())) class HelloDocker(DockWidget): """ The HelloDocker is an example of a simple Python-based docker. """ def __init__(self): """ Constructs an instance of HelloDocker and the widget it contains """ super(HelloDocker, self).__init__() # The window title is also used in the Docker menu, # so it should be set to something sensible! self.setWindowTitle("HelloDocker") label = QLabel("Hello", self) self.setWidget(label) self._label = label def canvasChanged(self, canvas): """ Override canvasChanged from :class:`DockWidget`. This gets called when the canvas changes. You can also access the active canvas via :func:`DockWidget.canvas` Parameter `canvas` can be null if the last document is closed """ self._label.setText("HelloDocker: canvas changed") # Register the docker so Krita can use it! Application.addDockWidgetFactory(DockWidgetFactory("hello", DockWidgetFactoryBase.DockRight, HelloDocker)) diff --git a/plugins/python/lastdocumentsdocker/lastdocumentsdocker.py b/plugins/python/lastdocumentsdocker/lastdocumentsdocker.py index 449a4ba278..cec8fd6a9d 100644 --- a/plugins/python/lastdocumentsdocker/lastdocumentsdocker.py +++ b/plugins/python/lastdocumentsdocker/lastdocumentsdocker.py @@ -1,47 +1,47 @@ ''' 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 ''' from PyQt5.QtWidgets import QWidget, QVBoxLayout, QListView, QPushButton import krita from . import lastdocumentslistmodel class LastDocumentsDocker(krita.DockWidget): def __init__(self): super(LastDocumentsDocker, self).__init__() self.baseWidget = QWidget() self.layout = QVBoxLayout() self.listView = QListView() - self.loadButton = QPushButton("Refresh") + self.loadButton = QPushButton(i18n("Refresh")) self.listModel = lastdocumentslistmodel.LastDocumentsListModel() self.listView.setModel(self.listModel) self.listView.setFlow(QListView.LeftToRight) self.layout.addWidget(self.listView) self.layout.addWidget(self.loadButton) self.baseWidget.setLayout(self.layout) self.setWidget(self.baseWidget) self.loadButton.clicked.connect(self.refreshRecentDocuments) - self.setWindowTitle("Last Documents Docker") + self.setWindowTitle(i18n("Last Documents Docker")) def canvasChanged(self, canvas): pass def refreshRecentDocuments(self): self.listModel.loadRecentDocuments() Application.addDockWidgetFactory(krita.DockWidgetFactory("lastdocumentsdocker", krita.DockWidgetFactoryBase.DockRight, LastDocumentsDocker)) diff --git a/plugins/python/palette_docker/palette_docker.py b/plugins/python/palette_docker/palette_docker.py index c15949afd0..5344b302ef 100644 --- a/plugins/python/palette_docker/palette_docker.py +++ b/plugins/python/palette_docker/palette_docker.py @@ -1,262 +1,262 @@ ''' Description: A Python based docker that allows you to edit KPL color palettes. By Wolthera(originally) 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 @package palette_docker ''' # Importing the relevant dependencies: import sys from PyQt5.QtGui import QPixmap, QIcon, QImage, QPainter, QBrush, QPalette from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QComboBox, QAction, QTabWidget, QLineEdit, QSpinBox, QDialogButtonBox, QToolButton, QDialog, QPlainTextEdit, QCompleter, QMenu from PyQt5.Qt import Qt, pyqtSignal, pyqtSlot import math from krita import * # import the exporters from . import palette_exporter_gimppalette, palette_exporter_inkscapeSVG, palette_sortColors class Palette_Docker(DockWidget): # Init the docker def __init__(self): super(Palette_Docker, self).__init__() # make base-widget and layout widget = QWidget() layout = QVBoxLayout() buttonLayout = QHBoxLayout() widget.setLayout(layout) - self.setWindowTitle("Python Palette Docker") + self.setWindowTitle(i18n("Python Palette Docker")) # Make a combobox and add palettes self.cmb_palettes = QComboBox() allPalettes = Application.resources("palette") for palette_name in allPalettes: self.cmb_palettes.addItem(palette_name) self.cmb_palettes.model().sort(0) if len(allPalettes.keys()) > 0: self.currentPalette = Palette(allPalettes[list(allPalettes.keys())[0]]) else: self.currentPalette = None self.cmb_palettes.currentTextChanged.connect(self.slot_paletteChanged) layout.addWidget(self.cmb_palettes) # add combobox to the layout self.paletteView = PaletteView() self.paletteView.setPalette(self.currentPalette) layout.addWidget(self.paletteView) self.paletteView.entrySelectedForeGround.connect(self.slot_swatchSelected) self.colorComboBox = QComboBox() self.colorList = list() buttonLayout.addWidget(self.colorComboBox) self.bnSetColor = QToolButton() - self.bnSetColor.setText("Set") + self.bnSetColor.setText(i18n("Set")) self.bnSetColor.clicked.connect(self.slot_get_color_from_combobox) buttonLayout.addWidget(self.bnSetColor) self.addEntry = QAction(self) - self.addEntry.setIconText("+") + self.addEntry.setIconText(i18n("+")) self.addEntry.triggered.connect(self.slot_add_entry) self.addGroup = QAction(self) self.addGroup.triggered.connect(self.slot_add_group) - self.addGroup.setText("Add Group") + self.addGroup.setText(i18n("Add Group")) self.addGroup.setIconText(str("\U0001F4C2")) self.removeEntry = QAction(self) - self.removeEntry.setText("Remove Entry") + self.removeEntry.setText(i18n("Remove Entry")) self.removeEntry.setIconText("-") self.removeEntry.triggered.connect(self.slot_remove_entry) addEntryButton = QToolButton() addEntryButton.setDefaultAction(self.addEntry) buttonLayout.addWidget(addEntryButton) addGroupButton = QToolButton() addGroupButton.setDefaultAction(self.addGroup) buttonLayout.addWidget(addGroupButton) removeEntryButton = QToolButton() removeEntryButton.setDefaultAction(self.removeEntry) buttonLayout.addWidget(removeEntryButton) # QActions self.extra = QToolButton() self.editPaletteData = QAction(self) - self.editPaletteData.setText("Edit Palette Settings") + self.editPaletteData.setText(i18n("Edit Palette Settings")) self.editPaletteData.triggered.connect(self.slot_edit_palette_data) self.extra.setDefaultAction(self.editPaletteData) buttonLayout.addWidget(self.extra) self.actionMenu = QMenu() self.exportToGimp = QAction(self) - self.exportToGimp.setText("Export as GIMP palette file.") + self.exportToGimp.setText(i18n("Export as GIMP Palette File")) self.exportToGimp.triggered.connect(self.slot_export_to_gimp_palette) self.exportToInkscape = QAction(self) - self.exportToInkscape.setText("Export as Inkscape SVG with swatches.") + self.exportToInkscape.setText(i18n("Export as Inkscape SVG with Swatches")) self.exportToInkscape.triggered.connect(self.slot_export_to_inkscape_svg) self.sortColors = QAction(self) - self.sortColors.setText("Sort colors") + self.sortColors.setText(i18n("Sort Colors")) self.sortColors.triggered.connect(self.slot_sort_colors) self.actionMenu.addAction(self.editPaletteData) self.actionMenu.addAction(self.exportToGimp) self.actionMenu.addAction(self.exportToInkscape) # self.actionMenu.addAction(self.sortColors) self.extra.setMenu(self.actionMenu) layout.addLayout(buttonLayout) self.slot_fill_combobox() self.setWidget(widget) # add widget to the docker def slot_paletteChanged(self, name): allPalettes = Application.resources("palette") if len(allPalettes) > 0 and name in allPalettes: self.currentPalette = Palette(Application.resources("palette")[name]) self.paletteView.setPalette(self.currentPalette) self.slot_fill_combobox() @pyqtSlot('PaletteEntry') def slot_swatchSelected(self, entry): if (self.canvas()) is not None: if (self.canvas().view()) is not None: name = entry.name() if len(entry.id) > 0: name = entry.id() + " - " + entry.name() if len(name) > 0: if name in self.colorList: self.colorComboBox.setCurrentIndex(self.colorList.index(name)) color = self.currentPalette.colorForEntry(entry) self.canvas().view().setForeGroundColor(color) ''' A function for making a combobox with the available colors. We use QCompleter on the colorComboBox so that people can type in the name of a color to select it. This is useful for people with carefully made palettes where the colors are named properly, which makes it easier for them to find colors. ''' def slot_fill_combobox(self): if self.currentPalette is None: pass palette = self.currentPalette self.colorComboBox.clear() self.colorList = list() for i in range(palette.colorsCountTotal()): entry = palette.colorSetEntryByIndex(i) color = palette.colorForEntry(entry).colorForCanvas(self.canvas()) colorSquare = QPixmap(12, 12) if entry.spotColor() is True: img = colorSquare.toImage() circlePainter = QPainter() img.fill(self.colorComboBox.palette().color(QPalette.Base)) circlePainter.begin(img) brush = QBrush(Qt.SolidPattern) brush.setColor(color) circlePainter.setBrush(brush) circlePainter.pen().setWidth(0) circlePainter.drawEllipse(0, 0, 11, 11) circlePainter.end() colorSquare = QPixmap.fromImage(img) else: colorSquare.fill(color) name = entry.name() if len(entry.id()) > 0: name = entry.id() + " - " + entry.name() self.colorList.append(name) self.colorComboBox.addItem(QIcon(colorSquare), name) self.colorComboBox.setEditable(True) self.colorComboBox.setInsertPolicy(QComboBox.NoInsert) self.colorComboBox.completer().setCompletionMode(QCompleter.PopupCompletion) self.colorComboBox.completer().setCaseSensitivity(False) self.colorComboBox.completer().setFilterMode(Qt.MatchContains) def slot_get_color_from_combobox(self): if self.currentPalette is not None: entry = self.currentPalette.colorSetEntryByIndex(self.colorComboBox.currentIndex()) self.slot_swatchSelected(entry) def slot_add_entry(self): if (self.canvas()) is not None: if (self.canvas().view()) is not None: color = self.canvas().view().foregroundColor() success = self.paletteView.addEntryWithDialog(color) if success is True: self.slot_fill_combobox() def slot_add_group(self): success = self.paletteView.addGroupWithDialog() if success is True: self.slot_fill_combobox() def slot_remove_entry(self): success = self.paletteView.removeSelectedEntryWithDialog() if success is True: self.slot_fill_combobox() ''' A function for giving a gui to edit palette metadata... I also want this to be the way to edit the settings of the palette docker. ''' def slot_edit_palette_data(self): dialog = QDialog(self) tabWidget = QTabWidget() - dialog.setWindowTitle("Edit Palette Data") + dialog.setWindowTitle(i18n("Edit Palette Data")) dialog.setLayout(QVBoxLayout()) dialog.layout().addWidget(tabWidget) paletteWidget = QWidget() paletteWidget.setLayout(QVBoxLayout()) - tabWidget.addTab(paletteWidget, "Palette Data") + tabWidget.addTab(paletteWidget, i18n("Palette Data")) paletteName = QLineEdit() paletteName.setText(self.cmb_palettes.currentText()) paletteWidget.layout().addWidget(paletteName) paletteColumns = QSpinBox() paletteColumns.setValue(self.currentPalette.columnCount()) paletteWidget.layout().addWidget(paletteColumns) paletteComment = QPlainTextEdit() paletteComment.appendPlainText(self.currentPalette.comment()) paletteWidget.layout().addWidget(paletteComment) buttons = QDialogButtonBox(QDialogButtonBox.Ok) dialog.layout().addWidget(buttons) buttons.accepted.connect(dialog.accept) # buttons.rejected.connect(dialog.reject()) if dialog.exec_() == QDialog.Accepted: Resource = Application.resources("palette")[self.cmb_palettes.currentText()] Resource.setName(paletteName.text()) self.currentPalette = Palette(Resource) self.currentPalette.setColumnCount(paletteColumns.value()) self.paletteView.setPalette(self.currentPalette) self.slot_fill_combobox() self.currentPalette.setComment(paletteComment.toPlainText()) self.currentPalette.save() def slot_export_to_gimp_palette(self): palette_exporter_gimppalette.gimpPaletteExporter(self.cmb_palettes.currentText()) def slot_export_to_inkscape_svg(self): palette_exporter_inkscapeSVG.inkscapeSVGExporter(self.cmb_palettes.currentText()) def slot_sort_colors(self): colorSorter = palette_sortColors.sortColors(self.cmb_palettes.currentText()) self.paletteView.setPalette(colorSorter.palette()) def canvasChanged(self, canvas): self.cmb_palettes.clear() allPalettes = Application.resources("palette") for palette_name in allPalettes: self.cmb_palettes.addItem(palette_name) self.cmb_palettes.model().sort(0) if self.currentPalette == None and len(allPalettes.keys()) > 0: self.currentPalette = Palette(allPalettes[list(allPalettes.keys())[0]]) # Add docker to the application :) Application.addDockWidgetFactory(DockWidgetFactory("palette_docker", DockWidgetFactoryBase.DockRight, Palette_Docker)) diff --git a/plugins/python/palette_docker/palette_exporter_gimppalette.py b/plugins/python/palette_docker/palette_exporter_gimppalette.py index c0f7091f66..3724ab89e2 100644 --- a/plugins/python/palette_docker/palette_exporter_gimppalette.py +++ b/plugins/python/palette_docker/palette_exporter_gimppalette.py @@ -1,73 +1,73 @@ ''' A script that converts the palette with the given name to a gimp palette at the location asked for. By Wolthera(originally) 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 @package palette_docker ''' # Importing the relevant dependencies: import sys from PyQt5.QtWidgets import QFileDialog, QMessageBox import math from krita import * class gimpPaletteExporter: def __init__(self, name): # We want people to select a palette and a location to save to... self.fileName = QFileDialog.getExistingDirectory() allPalettes = Application.resources("palette") self.paletteName = name self.currentPalette = Palette(allPalettes[self.paletteName]) self.export() done = QMessageBox() - done.setWindowTitle("Export successful") - done.setText(self.paletteName + " has been exported to " + self.fileName + "!") + done.setWindowTitle(i18n("Export Successful")) + done.setText(str(i18n("{input} has been exported to {output}.")).format(input=self.paletteName, output=self.fileName)) done.exec_() pass def export(self): # open the appropriate file... gplFile = open(self.fileName + "/" + self.paletteName + ".gpl", "w") gplFile.write("GIMP Palette\n") gplFile.write("Name: " + self.paletteName + "\n") gplFile.write("Columns: " + str(self.currentPalette.columnCount()) + "\n") gplFile.write("#" + self.currentPalette.comment() + "\n") colorCount = self.currentPalette.colorsCountGroup("") for i in range(colorCount): entry = self.currentPalette.colorSetEntryFromGroup(i, "") color = self.currentPalette.colorForEntry(entry) # convert to sRGB color.setColorSpace("RGBA", "U8", "sRGB built-in") red = max(min(int(color.componentsOrdered()[0] * 255), 255), 0) green = max(min(int(color.componentsOrdered()[1] * 255), 255), 0) blue = max(min(int(color.componentsOrdered()[2] * 255), 255), 0) gplFile.write(str(red) + " " + str(green) + " " + str(blue) + " " + entry.id() + "-" + entry.name() + "\n") groupNames = self.currentPalette.groupNames() for groupName in groupNames: colorCount = self.currentPalette.colorsCountGroup(groupName) for i in range(colorCount): entry = self.currentPalette.colorSetEntryFromGroup(i, groupName) color = self.currentPalette.colorForEntry(entry) # convert to sRGB color.setColorSpace("RGBA", "U8", "sRGB built-in") red = max(min(int(color.componentsOrdered()[0] * 255), 255), 0) green = max(min(int(color.componentsOrdered()[1] * 255), 255), 0) blue = max(min(int(color.componentsOrdered()[2] * 255), 255), 0) gplFile.write(str(red) + " " + str(green) + " " + str(blue) + " " + entry.id() + "-" + entry.name() + "\n") gplFile.close() diff --git a/plugins/python/palette_docker/palette_exporter_inkscapeSVG.py b/plugins/python/palette_docker/palette_exporter_inkscapeSVG.py index 913600db37..f782ca2059 100644 --- a/plugins/python/palette_docker/palette_exporter_inkscapeSVG.py +++ b/plugins/python/palette_docker/palette_exporter_inkscapeSVG.py @@ -1,186 +1,186 @@ ''' A script that converts the palette named "Default" to a SVG so that Inkscape may use the colors The icc-color stuff doesn't work right, because we'd need the ability to get the url of the colorprofile somehow, and then we can make color-profile things in the definitions. By Wolthera(originally) 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 @package palette_docker ''' # Importing the relevant dependencies: import sys from PyQt5.QtXml import QDomDocument from PyQt5.QtWidgets import QFileDialog, QMessageBox import math from krita import * class inkscapeSVGExporter: def __init__(self, name): # We want people to select a palette and a location to save to... self.fileName = QFileDialog.getExistingDirectory() allPalettes = Application.resources("palette") self.paletteName = name self.currentPalette = Palette(allPalettes[self.paletteName]) self.export() done = QMessageBox() - done.setWindowTitle("Export successful") - done.setText(self.paletteName + " has been exported to " + self.fileName + "!") + done.setWindowTitle(i18n("Export Successful")) + done.setText(str(i18n("{input} has been exported to {output}.")).format(input=self.paletteName, output=self.fileName)) done.exec_() pass def export(self): # open the appropriate file... svgFile = open(self.fileName + "/" + self.paletteName + ".svg", "w") svgDoc = QDomDocument() svgBaseElement = svgDoc.createElement("svg") svgBaseElement.setAttribute("xmlns:osb", "http://www.openswatchbook.org/uri/2009/osb") svgBaseElement.setAttribute("xmlns:svg", "http://www.w3.org/2000/svg") svgBaseElement.setAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/") svgBaseElement.setAttribute("xmlns:cc", "http://creativecommons.org/ns#") svgBaseElement.setAttribute("xmlns:rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#") svgDefs = svgDoc.createElement("defs") svgSwatches = svgDoc.createElement("g") svgSwatches.setAttribute("id", "Swatches") svgMeta = svgDoc.createElement("metadata") svgBaseElement.appendChild(svgMeta) rdf = svgDoc.createElement("rdf:RDF") ccwork = svgDoc.createElement("cc:Work") dctitle = svgDoc.createElement("dc:title") dcdescription = svgDoc.createElement("dc:description") dctitle.appendChild(svgDoc.createTextNode(self.paletteName)) dcdescription.appendChild(svgDoc.createTextNode(self.currentPalette.comment())) ccwork.appendChild(dctitle) ccwork.appendChild(dcdescription) rdf.appendChild(ccwork) svgMeta.appendChild(rdf) Row = 0 Column = 0 iccProfileList = [] colorCount = self.currentPalette.colorsCountGroup("") for i in range(colorCount): entry = self.currentPalette.colorSetEntryFromGroup(i, "") color = self.currentPalette.colorForEntry(entry) iccColor = "icc-color(" + color.colorProfile() for c in range(len(color.componentsOrdered()) - 1): iccColor = iccColor + "," + str(color.componentsOrdered()[c]) iccColor = iccColor + ")" if color.colorProfile() not in iccProfileList: iccProfileList.append(color.colorProfile()) # convert to sRGB color.setColorSpace("RGBA", "U8", "sRGB built-in") red = max(min(int(color.componentsOrdered()[0] * 255), 255), 0) green = max(min(int(color.componentsOrdered()[1] * 255), 255), 0) blue = max(min(int(color.componentsOrdered()[2] * 255), 255), 0) hexcode = "#" + str(format(red, '02x')) + str(format(green, '02x')) + str(format(blue, '02x')) swatchName = str(i) + "-" + entry.name() swatchName = swatchName.replace(" ", "-") swatchName = swatchName.replace("(", "-") swatchName = swatchName.replace(")", "-") swatchMain = svgDoc.createElement("linearGradient") swatchMain.setAttribute("osb:paint", "solid") swatchMain.setAttribute("id", swatchName) swatchSub = svgDoc.createElement("stop") swatchSub.setAttribute("style", "stop-color: " + hexcode + " " + iccColor + ";stop-opacity:1;") swatchMain.appendChild(swatchSub) svgDefs.appendChild(swatchMain) svgSingleSwatch = svgDoc.createElement("rect") svgSingleSwatch.setAttribute("x", str(int(Column * 20))) svgSingleSwatch.setAttribute("y", str(int(Row * 20))) svgSingleSwatch.setAttribute("width", str(int(20))) svgSingleSwatch.setAttribute("height", str(int(20))) svgSingleSwatch.setAttribute("fill", "url(#" + swatchName + ")") svgSingleSwatch.setAttribute("id", "swatch" + swatchName) if entry.spotColor() is True: svgSingleSwatch.setAttribute("rx", str(10)) svgSingleSwatch.setAttribute("ry", str(10)) svgSwatches.appendChild(svgSingleSwatch) Column += 1 if (Column >= self.currentPalette.columnCount()): Column = 0 Row += 1 groupNames = self.currentPalette.groupNames() for groupName in groupNames: Column = 0 Row += 1 groupTitle = svgDoc.createElement("text") groupTitle.setAttribute("x", str(int(Column * 20))) groupTitle.setAttribute("y", str(int(Row * 20) + 15)) groupTitle.appendChild(svgDoc.createTextNode(groupName)) svgSwatches.appendChild(groupTitle) Row += 1 colorCount = self.currentPalette.colorsCountGroup(groupName) for i in range(colorCount): entry = self.currentPalette.colorSetEntryFromGroup(i, groupName) color = self.currentPalette.colorForEntry(entry) iccColor = "icc-color(" + color.colorProfile() for c in range(len(color.componentsOrdered()) - 1): iccColor = iccColor + "," + str(color.componentsOrdered()[c]) iccColor = iccColor + ")" if color.colorProfile() not in iccProfileList: iccProfileList.append(color.colorProfile()) # convert to sRGB color.setColorSpace("RGBA", "U8", "sRGB built-in") red = max(min(int(color.componentsOrdered()[0] * 255), 255), 0) green = max(min(int(color.componentsOrdered()[1] * 255), 255), 0) blue = max(min(int(color.componentsOrdered()[2] * 255), 255), 0) hexcode = "#" + str(format(red, '02x')) + str(format(green, '02x')) + str(format(blue, '02x')) swatchName = groupName + str(i) + "-" + entry.name() swatchName = swatchName.replace(" ", "-") swatchName = swatchName.replace("(", "-") swatchName = swatchName.replace(")", "-") swatchMain = svgDoc.createElement("linearGradient") swatchMain.setAttribute("osb:paint", "solid") swatchMain.setAttribute("id", swatchName) swatchSub = svgDoc.createElement("stop") swatchSub.setAttribute("style", "stop-color: " + hexcode + " " + iccColor + ";stop-opacity:1;") swatchMain.appendChild(swatchSub) svgDefs.appendChild(swatchMain) svgSingleSwatch = svgDoc.createElement("rect") svgSingleSwatch.setAttribute("x", str(int(Column * 20))) svgSingleSwatch.setAttribute("y", str(int(Row * 20))) svgSingleSwatch.setAttribute("width", str(int(20))) svgSingleSwatch.setAttribute("height", str(int(20))) svgSingleSwatch.setAttribute("fill", "url(#" + swatchName + ")") svgSingleSwatch.setAttribute("id", "swatch " + swatchName) if entry.spotColor() is True: svgSingleSwatch.setAttribute("rx", str(10)) svgSingleSwatch.setAttribute("ry", str(10)) svgSwatches.appendChild(svgSingleSwatch) Column += 1 if (Column >= self.currentPalette.columnCount()): Column = 0 Row += 1 for profile in iccProfileList: svgProfileDesc = svgDoc.createElement("color-profile") svgProfileDesc.setAttribute("name", profile) # This is incomplete because python api doesn't have any way to ask for this data yet. # svgProfileDesc.setAttribute("local", "sRGB") # svgProfileDesc.setAttribute("xlink:href", colorprofileurl) svgProfileDesc.setAttribute("rendering-intent", "perceptual") svgDefs.appendChild(svgProfileDesc) svgBaseElement.appendChild(svgDefs) svgBaseElement.appendChild(svgSwatches) svgBaseElement.setAttribute("viewBox", "0 0 " + str(self.currentPalette.columnCount() * 20) + " " + str(int((Row + 1) * 20))) svgDoc.appendChild(svgBaseElement) svgFile.write(svgDoc.toString()) svgFile.close() diff --git a/plugins/python/quick_settings_docker/quick_settings_docker.py b/plugins/python/quick_settings_docker/quick_settings_docker.py index 1add2d6a18..9d27ae8a3b 100644 --- a/plugins/python/quick_settings_docker/quick_settings_docker.py +++ b/plugins/python/quick_settings_docker/quick_settings_docker.py @@ -1,175 +1,175 @@ ''' Description: A Python based docker for quickly choosing the brushsize like similar dockers in other drawing programs. By Wolthera(originally) 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 @package quick_settings_docker ''' # Importing the relevant dependencies: import sys from PyQt5.QtCore import pyqtSlot, Qt, QPointF from PyQt5.QtGui import QStandardItem, QStandardItemModel, QPainter, QPalette, QPixmap, QImage, QBrush, QPen, QIcon from PyQt5.QtWidgets import QWidget, QTabWidget, QListView, QVBoxLayout from krita import * class QuickSettingsDocker(DockWidget): # Init the docker def __init__(self): super(QuickSettingsDocker, self).__init__() # make base-widget and layout widget = QWidget() layout = QVBoxLayout() widget.setLayout(layout) - self.setWindowTitle("Quick Settings Docker") + self.setWindowTitle(i18n("Quick Settings Docker")) tabWidget = QTabWidget() self.brushSizeTableView = QListView() self.brushSizeTableView.setViewMode(QListView.IconMode) self.brushSizeTableView.setMovement(QListView.Static) self.brushSizeTableView.setResizeMode(QListView.Adjust) self.brushSizeTableView.setUniformItemSizes(True) self.brushSizeTableView.setSelectionMode(QListView.SingleSelection) self.brushOpacityTableView = QListView() self.brushOpacityTableView.setViewMode(QListView.IconMode) self.brushOpacityTableView.setMovement(QListView.Static) self.brushOpacityTableView.setResizeMode(QListView.Adjust) self.brushOpacityTableView.setUniformItemSizes(True) self.brushOpacityTableView.setSelectionMode(QListView.SingleSelection) self.brushFlowTableView = QListView() self.brushFlowTableView.setViewMode(QListView.IconMode) self.brushFlowTableView.setMovement(QListView.Static) self.brushFlowTableView.setResizeMode(QListView.Adjust) self.brushFlowTableView.setUniformItemSizes(True) self.brushFlowTableView.setSelectionMode(QListView.SingleSelection) - tabWidget.addTab(self.brushSizeTableView, "Size") - tabWidget.addTab(self.brushOpacityTableView, "Opacity") - tabWidget.addTab(self.brushFlowTableView, "Flow") + tabWidget.addTab(self.brushSizeTableView, i18n("Size")) + tabWidget.addTab(self.brushOpacityTableView, i18n("Opacity")) + tabWidget.addTab(self.brushFlowTableView, i18n("Flow")) layout.addWidget(tabWidget) self.setWidget(widget) # Add the widget to the docker. # amount of columns in each row for all the tables. # We want a grid with possible options to select. # To do this, we'll make a ListView widget and use a standarditemmodel for the entries. # The entries are filled out based on the sizes and opacity lists. # Sizes and opacity lists. The former is half-way copied from ptsai, the latter is based on personal experience of useful opacities. self.sizesList = [0.7, 1.0, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 20, 25, 30, 35, 40, 50, 60, 70, 80, 100, 120, 160, 200, 250, 300, 350, 400, 450, 500] self.opacityList = [0.1, 0.5, 1, 5, 10, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100] self.brushSizeModel = QStandardItemModel() self.brushOpacityModel = QStandardItemModel() self.brushFlowModel = QStandardItemModel() self.fillSizesModel() self.fillOpacityModel() # Now we're done filling out our tables, we connect the views to the functions that'll change the settings. self.brushSizeTableView.clicked.connect(self.setBrushSize) self.brushOpacityTableView.clicked.connect(self.setBrushOpacity) self.brushFlowTableView.clicked.connect(self.setBrushFlow) def fillSizesModel(self): # First we empty the old model. We might wanna use this function in the future to fill it with the brushmask of the selected brush, but there's currently no API for recognising changes in the current brush nor is there a way to get its brushmask. self.brushSizeModel.clear() for s in range(len(self.sizesList)): # we're gonna itterate over our list, and make a new item for each entry. # We need to disable a bunch of stuff to make sure people won't do funny things to our entries. item = QStandardItem() item.setCheckable(False) item.setEditable(False) item.setDragEnabled(False) item.setText(str(self.sizesList[s])+" px") # And from here on we'll make an icon. brushImage = QPixmap(64, 64) img = QImage(64, 64, QImage.Format_RGBA8888) circlePainter = QPainter() img.fill(Qt.transparent) circlePainter.begin(img) brush = QBrush(Qt.SolidPattern) brush.setColor(self.brushSizeTableView.palette().color(QPalette.Text)) circlePainter.setBrush(brush) circlePainter.setPen(QPen(QBrush(Qt.transparent), 0)) brushSize = max(min(self.sizesList[s], 64), 1) brushSize = brushSize * 0.5 circlePainter.drawEllipse(QPointF(32, 32), brushSize, brushSize) circlePainter.end() brushImage = QPixmap.fromImage(img) # now we're done with drawing the icon, so we set it on the item. item.setIcon(QIcon(brushImage)) self.brushSizeModel.appendRow(item) self.brushSizeTableView.setModel(self.brushSizeModel) def fillOpacityModel(self): self.brushOpacityModel.clear() self.brushFlowModel.clear() for s in range(len(self.opacityList)): # we're gonna itterate over our list, and make a new item for each entry. item = QStandardItem() item.setCheckable(False) item.setEditable(False) item.setDragEnabled(False) item.setText(str(self.opacityList[s])+" %") brushImage = QPixmap(64, 64) img = QImage(64, 64, QImage.Format_RGBA8888) circlePainter = QPainter() img.fill(Qt.transparent) circlePainter.begin(img) brush = QBrush(Qt.SolidPattern) brush.setColor(self.brushSizeTableView.palette().color(QPalette.Text)) circlePainter.setBrush(brush) circlePainter.setPen(QPen(QBrush(Qt.transparent), 0)) circlePainter.setOpacity(float(self.opacityList[s]) / 100.0) circlePainter.drawEllipse(QPointF(32, 32), 32, 32) circlePainter.end() brushImage = QPixmap.fromImage(img) item.setIcon(QIcon(brushImage)) # the flow and opacity models will use virtually the same items, but Qt would like us to make sure we understand # these are not really the same items, so hence the clone. itemFlow = item.clone() self.brushOpacityModel.appendRow(item) self.brushFlowModel.appendRow(itemFlow) self.brushOpacityTableView.setModel(self.brushOpacityModel) self.brushFlowTableView.setModel(self.brushFlowModel) def canvasChanged(self, canvas): pass @pyqtSlot('QModelIndex') def setBrushSize(self, index): i = index.row() brushSize = self.sizesList[i] if Application.activeWindow() and len(Application.activeWindow().views()) > 0: Application.activeWindow().views()[0].setBrushSize(brushSize) @pyqtSlot('QModelIndex') def setBrushOpacity(self, index): i = index.row() brushOpacity = float(self.opacityList[i]) / 100.0 if Application.activeWindow() and len(Application.activeWindow().views()) > 0: Application.activeWindow().views()[0].setPaintingOpacity(brushOpacity) @pyqtSlot('QModelIndex') def setBrushFlow(self, index): i = index.row() brushOpacity = float(self.opacityList[i]) / 100.0 if Application.activeWindow() and len(Application.activeWindow().views()) > 0: Application.activeWindow().views()[0].setPaintingFlow(brushOpacity) # Add docker to the application :) Application.addDockWidgetFactory(DockWidgetFactory("quick_settings_docker", DockWidgetFactoryBase.DockRight, QuickSettingsDocker)) diff --git a/plugins/python/scriptdocker/scriptdocker.py b/plugins/python/scriptdocker/scriptdocker.py index a113f2d851..3b865c610a 100644 --- a/plugins/python/scriptdocker/scriptdocker.py +++ b/plugins/python/scriptdocker/scriptdocker.py @@ -1,66 +1,66 @@ ''' 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 ''' rom PyQt5.QtWidgets import (QWidget, QVBoxLayout, QListView, QFormLayout, QHBoxLayout, QPushButton, QLineEdit, QListWidget) from PyQt5.QtCore import QObject import krita class ScriptDocker(krita.DockWidget): def __init__(self): super(ScriptDocker, self).__init__() self.baseWidget = QWidget() self.layout = QVBoxLayout() self.scriptsLayout = QFormLayout() - self.addButton = QPushButton("Add Script") + self.addButton = QPushButton(i18n("Add Script")) self.actions = [] self.layout.addLayout(self.scriptsLayout) self.layout.addWidget(self.addButton) self.baseWidget.setLayout(self.layout) self.setWidget(self.baseWidget) - self.setWindowTitle("Script Docker") + self.setWindowTitle(i18n("Script Docker")) self.addButton.clicked.connect(self.addNewRow) def canvasChanged(self, canvas): pass def addNewRow(self): directorySelectorLayout = QHBoxLayout() directoryTextField = QLineEdit() - directoryDialogButton = QPushButton("...") + directoryDialogButton = QPushButton(i18n("...")) directoryDialogButton.clicked.connect(self.test) directorySelectorLayout.addWidget(directoryTextField) directorySelectorLayout.addWidget(directoryDialogButton) - self.scriptsLayout.addRow("Script {0}".format(self.scriptsLayout.rowCount() + 1), directorySelectorLayout) + self.scriptsLayout.addRow(str(i18n("Script {0}")).format(self.scriptsLayout.rowCount() + 1), directorySelectorLayout) def test(self): obj = self.sender() print('button', obj) def loadActions(self): pass def readSettings(self): pass def writeSettings(self): pass Application.addDockWidgetFactory(krita.DockWidgetFactory("scriptdocker", krita.DockWidgetFactoryBase.DockRight, ScriptDocker)) diff --git a/plugins/python/scripter/ui_scripter/actions/closeaction/closeaction.py b/plugins/python/scripter/ui_scripter/actions/closeaction/closeaction.py index 064a889f53..3b5b5938fb 100644 --- a/plugins/python/scripter/ui_scripter/actions/closeaction/closeaction.py +++ b/plugins/python/scripter/ui_scripter/actions/closeaction/closeaction.py @@ -1,54 +1,55 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtWidgets import QAction, QMessageBox from PyQt5.QtGui import QKeySequence from PyQt5.QtCore import Qt +import krita class CloseAction(QAction): def __init__(self, scripter, parent=None): super(CloseAction, self).__init__(parent) self.scripter = scripter self.triggered.connect(self.close) - self.setText('Close') + self.setText(i18n("Close")) self.setObjectName('close') self.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q)) @property def parent(self): return 'File' def close(self): msgBox = QMessageBox(self.scripter.uicontroller.mainWidget) - msgBox.setInformativeText("Do you want to save the current document?") + msgBox.setInformativeText(i18n("Do you want to save the current document?")) msgBox.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) msgBox.setDefaultButton(QMessageBox.Save) ret = msgBox.exec_() if ret == QMessageBox.Cancel: return if ret == QMessageBox.Save: if not self.scripter.uicontroller.invokeAction('save'): return self.scripter.uicontroller.closeScripter() diff --git a/plugins/python/scripter/ui_scripter/actions/debugaction/debugaction.py b/plugins/python/scripter/ui_scripter/actions/debugaction/debugaction.py index e5ae9512ad..4063a8e7a0 100644 --- a/plugins/python/scripter/ui_scripter/actions/debugaction/debugaction.py +++ b/plugins/python/scripter/ui_scripter/actions/debugaction/debugaction.py @@ -1,46 +1,47 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtWidgets import QAction from PyQt5.QtGui import QIcon, QPixmap, QKeySequence from scripter import resources_rc from PyQt5.QtCore import Qt +import krita class DebugAction(QAction): def __init__(self, scripter, parent=None): super(DebugAction, self).__init__(parent) self.scripter = scripter self.triggered.connect(self.debug) - self.setText('Debug') - self.setToolTip('Debug Ctrl+D') + self.setText(i18n("Debug")) + self.setToolTip(i18n("Debug Ctrl+D")) self.setIcon(QIcon(':/icons/debug.svg')) self.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_D)) @property def parent(self): return 'toolBar' def debug(self): if self.scripter.uicontroller.invokeAction('save'): self.scripter.uicontroller.setActiveWidget('Debugger') self.scripter.debugcontroller.start(self.scripter.documentcontroller.activeDocument) widget = self.scripter.uicontroller.findTabWidget('Debugger') widget.startDebugger() diff --git a/plugins/python/scripter/ui_scripter/actions/newaction/newaction.py b/plugins/python/scripter/ui_scripter/actions/newaction/newaction.py index e5761f2b7e..d446281fad 100644 --- a/plugins/python/scripter/ui_scripter/actions/newaction/newaction.py +++ b/plugins/python/scripter/ui_scripter/actions/newaction/newaction.py @@ -1,56 +1,57 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtWidgets import QAction, QMessageBox from PyQt5.QtGui import QKeySequence from PyQt5.QtCore import Qt +import krita class NewAction(QAction): def __init__(self, scripter, parent=None): super(NewAction, self).__init__(parent) self.scripter = scripter self.triggered.connect(self.new) - self.setText('New') + self.setText(i18n("New")) self.setObjectName('new') self.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_N)) @property def parent(self): return 'File' def new(self): msgBox = QMessageBox(self.scripter.uicontroller.mainWidget) - msgBox.setText("The document has been modified.") - msgBox.setInformativeText("Do you want to save your changes?") + msgBox.setText(i18n("The document has been modified.")) + msgBox.setInformativeText(i18n("Do you want to save your changes?")) msgBox.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) msgBox.setDefaultButton(QMessageBox.Save) ret = msgBox.exec_() if ret == QMessageBox.Cancel: return if ret == QMessageBox.Save: self.scripter.uicontroller.invokeAction('save') self.scripter.documentcontroller.clearActiveDocument() self.scripter.uicontroller.setStatusBar() self.scripter.uicontroller.clearEditor() diff --git a/plugins/python/scripter/ui_scripter/actions/openaction/openaction.py b/plugins/python/scripter/ui_scripter/actions/openaction/openaction.py index 209b371185..eb88385e9d 100644 --- a/plugins/python/scripter/ui_scripter/actions/openaction/openaction.py +++ b/plugins/python/scripter/ui_scripter/actions/openaction/openaction.py @@ -1,57 +1,58 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtWidgets import QAction, QFileDialog, QMessageBox from PyQt5.QtGui import QKeySequence from PyQt5.QtCore import Qt +import krita import os class OpenAction(QAction): def __init__(self, scripter, parent=None): super(OpenAction, self).__init__(parent) self.scripter = scripter self.triggered.connect(self.open) - self.setText('Open') + self.setText(i18n("Open")) self.setObjectName('open') self.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_O)) @property def parent(self): return 'File' def open(self): dialog = QFileDialog(self.scripter.uicontroller.mainWidget) - dialog.setNameFilter('Python files (*.py)') + dialog.setNameFilter(i18n("Python Files (*.py)")) if dialog.exec_(): try: selectedFile = dialog.selectedFiles()[0] _, fileExtension = os.path.splitext(selectedFile) if fileExtension == '.py': document = self.scripter.documentcontroller.openDocument(selectedFile) self.scripter.uicontroller.setDocumentEditor(document) self.scripter.uicontroller.setStatusBar(document.filePath) except Exception: QMessageBox.information(self.scripter.uicontroller.mainWidget, - 'Invalid File', - 'Open files with .py extension') + i18n("Invalid File"), + i18n("Open files with .py extension")) diff --git a/plugins/python/scripter/ui_scripter/actions/reloadaction/reloadaction.py b/plugins/python/scripter/ui_scripter/actions/reloadaction/reloadaction.py index 7b6ebbb0e3..ec142f21dc 100644 --- a/plugins/python/scripter/ui_scripter/actions/reloadaction/reloadaction.py +++ b/plugins/python/scripter/ui_scripter/actions/reloadaction/reloadaction.py @@ -1,62 +1,63 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtWidgets import QAction, QMessageBox from PyQt5.QtGui import QKeySequence from PyQt5.QtCore import Qt +import krita class ReloadAction(QAction): def __init__(self, scripter, parent=None): super(ReloadAction, self).__init__(parent) self.scripter = scripter self.editor = self.scripter.uicontroller.editor self.triggered.connect(self.reloadFile) - self.setText('Reload File') + self.setText(i18n("Reload File")) self.setObjectName('reloadfile') self.setShortcut(QKeySequence(Qt.ALT + Qt.Key_R)) @property def parent(self): return 'File' def reloadFile(self): # get the currently open document's path curr_doc_fpath = '' document = self.scripter.documentcontroller._activeDocument if document is None: QMessageBox.critical(self.scripter.uicontroller.mainWidget, - 'No existing document', - 'Please specify a document by opening it before reloading') + i18n("No existing document"), + i18n("Please specify a document by opening it before reloading")) return else: curr_doc_fpath = document.filePath # clear the editor self.scripter.documentcontroller.clearActiveDocument() self.scripter.uicontroller.setStatusBar() self.scripter.uicontroller.clearEditor() # reload the document document = self.scripter.documentcontroller.openDocument(curr_doc_fpath) self.scripter.uicontroller.setDocumentEditor(document) self.scripter.uicontroller.setStatusBar(document.filePath) return document diff --git a/plugins/python/scripter/ui_scripter/actions/runaction/runaction.py b/plugins/python/scripter/ui_scripter/actions/runaction/runaction.py index 66f2d909d1..98dfb2b550 100644 --- a/plugins/python/scripter/ui_scripter/actions/runaction/runaction.py +++ b/plugins/python/scripter/ui_scripter/actions/runaction/runaction.py @@ -1,155 +1,156 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtWidgets import QAction from PyQt5.QtGui import QIcon, QKeySequence from PyQt5.QtCore import Qt import sys import traceback import inspect from . import docwrapper +import krita if sys.version_info[0] > 2: import importlib from importlib.machinery import SourceFileLoader else: import imp PYTHON27 = sys.version_info.major == 2 and sys.version_info.minor == 7 PYTHON33 = sys.version_info.major == 3 and sys.version_info.minor == 3 PYTHON34 = sys.version_info.major == 3 and sys.version_info.minor == 4 EXEC_NAMESPACE = "__main__" # namespace that user scripts will run in class RunAction(QAction): def __init__(self, scripter, parent=None): super(RunAction, self).__init__(parent) self.scripter = scripter self.editor = self.scripter.uicontroller.editor self.output = self.scripter.uicontroller.findTabWidget('OutPut', 'OutPutTextEdit') self.triggered.connect(self.run) - self.setText('Run') + self.setText(i18n("Run")) self.setToolTip('Run Ctrl+R') self.setIcon(QIcon(':/icons/run.svg')) self.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_R)) @property def parent(self): return 'toolBar' def run(self): """ This method execute python code from an activeDocument (file) or direct from editor (ui_scripter/editor/pythoneditor.py). When executing code from a file, we use importlib to load this module/file and with "users_script" name. That's implementation seeks for a "main()" function in the script. When executing code from editor without creating a file, we compile this script to bytecode and we execute this in an empty scope. That's faster than use exec directly and cleaner, because we are using an empty scope. """ self.scripter.uicontroller.setActiveWidget('OutPut') stdout = sys.stdout stderr = sys.stderr output = docwrapper.DocWrapper(self.output.document()) if (self.editor._documentModified is True): output.write("==== Warning: Script not saved! ====\n") else: output.write("======================================\n") sys.stdout = output sys.stderr = output script = self.editor.document().toPlainText() document = self.scripter.documentcontroller.activeDocument try: if document and self.editor._documentModified is False: if PYTHON27: users_module = self.run_py2_document(document) else: users_module = self.run_py3_document(document) # maybe script is to be execed, maybe main needs to be invoked # if there is a main() then execute it, otherwise don't worry... if hasattr(users_module, "main") and inspect.isfunction(users_module.main): users_module.main() else: code = compile(script, '', 'exec') globals_dict = {"__name__": EXEC_NAMESPACE} exec(code, globals_dict) except Exception: # Provide context (line number and text) for an error that is caught. # Ordinarily, syntax and Indent errors are caught during initial # compilation in exec(), and the traceback traces back to this file. # So these need to be treated separately. # Other errors trace back to the file/script being run. type_, value_, traceback_ = sys.exc_info() if type_ == SyntaxError: errorMessage = "%s\n%s" % (value_.text.rstrip(), " " * (value_.offset - 1) + "^") # rstrip to remove trailing \n, output needs to be fixed width font for the ^ to align correctly errorText = "Syntax Error on line %s" % value_.lineno elif type_ == IndentationError: # (no offset is provided for an IndentationError errorMessage = value_.text.rstrip() errorText = "Unexpected Indent on line %s" % value_.lineno else: errorText = traceback.format_exception_only(type_, value_)[0] format_string = "In file: {0}\nIn function: {2} at line: {1}. Line with error:\n{3}" tbList = traceback.extract_tb(traceback_) tb = tbList[-1] errorMessage = format_string.format(*tb) m = "\n**********************\n%s\n%s\n**********************\n" % (errorText, errorMessage) output.write(m) sys.stdout = stdout sys.stderr = stderr # scroll to bottom of output bottom = self.output.verticalScrollBar().maximum() self.output.verticalScrollBar().setValue(bottom) def run_py2_document(self, document): """ Loads and executes an external script using Python 2 specific operations and returns the loaded module for further execution if needed. """ try: user_module = imp.load_source(EXEC_NAMESPACE, document.filePath) except Exception as e: raise e return user_module def run_py3_document(self, document): """ Loads and executes an external script using Python 3 specific operations and returns the loaded module for further execution if needed. """ spec = importlib.util.spec_from_file_location(EXEC_NAMESPACE, document.filePath) try: users_module = importlib.util.module_from_spec(spec) spec.loader.exec_module(users_module) except AttributeError as e: # no module from spec if PYTHON34 or PYTHON33: loader = SourceFileLoader(EXEC_NAMESPACE, document.filePath) users_module = loader.load_module() else: raise e return users_module diff --git a/plugins/python/scripter/ui_scripter/actions/saveaction/saveaction.py b/plugins/python/scripter/ui_scripter/actions/saveaction/saveaction.py index 4fea1c0e89..887395ba8b 100644 --- a/plugins/python/scripter/ui_scripter/actions/saveaction/saveaction.py +++ b/plugins/python/scripter/ui_scripter/actions/saveaction/saveaction.py @@ -1,62 +1,63 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtWidgets import QAction, QFileDialog from PyQt5.QtGui import QKeySequence from PyQt5.QtCore import Qt +import krita class SaveAction(QAction): def __init__(self, scripter, parent=None): super(SaveAction, self).__init__(parent) self.scripter = scripter self.editor = self.scripter.uicontroller.editor self.triggered.connect(self.save) - self.setText('Save') + self.setText(i18n("Save")) self.setObjectName('save') self.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S)) @property def parent(self): return 'File' def save(self): text = self.editor.toPlainText() fileName = '' if not self.scripter.documentcontroller.activeDocument: fileName = QFileDialog.getSaveFileName(self.scripter.uicontroller.mainWidget, - 'Save Python File', '', - 'Python File (*.py)')[0] + i18n("Save Python File"), '', + i18n("Python File (*.py)"))[0] if not fileName: return # don't validate file name - trust user to specify the extension they want # getSaveFileName will add ".py" if there is no extension. # It will strip a trailing period and, in each case, test for file collisions document = self.scripter.documentcontroller.saveDocument(text, fileName) if document: self.scripter.uicontroller.setStatusBar(document.filePath) else: self.scripter.uicontroller.setStatusBar('untitled') self.editor._documentModified = False self.scripter.uicontroller.setStatusModified() return document diff --git a/plugins/python/scripter/ui_scripter/actions/saveasaction/saveasaction.py b/plugins/python/scripter/ui_scripter/actions/saveasaction/saveasaction.py index 97c1e8509f..2687e44bfa 100644 --- a/plugins/python/scripter/ui_scripter/actions/saveasaction/saveasaction.py +++ b/plugins/python/scripter/ui_scripter/actions/saveasaction/saveasaction.py @@ -1,60 +1,61 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtWidgets import QAction, QFileDialog from PyQt5.QtGui import QKeySequence from PyQt5.QtCore import Qt +import krita class SaveAsAction(QAction): def __init__(self, scripter, parent=None): super(SaveAsAction, self).__init__(parent) self.scripter = scripter self.editor = self.scripter.uicontroller.editor self.triggered.connect(self.save) - self.setText('Save As') + self.setText(i18n("Save As")) self.setObjectName('saveas') self.setShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_S)) @property def parent(self): return 'File' def save(self): text = self.editor.toPlainText() fileName = QFileDialog.getSaveFileName(self.scripter.uicontroller.mainWidget, - 'Save Python File', '', - 'Python File (*.py)')[0] + i18n("Save Python File"), '', + i18n("Python File (*.py)"))[0] if not fileName: return # don't validate file name - trust user to specify the extension they want # getSaveFileName will add ".py" if there is no extension. # It will strip a trailing period and, in each case, test for file collisions document = self.scripter.documentcontroller.saveDocument(text, fileName, save_as=True) if document: self.scripter.uicontroller.setStatusBar(document.filePath) else: self.scripter.uicontroller.setStatusBar('untitled') self.editor._documentModified = False self.scripter.uicontroller.setStatusModified() return document diff --git a/plugins/python/scripter/ui_scripter/actions/settingsaction/settingsaction.py b/plugins/python/scripter/ui_scripter/actions/settingsaction/settingsaction.py index 34f0f88b96..c5e138e851 100644 --- a/plugins/python/scripter/ui_scripter/actions/settingsaction/settingsaction.py +++ b/plugins/python/scripter/ui_scripter/actions/settingsaction/settingsaction.py @@ -1,49 +1,50 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtWidgets import QAction from PyQt5.QtCore import Qt from . import settingsdialog +import krita class SettingsAction(QAction): def __init__(self, scripter, parent=None): super(SettingsAction, self).__init__(parent) self.scripter = scripter self.triggered.connect(self.openSettings) self.settingsDialog = settingsdialog.SettingsDialog(self.scripter) self.settingsDialog.setWindowModality(Qt.WindowModal) self.settingsDialog.setFixedSize(400, 250) - self.setText('Settings') + self.setText(i18n("Settings")) @property def parent(self): return 'File' def openSettings(self): self.settingsDialog.show() self.settingsDialog.exec_() def readSettings(self): self.settingsDialog.readSettings(self.scripter.settings) def writeSettings(self): self.settingsDialog.writeSettings(self.scripter.settings) diff --git a/plugins/python/scripter/ui_scripter/actions/settingsaction/settingsdialog.py b/plugins/python/scripter/ui_scripter/actions/settingsaction/settingsdialog.py index fd80bd9807..f9df6c880a 100644 --- a/plugins/python/scripter/ui_scripter/actions/settingsaction/settingsdialog.py +++ b/plugins/python/scripter/ui_scripter/actions/settingsaction/settingsdialog.py @@ -1,41 +1,42 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtWidgets import QDialog, QFormLayout from . import syntaxstylescombobox, fontscombobox +import krita class SettingsDialog(QDialog): def __init__(self, scripter, parent=None): super(SettingsDialog, self).__init__(parent) self.scripter = scripter - self.setWindowTitle('Settings') + self.setWindowTitle(i18n("Settings")) self.mainLayout = QFormLayout(self) - self.mainLayout.addRow('Syntax Highlither', syntaxstylescombobox.SyntaxStylesComboBox(self.scripter.uicontroller.highlight, self.scripter.uicontroller.editor)) - self.mainLayout.addRow('Fonts', fontscombobox.FontsComboBox(self.scripter.uicontroller.editor)) + self.mainLayout.addRow(i18n("Syntax highlighter:"), syntaxstylescombobox.SyntaxStylesComboBox(self.scripter.uicontroller.highlight, self.scripter.uicontroller.editor)) + self.mainLayout.addRow(i18n("Fonts:"), fontscombobox.FontsComboBox(self.scripter.uicontroller.editor)) def readSettings(self, settings): for index in range(self.mainLayout.rowCount()): widget = self.mainLayout.itemAt(index, QFormLayout.FieldRole).widget() widget.readSettings(settings) def writeSettings(self, settings): for index in range(self.mainLayout.rowCount()): widget = self.mainLayout.itemAt(index, QFormLayout.FieldRole).widget() widget.writeSettings(settings) diff --git a/plugins/python/scripter/ui_scripter/tabwidgets/debuggerwidget/stepaction.py b/plugins/python/scripter/ui_scripter/tabwidgets/debuggerwidget/stepaction.py index 6385290d77..097b40a7eb 100644 --- a/plugins/python/scripter/ui_scripter/tabwidgets/debuggerwidget/stepaction.py +++ b/plugins/python/scripter/ui_scripter/tabwidgets/debuggerwidget/stepaction.py @@ -1,41 +1,42 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtWidgets import QAction from PyQt5.QtGui import QIcon from scripter import resources_rc +import krita class StepAction(QAction): def __init__(self, scripter, toolbar, parent=None): super(StepAction, self).__init__(parent) self.scripter = scripter self.toolbar = toolbar self.triggered.connect(self.step) - self.setText('Step Over') + self.setText(i18n("Step Over")) # path to the icon self.setIcon(QIcon(':/icons/step.svg')) def step(self): status = self.scripter.debugcontroller.isActive if status: self.scripter.debugcontroller.step() else: self.toolbar.disableToolbar(True) diff --git a/plugins/python/scripter/ui_scripter/tabwidgets/debuggerwidget/stopaction.py b/plugins/python/scripter/ui_scripter/tabwidgets/debuggerwidget/stopaction.py index 47aeb8d5cc..1d49380919 100644 --- a/plugins/python/scripter/ui_scripter/tabwidgets/debuggerwidget/stopaction.py +++ b/plugins/python/scripter/ui_scripter/tabwidgets/debuggerwidget/stopaction.py @@ -1,38 +1,39 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtWidgets import QAction from PyQt5.QtGui import QIcon from scripter import resources_rc +import krita class StopAction(QAction): def __init__(self, scripter, toolbar, parent=None): super(StopAction, self).__init__(parent) self.scripter = scripter self.toolbar = toolbar self.triggered.connect(self.stop) - self.setText('Stop') + self.setText(i18n("Stop")) # path to the icon self.setIcon(QIcon(':/icons/stop.svg')) def stop(self): self.scripter.debugcontroller.stop() self.toolbar.disableToolbar(True) diff --git a/plugins/python/scripter/ui_scripter/tabwidgets/outputwidget/clearaction.py b/plugins/python/scripter/ui_scripter/tabwidgets/outputwidget/clearaction.py index c86ec7eea0..d23bc3fba0 100644 --- a/plugins/python/scripter/ui_scripter/tabwidgets/outputwidget/clearaction.py +++ b/plugins/python/scripter/ui_scripter/tabwidgets/outputwidget/clearaction.py @@ -1,37 +1,38 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtWidgets import QAction from PyQt5.QtGui import QIcon from scripter import resources_rc +import krita class ClearAction(QAction): def __init__(self, scripter, toolbar, parent=None): super(ClearAction, self).__init__(parent) self.scripter = scripter self.toolbar = toolbar self.triggered.connect(self.clear) - self.setText('Clear') + self.setText(i18n("Clear")) # path to the icon # self.setIcon(QIcon(':/icons/clear.svg')) def clear(self): self.toolbar.outputtextedit.clear() diff --git a/plugins/python/scripter/uicontroller.py b/plugins/python/scripter/uicontroller.py index e02cabb330..d663c355ca 100644 --- a/plugins/python/scripter/uicontroller.py +++ b/plugins/python/scripter/uicontroller.py @@ -1,264 +1,265 @@ """ Copyright (c) 2017 Eliakin Costa This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ from PyQt5.QtCore import Qt, QObject, QFileInfo, QRect from PyQt5.QtGui import QTextCursor, QPalette from PyQt5.QtWidgets import (QToolBar, QMenuBar, QTabWidget, QLabel, QVBoxLayout, QMessageBox, QSplitter, QSizePolicy) from .ui_scripter.syntax import syntax, syntaxstyles from .ui_scripter.editor import pythoneditor from . import scripterdialog import importlib +import krita KEY_GEOMETRY = "geometry" DEFAULT_GEOMETRY = QRect(600, 200, 400, 500) # essentially randomly placed class Elided_Text_Label(QLabel): mainText = str() def __init__(self, parent=None): super(QLabel, self).__init__(parent) self.setMinimumWidth(self.fontMetrics().width("...")) self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) def setMainText(self, text=str()): self.mainText = text self.elideText() def elideText(self): self.setText(self.fontMetrics().elidedText(self.mainText, Qt.ElideRight, self.width())) def resizeEvent(self, event): self.elideText() class UIController(object): documentModifiedText = "" documentStatusBarText = "untitled" def __init__(self): self.mainWidget = scripterdialog.ScripterDialog(self) self.actionToolbar = QToolBar('toolBar', self.mainWidget) self.menu_bar = QMenuBar(self.mainWidget) self.actionToolbar.setObjectName('toolBar') self.menu_bar.setObjectName('menuBar') self.actions = [] self.mainWidget.setWindowModality(Qt.NonModal) def initialize(self, scripter): self.editor = pythoneditor.CodeEditor(scripter) self.tabWidget = QTabWidget() self.statusBar = Elided_Text_Label() self.statusBar.setMainText('untitled') self.splitter = QSplitter() self.splitter.setOrientation(Qt.Vertical) self.highlight = syntax.PythonHighlighter(self.editor.document(), syntaxstyles.DefaultSyntaxStyle()) p = self.editor.palette() p.setColor(QPalette.Base, syntaxstyles.DefaultSyntaxStyle()['background'].foreground().color()) p.setColor(QPalette.Text, syntaxstyles.DefaultSyntaxStyle()['foreground'].foreground().color()) self.editor.setPalette(p) self.scripter = scripter self.loadMenus() self.loadWidgets() self.loadActions() self._readSettings() # sets window size vbox = QVBoxLayout(self.mainWidget) vbox.addWidget(self.menu_bar) vbox.addWidget(self.actionToolbar) self.splitter.addWidget(self.editor) self.splitter.addWidget(self.tabWidget) vbox.addWidget(self.splitter) vbox.addWidget(self.statusBar) - self.mainWidget.setWindowTitle("Scripter") + self.mainWidget.setWindowTitle(i18n("Scripter")) self.mainWidget.setSizeGripEnabled(True) self.mainWidget.show() self.mainWidget.activateWindow() self.editor.undoAvailable.connect(self.setStatusModified) def loadMenus(self): self.addMenu('File', 'File') def addMenu(self, menuName, parentName): parent = self.menu_bar.findChild(QObject, parentName) self.newMenu = None if parent: self.newMenu = parent.addMenu(menuName) else: self.newMenu = self.menu_bar.addMenu(menuName) self.newMenu.setObjectName(menuName) return self.newMenu def loadActions(self): module_path = 'scripter.ui_scripter.actions' actions_module = importlib.import_module(module_path) modules = [] for class_path in actions_module.action_classes: _module = class_path[:class_path.rfind(".")] _klass = class_path[class_path.rfind(".") + 1:] modules.append(dict(module='{0}.{1}'.format(module_path, _module), klass=_klass)) for module in modules: m = importlib.import_module(module['module']) action_class = getattr(m, module['klass']) obj = action_class(self.scripter) parent = self.mainWidget.findChild(QObject, obj.parent) self.actions.append(dict(action=obj, parent=parent)) for action in self.actions: action['parent'].addAction(action['action']) def loadWidgets(self): modulePath = 'scripter.ui_scripter.tabwidgets' widgetsModule = importlib.import_module(modulePath) modules = [] for class_path in widgetsModule.widgetClasses: _module = class_path[:class_path.rfind(".")] _klass = class_path[class_path.rfind(".") + 1:] modules.append(dict(module='{0}.{1}'.format(modulePath, _module), klass=_klass)) for module in modules: m = importlib.import_module(module['module']) widgetClass = getattr(m, module['klass']) obj = widgetClass(self.scripter) self.tabWidget.addTab(obj, obj.objectName()) def invokeAction(self, actionName): for action in self.actions: if action['action'].objectName() == actionName: method = getattr(action['action'], actionName) if method: return method() def findTabWidget(self, widgetName, childName=''): for index in range(self.tabWidget.count()): widget = self.tabWidget.widget(index) if widget.objectName() == widgetName: if childName: widget = widget.findChild(QObject, childName) return widget def showException(self, exception): - QMessageBox.critical(self.editor, "Error running script", str(exception)) + QMessageBox.critical(self.editor, i18n("Error Running Script"), str(exception)) def setDocumentEditor(self, document): self.editor.clear() self.editor.moveCursor(QTextCursor.Start) self.editor._documentModified = False self.editor.setPlainText(document.data) self.editor.moveCursor(QTextCursor.End) def setStatusBar(self, value='untitled'): self.documentStatusBarText = value self.statusBar.setMainText(self.documentStatusBarText + self.documentModifiedText) def setStatusModified(self): self.documentModifiedText = "" if (self.editor._documentModified is True): self.documentModifiedText = " [Modified]" self.statusBar.setMainText(self.documentStatusBarText + self.documentModifiedText) def setActiveWidget(self, widgetName): widget = self.findTabWidget(widgetName) if widget: self.tabWidget.setCurrentWidget(widget) def setStepped(self, status): self.editor.setStepped(status) def clearEditor(self): self.editor.clear() def repaintDebugArea(self): self.editor.repaintDebugArea() def closeScripter(self): self.mainWidget.close() def _writeSettings(self): """ _writeSettings is a method invoked when the scripter starts, making control inversion. Actions can implement a writeSettings method to save your own settings without this method to know about it. """ self.scripter.settings.beginGroup('scripter') document = self.scripter.documentcontroller.activeDocument if document: self.scripter.settings.setValue('activeDocumentPath', document.filePath) else: self.scripter.settings.setValue('activeDocumentPath', '') self.scripter.settings.setValue('editorFontSize', self.editor.fontInfo().pointSize()) for action in self.actions: writeSettings = getattr(action['action'], "writeSettings", None) if callable(writeSettings): writeSettings() # Window Geometry rect = self.mainWidget.geometry() self.scripter.settings.setValue(KEY_GEOMETRY, rect) self.scripter.settings.endGroup() def _readSettings(self): """ It's similar to _writeSettings, but reading the settings when the ScripterDialog is closed. """ self.scripter.settings.beginGroup('scripter') activeDocumentPath = self.scripter.settings.value('activeDocumentPath', '') if activeDocumentPath: if QFileInfo(activeDocumentPath).exists(): document = self.scripter.documentcontroller.openDocument(activeDocumentPath) self.setStatusBar(document.filePath) self.setDocumentEditor(document) for action in self.actions: readSettings = getattr(action['action'], "readSettings", None) if callable(readSettings): readSettings() pointSize = self.scripter.settings.value('editorFontSize', str(self.editor.fontInfo().pointSize())) self.editor.setFontSize(int(pointSize)) # Window Geometry rect = self.scripter.settings.value(KEY_GEOMETRY, DEFAULT_GEOMETRY) self.mainWidget.setGeometry(rect) self.scripter.settings.endGroup() def _saveSettings(self): self.scripter.settings.sync() diff --git a/plugins/python/selectionsbagdocker/selectionsbagdocker.py b/plugins/python/selectionsbagdocker/selectionsbagdocker.py index 78784353e4..5d90cfedb2 100644 --- a/plugins/python/selectionsbagdocker/selectionsbagdocker.py +++ b/plugins/python/selectionsbagdocker/selectionsbagdocker.py @@ -1,31 +1,31 @@ ''' 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 ''' from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5 import uic from krita import * import os class SelectionsBagDocker(DockWidget): def __init__(self): super().__init__() widget = QWidget(self) uic.loadUi(os.path.dirname(os.path.realpath(__file__)) + '/selectionsbagdocker.ui', widget) self.setWidget(widget) - self.setWindowTitle("Selections bag") + self.setWindowTitle(i18n("Selections Bag")) def canvasChanged(self, canvas): print("Canvas", canvas)