CoolBox : A Blender like toolbox plugin for Krita

CoolBox : A Blender like toolbox plugin for Krita

This time is not just a standalone mockup or a proof of concept, it is a real working toolbox right inside Krita.

A bit of background, so last November, gave the new Blender 2.8  a shot one morning. The new UI though threw me off for a bit was pretty, looked similar to the other cool apps in the town. And I went on to recreate that on Qt, which I did by midnight with some spaghetti code. Surprisingly that thing got some traction on hackernews for a day and died off, me too also left that as an one hit wonder. That was until, a couple months ago, people started discussion about improving Krita's current UI in Krita Artists. In the flow of conversation, my proof of concept got mentioned and that was enough to ignite others with different ideas.

People were trying to hack something similar to that in Krita, but more or less nobody was exactly sure how to proceed, or if it could be done with the current plugin API or not. And me being not the best developer in Python tried to stay away from it for sometime, but curiosity got me at last.

On the first look at the API, it looked rather simple exposing a set of higher level functions to Python. And thanks to this vscode extension, I got something usable up in a few minutes of first poking into that.

The code is, I would say rather simple if you are familiar with Qt. The tool box is a QWidget whose paintEvent was overridden and same is for the popup. Also I take control of the mouse events too along with the drawing.

class ToolBox(QWidget):
    .
    .
    .
    def paintEvent(self, event):
        painter = QPainter()
        painter.begin(self)
        self.drawTools(painter, event.rect().topLeft() + QPoint(10, 5))
        painter.end()
    
    def drawTools(self, painter, topLeft):
        size = QSize(40, 40)
        drawRect = QRect(topLeft, size)
        for tool in self.tools:
            drawRect = QRect(topLeft, size)
            tool.paint(painter, drawRect)
            topLeft += QPoint(0, 45)
        self.setFixedSize(50, 45 * len(self.tools) + 5)
    .
    .
    .

The Tool class is just a container to hold data related to the tool and it's sub-tools. Though it also does some drawing of its own, by borrowing the QPainter from either ToolBox or Popup classes.

class Tool:
    .
    .
    .   
    def paint(self, painter, rect):
        self.toolRect = rect
        path = QPainterPath()
        path.addRoundedRect(QRectF(rect), 3, 3)
        color = highlightColor if self.isActivated or self.highlighted else backColor 
        painter.fillPath(path, color)
        newRect = rect.adjusted(10, 10, -10, -10)
        icon = Application.icon(self.icon)
        painter.drawPixmap(newRect, icon.pixmap(newRect.size()))

        if len(self.subTools) > 0 :
            triangle = QPainterPath()
            triangle.moveTo(rect.bottomRight())
            triangle.lineTo(rect.bottomRight() + QPoint(0, -5))
            triangle.lineTo(rect.bottomRight() + QPoint(-5, 0))
            painter.fillPath(triangle, Qt.white)
    .
    .
    .

If you want to try the plugin out, do grab it from here.

Some know issues

  • This tool box doesn't actually syncs with the original toolbox so, if you try to use the both at the same time, beware.
  • This a fixed tool box, can't be edited unless something is changed in the code. This is a feature not an issue.
  • The colors are hardcoded, might look awkward in some themes.

What is to be done ahead?

  • Obviously fix the known issues.
  • Add text hinting for the tools.
  • Add a couple more items like Undo/Redo in the bottom? just a random thought.

If you are trying and have some issues or suggestions, do drop them here or in Github issues.