Extension for painting application Krita, which allows to create custom, complex keyboard shortcuts.
The plugin adds new shortcuts of the following types:
Pie menu
- while key is pressed, displays a pie menu, which allows to pick values by hovering a mouse.Cursor tracker
- while key is pressed, tracks a cursor, switching values according to cursor offset.Canvas preview
- Temporarily changes canvas elements while the key is pressed.Multiple assignment
- repeatedly pressing a key, cycles between multiple values of krita property.Temporary key
- temporarily activates a krita property with long press or toggles it on/off with short press.
- [hotfix 1.2.2] - Fixed MultipleAssignment actions sharing one configuration window.
- [hotfix 1.2.1] - Fixed pie menus in edit mode hiding when clicked outside on the canvas.
- Adding and removing PieMenu icons with drag and drop.
- Class-oriented configuration system with automatic value parsing. Can be reused in other plugins.
- PieMenus are now able to handle their own local configuration with Pie settings (Replaces section in
Configure Shortcut Composer
). - Change PieIcon border's color when hovered in EditMode (Replaces gray indicator)
- Allow changes to PieMenu and PieIcon size for each pie separately.
- Separate button to enter PieMenu edit mode. Replaces clicking on PieIcon which was easy to do unintentionally.
- Preset PieMenus tag now can be chosen directly from the Pie settings. (Replaces section in
Configure Shortcut Composer
) - Preset PieMenus now reload automatically when the tag content changes. (Replaces
Reload Shortcut Composer
action) - PieMenus now automatically change between dark/light theme when the krita theme changes between these two theme families.
Cycle selection tools
action now is configured by local settings activated with a button that appears on long press (Replaces section inConfigure Shortcut Composer
)
- Support tags with quote and double-quote signs.
- Make
input_adapter
package independent from the rest of the plugin to improve re-usability. - Fix crash when picking a deleted preset with PieMenu.
Check out historic changelogs.
- Version of krita on plugin release: 5.1.5
- Required version of krita: 5.1.0
OS support state:
- Windows (10, 11)
- Linux (Ubuntu 20.04, 22.04)
- MacOS (Known bug of canvas losing focus after using PieMenu)
- Android (Does not support python plugins yet)
- on github project page, click the green button code and pick the download zip option. Do not extract it.
- in krita's topbar, open Tools > Scripts > Import Python Plugin From File and pick the downloaded .zip file
- restart krita.
- set custom shortcuts in Settings > Configure Krita > Keyboard Shortcuts under Scripts > Shortcut Composer: Complex Actions section. By intention, there are no default bindings.
While Shortcut-Composer is highly configurable and extendable, the add-on comes with pre-made, plug-and-play actions.
Pie menu is a widget displayed on the canvas while a key is pressed. It will disappear as soon, as the key is released. Moving cursor in a direction of an icon, activates its value on key release. The action only requires hovering. Pie menu does nothing if the cursor is not moved out of the deadzone.
Clicking the settings button in bottom-right corner switches into Edit mode
which allows to modify pie. At this point the keyboard button no longer needs to be pressed. In this mode values one can:
- drag icons to change their order
- drag icons out of the ring to remove them
- drag icons from the settings window to add them
Settings window visible in Edit mode
also allows to change the local settings of the pie. When done, press the tick button to apply the changes.
-
Three color coded pie menus that let you pick a brush preset from related tag with brush presets.
Used tag can be changed in pie settings by entering
Edit mode
. Presets in the pie depend on the tag, so they cannot be removed or added with dragging, but it is possible to change their order. When presets are added or remove from the tag, pie should update automatically.Default tag mapping is as follows:
- red: "โ My Favorites"
- green: "RGBA"
- blue: "Erasers"
-
Pie menu for picking active tools. It is recommended to change the default values being:
- crop tool,
- reference tool,
- gradient tool,
- multi_brush tool,
- assistant tool
-
Pie menu for picking painting blending modes. It is recommended to change the default values being:
- normal
- overlay,
- color,
- multiply,
- add,
- screen,
- darken,
- lighten
-
Pie menu for creating a new layer with picked blending mode. It is recommended to change the default values being:
- normal
- erase
- overlay,
- color,
- multiply,
- add,
- screen,
- darken,
- lighten
Cursor tracker is an action for switching values using cursor movement, while the keyboard key is pressed. It changes a single krita property according to the cursor movement along horizontal or vertical axis. The action does not recognise mouse clicks, and only requires hovering
-
Scrolls the layers by sliding the cursor vertically. Can be used for picking the active layer and analizing the layer stack. While the key is pressed, isolates the active layer to give better response of which layer is active.
- Key press: isloate active layer
- Horizontal: -
- Vertical: scroll all layers
-
Variation on "Scroll isolated layers" for animators. Scrolling is restricted only to layers pinned to the animation timeline. Horizontal mouse movement changes the current frame.
- Key press: isloate active layer
- Horizontal: scroll animation frames
- Vertical: scroll layers pinned to timeline
-
Extends the krita undo action ctrl+z. While the key is pressed, horizontal mouse movement controls the undo stack by performing undo and redo actions. Usual undo with short key press is still possible.
- Key press: undo last operation
- Horizontal: scroll left to undo, or right to redo
- Vertical: -
-
Allows to control both
brush size
oropacity
with a single key. Opacity changes contiguously with vertical mouse movement, while brush size snaps to custom values.- Key press: -
- Horizontal: scroll brush size (descrete)
- Vertical: scroll painting opacity (contiguous)
-
Allows to control both
canvas zoom
orcanvas rotation
with a single key. Does not block the ability to paint.- Key press: -
- Horizontal: canvas rotation (contiguous)
- Vertical: canvas zoom (contiguous)
Canvas preview is an action which changes canvas elements when the key is pressed, and changes them back to their original state on key release.
-
Changes active layer visibility on key press and release. Allows to quickly check layer's content.
-
Hides all visible layers above the active one on key press, and reverses this change on key release. Allows to check what is the position of current layer in a stack. It is possible to paint while action is active.
Multiple assignment is an action which cycles between multiple values of single krita property. Each key press activates next list element. Performing a long press breaks the cycle and sets a default value, which does not have to belong the the list.
-
Pressing a key repeatedly cycles most commonly used selection tools:
- freehand selection tool,
- rectangular selection tool,
- contiguous selection tool
Performing a long press, goes back to the
freehand brush tool
. Tools can be used while the key is pressed.Default values can be modified in
Edit mode
. To enter it, long press the button, and click on the button which appears in top-left corner of painting area.Values are added by selecting the list value(s) on the left and pressing the green add button. Analogically, selecting values on the right, and pressing the remove button, removes the values from action. Dragging values on the right, allow to change their order.
-
Pressing a key repeatedly cycles brush predefined opacity values:
100%
,70%
,50%
,30%
Performing a long press, goes back to the
100%
opacity. Modified opacity can be used while the key is pressed.Currently does not allow to configure predefined values without editing code.
-
Pressing a key temporarily activates the
move tool
which goes back to thefreehand brush tool
after the key release. Short key presses allow to permanently toggle between those two tools. -
Pressing a key temporarily activates the
eraser
mode which gets turned off after the key is released. Short key presses allow to permanently toggle between those two states. -
Pressing a key temporarily activates the
preserve alpha
mode which gets turned off after the key is released. Short key presses allow to permanently toggle between those two states.
Shortcut-Composer comes with a settings dialog available from krita topbar: Tools > Scripts > Configure Shortcut Composer. The dialog allows to change the following aspects of actions:
- Common settings
Short vs long press time
- Time in seconds distinguishing short key presses from long ones.FPS limit
- Maximum rate of Mouse Tracker and Pie Menu refresh.
- Cursor trackers
Tracker sensitivity scale
- Sensitivity multiplier of all Mouse Trackers.Tracker deadzone
- Amount of pixels a mouse needs to moved for Mouse Trackers to start work.
- Pie menus display
Pie global scale
- Global scale factor for base of every pie menu.Pie icon global scale
- Global scale factor for icons of every pie menu.Pie deadzone global scale
- Global scale factor for the deadzone area of every pie menu.Pie animation time
- Time (in seconds) for fade-in animation when showing the pie menu.
While the settings dialog allows to tweak the values common for plugin actions, it does not allow to modify the behaviour of the actions or create new ones.
To achieve that it is required to modify actions implementation:
- in krita's topbar, open Settings > Manage Resources > Open Resource Folder
- navigate to ./pykrita/shortcut_composer/ directory.
- action definitions are located in
actions.action
file. - actions implementation is located in
actions.py
file.
- Define an action in
actions.action
file by duplicating one of the existing definitions and using an unique name for it. - Implement an action in
actions.py
file. Once again, duplicate one of the existing implementations. It is best to pick the one that feels closest to desired action. Fill its arguments, making sure the name is exactly the same as defined earlier.
- Key bindings with modifiers like ctrl or shift are supported. When assigned to a key combination, the key is considered released when the main key in sequence (non-modifier) is released.
- Multiple shortcuts from this plugin can be used at the same time, unless bindings make it technically impossible. For example holding both keys for
Temporary eraser
andCycle painting opacity
result in an eraser with 70% opacity.
- Pressing a modifier while the usual key is pressed, will result in conflict. For instance, pressing ctrl while using temporary eraser assigned to x will result in unwanted ctrl+x operation which cuts current layer.
- It is possible to activate multiple pie menus at the same time.
- Keyboard shortcuts assigned to actions can conflict with Canvas Input (General limitation of Krita).
Some parts of plugin code solve general problems, which can apply outside of Shortcut Composer. Those solutions were placed in separate packages that can be copy-pasted into any other plugin and reused there.
They depend only on original Krita API and PyQt5 with which krita is shipped.
Package input_adapter
consists of ActionManager
and ComplexActionInterface
which together allow to recognise more keyboard events than usual krita action does.
While usual actions can only recognise key press, implementing ComplexActionInterface
lets you override methods performed on:
- key press
- short key release
- long key release
- every key release
Each action needs to have public name: str
attribute which is the same, as the one used in .action file, as well as short_vs_long_press_time: float
which determines how many seconds need to elapse to consider that a key press was long.
Use ActionManager
instance to bind objects of those custom actions to krita during CreateActions
phase:
"""
Print whether action key was released before of after
0.2 seconds from being pressed.
"""
from krita import Krita
from input_adapter import ActionManager, ComplexActionInterface
class CustomAction(ComplexActionInterface):
def __init__(self, name: str, press_time: float = 0.2):
self.name = name
self.short_vs_long_press_time = press_time
def on_key_press(self): print("key was pressed")
def on_short_key_release(self): print("key released before than 0.2s")
def on_long_key_release(self): print("key released later than after 0.2s")
def on_every_key_release(self): pass
class MyExtension(Extension):
def setup(self) -> None: pass
def createActions(self, window) -> None:
action = CustomAction(name="Custom action name")
self.manager = ActionManager(window)
self.manager.bind_action(action)
Krita.instance().addExtension(MyExtension(Krita.instance()))
Package config_system
consists of Field
and FieldGroup
which grant object-oriented API to control kritarc configuration file easier, than with API of krita.
Field
represents a single value in kritarc file. Once initialized with its group name, name and default value, it allows to:
- write a given value to kritarc.
- read current value from kritarc, parsing it to correct python type.
- reset the value to default.
- register a callback run on each value change.
Type of default value passed on initlization is remembered, and used to parse values both on read and write. Supported types are:
int
,list[int]
,float
,list[float]
,str
,list[str]
,bool
,list[bool]
,Enum
,list[Enum]
For empty, homogeneous lists, parser_type
argument must be used to determine type of list elements. Default values are not saved when until the field does not exist in kritarc. Repeated saves of the same value are filtered, so that callbacks are not called when the same value is written multiple times one after the other.
FieldGroup
represents a section of fields in kritarc file. It simplifies the field creation by auto-completing the group name.
FieldGroup holds and aggregates fields created with it. It allows to reset all the fields at once, and register a callback to all its fields: both existing and future ones.
Example usage:
from enum import Enum
from config_system import FieldGroup
class EnumMock(Enum):
MODE_A = 0
MODE_B = 1
# Create a config group
group = FieldGroup("MyGroup")
# Register a callback on all three fields
group.register_callback(lambda: print("any field changed"))
# Create three fields inside a group - for string and two enum lists
str_field = group.field(name="my_str", default="Sketch")
enums_field_1 = group.field("my_enums_1", [], parser_type=EnumMock)
enums_field_2 = group.field("my_enums_2", [EnumMock.MODE_A])
# Register a different callback on each field
str_field.register_callback(lambda: print("string changed"))
enums_field_1.register_callback(lambda: print("enum 1 changed"))
enums_field_2.register_callback(lambda: print("enum 2 changed"))
# Change the value from default "Sketch" to "Digital"
str_field.write("Digital")
# Change the value from empty list to one with two values
enums_field_1.write([EnumMock.MODE_A, EnumMock.MODE_B])
# Repeat the default value. Will be filtered
enums_field_2.write([EnumMock.MODE_A])
# The program will not break, as red values are the same as written ones
assert str_field.read() == "Digital"
assert enums_field_1.read() == [EnumMock.MODE_A, EnumMock.MODE_B]
assert enums_field_2.read() == [EnumMock.MODE_A]
The code above produces "MyGroup" section in kritarc file. my_enums_2 is missing, as the default value was not changed:
[MyGroup]
my_str=Digital
my_enums_1=MODE_A\tMODE_B
Registered callbacks outputs on the terminal:
any field changed
string changed
any field changed
enum 1 changed
Calling group.reset_defaults()
would change both values back to their defaults, and produce the same output on the terminal, as resetting changes the fields.
Package api_krita
wraps krita api offering PEP8 compatibility, typings, and docstring documentation. Most of objects attributes are now available as settables properties.
from .api_krita import Krita
from .api_krita.enums import BlendingMode, Tool, Toggle
# active tool operations
tool = Krita.active_tool # get current tool
Krita.active_tool = Tool.FREEHAND_BRUSH # set current tool
Tool.FREEHAND_BRUSH.activate() # set current tool (alternative way)
# operations on a document
document = Krita.get_active_document()
all_nodes = document.get_all_nodes() # all nodes with flattened structure
picked_node = all_nodes[3]
picked_node.name = "My layer name"
picked_node.visible = True
picked_node.opacity = 50 # remapped from 0-255 go 0-100 [%]
document.active_node = picked_node
document.refresh()
# Operations on a view
view = Krita.get_active_view()
view.brush_size = 100
view.blending_mode = BlendingMode.NORMAL # Enumerated blending modes
# Handling checkable actions
mirror_state = Toggle.MIRROR_CANVAS.state # get mirror state
Toggle.SOFT_PROOFING.state = False # turn off soft proofing
Toggle.PRESERVE_ALPHA.switch_state() # change state of preserve alpha
Only functionalities that were needed during this plugin development are wrapped, so some of them are not yet available. The syntax can also change over time.