Can two plugins send or read information between each other? I wonder this in order not too duplicate a bunch of code.
The thought just crossed my head. You import the other plugin as a module? Is that a thing? I need to test it.
yes a module imported by a plugin X is available for plugin Y
I currently have the problem of 2 plugins for which there’s a module with the same name and then, there’s a plugin cor which module is not as expected because already loaded by another one…
just have to think : you don’t know in which order plugins will be loaded, neither if both plugins will be available for user…
Oh that is a curious situation then. I wonder I placing the import in the startup Def would not solve that then.
The startup is the last thing to run after all the inits. It is how I solve all the formatting issues I had with pigmento while loading with the scaling menus that still don’t know they do stuff.
But between plugins I really donno I am still not at the computer to test it out.
Doing a import on the
def showEvent(self, event): as I was thinking does not work. PyQt did not like it and even told me otherwise hehehe.
I rewrote a quick extension for pigmento to try and connect them by sending a signals from the extension shortcut action into the docker and trigger one of its functions inside, however something is not allowing the connection to be made. I took a screenshot of the important stuff I added to connect them.
Krita responds to the Extension inputs but Pigmentostays silent on the initialize of the Extension lines to connect the signal. is this the wrong approach or some odd typo?
There’s a wrong approach I think.
I don’t have all the code under my eye, but I suppose that pigment_o_extension.py is initialised at startup?
If yes, In pigment_o_docker.py in Extension method, line 1642, you’re creating a new instance of extension, and it’s not the same than the one created at startup.
Here a working example with 2 differents plugins (i’m not sure if you have 2 plugins intalled or if docker and extension are installed from the same plugin… )
It’s one possible implementation, I choose the simplest for me
Plugin testA (create action, emit signal)
from PyQt5.Qt import * from PyQt5.QtCore import pyqtSignal as Signal from krita import * EXTENSION_ID = 'pykrita_testA' class TestA(Extension): colorChanged = Signal(QColor) def __init__(self, parent): super().__init__(parent) # store current instance of extension as a property of krita instance Krita.instance().setProperty('testA', self) def setup(self): pass def createActions(self, window): # create actions actionRed = window.createAction(EXTENSION_ID+'red', "Test color: Red", "tools/scripts") actionRed.triggered.connect(self.actionRed) actionGreen = window.createAction(EXTENSION_ID+'green', "Test color: Green", "tools/scripts") actionGreen.triggered.connect(self.actionGreen) actionBlue = window.createAction(EXTENSION_ID+'blue', "Test color: Blue", "tools/scripts") actionBlue.triggered.connect(self.actionBlue) def actionRed(self): # emit signal for red color self.colorChanged.emit(QColor(Qt.red)) def actionGreen(self): # emit signal for green color self.colorChanged.emit(QColor(Qt.green)) def actionBlue(self): # emit signal for blue color self.colorChanged.emit(QColor(Qt.blue))
from .testa import TestA # And add the extension to Krita's list of extensions: app = Krita.instance() # Instantiate your class: extension = TestA(parent=app) app.addExtension(extension)
[Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=testa X-Python-2-Compatible=false X-Krita-Manual=Manual.html Name=TestA Comment=TestA plugin
Plugin testD (docker, receive signal from plugin testA)
from PyQt5.Qt import * from krita import * EXTENSION_ID = 'pykrita_testd' MENU_ENTRY = 'TestD script' class WColoredBox(QWidget): """A simple widget to display color""" def __init__(self, parent=None): super(WColoredBox, self).__init__(parent) self.__color=QColor(Qt.black) self.setMinimumSize(100,100) def paintEvent(self, event): canvas=QPainter(self) canvas.fillRect(event.rect(), QBrush(self.__color)) def setColor(self, color): if isinstance(color, QColor): self.__color=color self.update() def color(self): return self.__color class WTestD(QWidget): """Docker UI content""" def __init__(self, parent=None): super(WTestD, self).__init__(parent) self.__initialised=False # initialise ui layout=QVBoxLayout(self) self.__lbl=QLabel('Black') self.__lbl.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Maximum) self.__color=WColoredBox(self) self.__connectedTestAExtension=None layout.addWidget(self.__lbl) layout.addWidget(self.__color) # if krita 5.0.0, this is the best method #self.__notifier=Krita.instance().notifier() #self.__notifier.windowCreated.connect(self.__initialise) def __initialise(self): if self.__initialised: # do not apply initialisation more than one time return # retrieve instance of plugin testA self.__connectedTestAExtension=Krita.instance().property('testA') if not self.__connectedTestAExtension is None: # instance found (plugin installed and initialised) self.__connectedTestAExtension.colorChanged.connect(self.__actionFromTestA) # ensure to do this action only one time self.__initialised=True def __actionFromTestA(self, color): # set color provided from extension plugin self.__lbl.setText(color.name()) self.__color.setColor(color) def initialise(self): self.__initialise() class TestD(DockWidget): """Class to manage current selection""" def __init__(self): super(TestD, self).__init__() self.setWindowTitle('TestD plugin') self.__ui=WTestD() self.setWidget(self.__ui) def canvasChanged(self, canvas): """notifies when views are added or removed""" # if krita 4, windowCreated() signal doesn't work and then, dirty method.. self.__ui.initialise()
from krita import DockWidgetFactory, DockWidgetFactoryBase from .testd import * instance = Krita.instance() testDocker = DockWidgetFactory(f'testd_test_docker', DockWidgetFactoryBase.DockRight, TestD) instance.addDockWidgetFactory(testDocker)
[Desktop Entry] Type=Service ServiceTypes=Krita/PythonPlugin X-KDE-Library=testd X-Python-2-Compatible=false X-Krita-Manual=Manual.html Name=TestD Comment=TestD plugin
I just think about this possibility:
Krita already maintains a list of extensions then, the
property() usage can be replaced by a search in the returned list
# my_extension_a/extension.py from krita import ( Krita, Extension) class MyExtensionA(Extension): def find_my_buddy(self): from my_extension_b.extension import MyExtensionB app = Krita.instance() buddy = next((e for e in app.extensions() if isinstance(e, MyExtensionB)), None) print(buddy)
# my_extension_b/extension.py from krita import ( Krita, Extension) class MyExtensionB(Extension): def find_my_buddy(self): from my_extension_a.extension import MyExtensionA app = Krita.instance() buddy = next((e for e in app.extensions() if isinstance(e, MyExtensionA)), None) print(buddy)
This should work. (not tested)
Note that if
my_extension_x/__init__.py module is imported ie.
import my_extension_x, then any plugin registering code would run, so it’s better to keep
class MyExtensionX(Extension) in separate file, so it can be imported, without triggering registering.
it is accepting it look
I am using shortcut keys to change the values here, but I am gonna try build up a bit more on top of it.
There are things accessible to Extensions that are not too Dockers by default so I will be able to some new tricks like this.
The way I have it set up is to have one init to kick start both Docker and Extension as if they were two different plugins.
# Imports from krita import * from PyQt5 import * from .pigment_o_docker import * from .pigment_o_extension import * # Name the Python Script for the program DOCKER_ID = "pykrita_pigment_o_docker" # Register Krita Docker Application.addDockWidgetFactory( DockWidgetFactory(DOCKER_ID, DockWidgetFactoryBase.DockRight, PigmentODocker) ) # Register Krita Extension Krita.instance().addExtension(PigmentOExtension(Krita.instance()))
Having them talk to each other I can open more doors, one that was closed was action shortcuts that are better than key events by far.
In this case things could be simplified; You can register extension before Docker and then when docker is created you can do connection immediately, without having to use my trick to initialize connection through windowCreated() signal or canvasChanged() event.