This is an earlier version of the plugin, maybe more a Proof Of Concept than a real plugin, there’s some bug and missing functionalities (example: currently don’t manage plugin provided with Krita)
The plugin works but there’s still many work to do before having something that I can publish in v1.0.0 (ie: version that you can use)
Do not use it on Krita installation you’re using to draw: install and test it on a testing instance
This plugin has been written:
To understand how Krita manage the plugin
To provide a concrete foundation around which we can work to propose and find solutions
3 Buttons to:
– Install a new plugin from zip archive
– Uninstall a plugin
– Activate/Deactivate a plugin (note: you can also check/uncheck checbox from list)
What’s working?
Consider that plugin xxxx is managed
Install a plugin
The plugin manager doesn’t reinvent wheel, and I mostly be inspired by the Python Plugin Importer:
Load a ZIP archive
Check content validity (xxxx.desktop and xxxx/__init__.py files)
Unzip files to the right place
– xxxx.desktop in pykrita directory
– xxxx.action in actions directory (if file exists)
– xxxx/* in pykrita directory
Activate plugin automatically after installation
Uninstall a plugin
This function is not complete, but currently:
Deactivate plugin if activated
Delete all plugins’ files from disk
– xxxx.desktop from pykrita directory
– xxxx.action from actions directory (if file exists)
– xxxx/* from pykrita directory
Activate a plugin
Ok, here it start to be tricky…
When a plugin is activated:
Analyse loaded extensions, and for extensions that has been loaded from plugin xxxx
– Execute setup() method if exists
– Execute createActions() method if exists
Probably, the plugin have created a new entry in menu…
– Search for new action(s)
– If found, do the freaky tweak to add action in menu
(because it seems that actions are created only at Krita’s startup)
From here, the plugin is loaded and ready to be used by user in Krita, without need to restart
Note
For plugins using Docker, unfortunately I’m currently not able to activate docker without having to restart Krita
Looking in Settings > Configure Krita > Python Plugin Manager the newly installed/activated plugin is not available yet: I think the plugin list is loaded at startup and is not refreshed when opened
Unload all modules from plugin xxxx
This is not fully operational, and might never be fully operational
Note:
Once again, concerning plugins with Docker, I currently can’t do anything (no time to dig more)
Removing action from menu is not possible because there’s currently no way to determinate which plugin added which menu entry
– I can implement a method, but it will work only for plugin that have been installed/activated by plugin manager…
Looking in Settings > Configure Krita > Python Plugin Manager the newly uninstalled/deactivated plugin status is not available yet: I think the plugin list is loaded at startup and is not refreshed when opened
What can be improved in Krita?
Now, to be able to continue on this plugin, I think we need to think further about some points.
From my point of view, are currently concerned:
The Extension class
The DockWidget class
The Window class
The Settings > Configure Krita > Python Plugin Manager window
The Extension class
Currently, the Extension class provide 2 methods (that does nothing by default):
setup()
createActions()
Here is a proposition of methods that an Extension could provides:
Extension.id() New method
Return the plugin Id that have created the extension
Note: a plugin can create more than one extension class, but all have the same plugin id
The goal is to be able to identify easily which plugin create which extension
Extension.actions() New method
Return list of actions created by extension (this will allow to remove them from menu easily when plugin is deactivated)
Extension.addAction(id, name, location) New method
Create a new action for extension
Basically:
– do a call to Window.createAction()
– store action in a list internal to extension
– return action
Extension.removeAction(id) New method
Remove action created by extension and identified by id (does nothing if tries to remove an actions that has not been created by extension)
Extension.createActions() Unchanged method
Called at Krita’s startup
Called when plugin is activated
Extension.setup() Unchanged method
Called at Krita’s startup
Called when plugin is activated
Extension.cleanup() new method
Called when plugin is deactivated
Allows plugin to made some cleanup and avoid having stuff created by plugin everywhere
For example, if plugin have created files and/or directories to work, delete them
Example of an extension:
class MyExtension(Extension):
def __init__(self, parent, pluginId=None):
super().__init__(parent, pluginId)
def setup(self):
# executed when plugin is activated
pass
def cleanup(self):
# executed when plugin is deactivated
pass
def createActions(self, window)
# ==> unchanged, except the method to create an action
action = self.addAction("my_extension_id", "My extension")
action.triggered.connect(self.do_some_stuff)
Krita.instance().addExtension(MyExtension(Krita.instance(), 'my_extension_id))
The DockWidget class
Currently I’m not able to propose anything as I never used them.
But from what I saw with activation/deactivation plugin, we need something that allow to create/delete docker dynamically, not only at Krita startup.
The Window class
For now, I think to a have function that allows to apply change to window menu.
Something like menuUpdate()
Anyway, a function that is able to apply changes to menu and add/remove actions that has been added/removed by plugin
The Settings > Configure Krita > Python Plugin Manager window
This window is currently not aware of changes.
So, when the window is displayed, it should:
update the list of installed plugins
take in account changes made in kritarc file (plugins enabled/disabled)
Another thing is:
Don’t have the time now the formalise this point properly, but to ensure that a plugin manager can manage all plugins, there’s might be some norms to write about a plugin zip archive content.
I think that 95% already exists (desktop file, init.py file, …) but I have in mind few additional things that I’ll try to expose later.
Any idea/comment to improve how plugins can be installed/deinstalled without having to restart are welcome
@EyeOdin, concerning docker I think you’re the one who have created the most docker plugin?
If you already have some idea about improvment of DockWidget class for a better integration in a plugin management system, please share
@Kapyia I don’t know if you have wishes about this part? Concerning API bugs&improvements, I will create a new topic later (I need some times to formalize what’s in my mind) but you can always create a topic and/or prepare your wishlist to share it when the topic will be created
Item to add to list (improve Python Plugins/Extensions/Dockers):
Krita.loadPlugin(“PluginName”): makes sure that plugin with given name is loaded. Currently plugin dependancy asks user to load some plugin & restart Krita. (User may become bit angry when PluginA asks PluginB ask PluginC asks PluginD asks …) and each step user must click enabled & restart.
Sorry for the late response I did not notice the question for me when I got the notice.
What comes more up to mind is more on the teaching how to use the docker class in the Krita site where I think is a very convoluted method and not practical. Mostly how the code is distributed through out the various files and how to load the UI. I just think the UI file should be preserved and not converted to a python file as they say only on smaller scripts it is worth.
Some other stuff not sure if it helps with Dockers directley but I guess might for Plugins in general:
load addon without reset but I think it might be impossible request due to PyQt5. but lowering the amount of reboots after installing would be amazing, and having the “Import Python Plugin” active by default would be nice. Sometimes I go to a live session of Linux to test something and I need to brute force through a bunch of reboots (x3reboots) and the inability to boot Krita as it keeps crashing constantly (x20crashes x3reboots = 60reboots). Just One reboot or without reboot would be so so nice but everyone knows about it already.
the docker name changes when it is floating. goes from “Plugin” to “&Plugin”. it is really strange behaviour I know it is nice to identificate it’s state but it is not intuitive. strangely on Linux I don’t see it on the Header wich is curious. Also non floating dockers work faster for some weird reason and I don’t know why.
Restricted to signals inside the docker you create. But I think it is just a PyQt5 thing that is hard coded on hard parenting works there. I was still hoping to have the API open those Qt events like brush up and down. Dockers are like a isolated island.
One thing that has crossed my mind before is to make like 2 dockers connect to each other. I know this sounds stupid but might unlock some stuff. But might be a silly idea. So like pre register or a code for another another class or something so they could talk? Don’t ask I wake up with weird ideas when I wake up.
One thing not related to dockers that has been on my mind recently is “Modal Operators” like in blender. I made a post already but I think it is really hard to implement I thought about it to make stuff like on mouse cardinal options and other things that run operators until the user gives a input. The event system on Blender is just so much more better.
Another thing is having Plugins organized each in their own folders like all files inside it and not have the desktop file floating around mingling. I think this would help creation as much as distribuition. for the user it would be unzip and drag the folder here. for the creator it would help it sync with github since everything was contained inside the project folder.