Margins Support

Qutepart supports margins on the left hand side of the editor pane. Each margin has a unique string identifier and two margins are instantiated at the time the quitepart is created:

  • Line numbers margin

  • Marks margin which can display pylint messages and handles bookmarks

The line numbers margin uses the line_numbers identifier and the marks margin uses the mark_area identifier.

Qutepart Interface for Margins

Getting a list of margins

# Returns a list of the current margins
qpart.getMargins()

Looking up for a margin

# Returns a reference to the line numbers margin or None if not found
margin = qpart.getMargin("line_numbers")

Removing a margin

if qpart.delMargin("mark_area"):
    print("Mark area margin has been removed")
else:
    print("Mark area margin is not found")

Hiding/showing margins

margin = qpart.getMargin("line_numbers")
if margin:
    margin.hide()
    # later on the margin can be shown again: margin.show()

Adding a margin

margin1 = MyMargin1(qpart, ...)
margin2 = MyMargin2(qpart, ...)

# will add the margin as the most right
qpart.addMargin(margin1)

# will add the margin as the most left
# the second argument is a list index to be inserted at
qpart.addMargin(margin2, 0)

Custom Margins

Overview

All margins must derive from the QWidget and MarginBase classes. Due to some PyQT5 implementation details there is no good way to implement the hierarchy nicely so a workaround has been developed.

The custom margin code may look as follows:

class MyMargin(QWidget):
    """Custom margin
    """
    def __init__(self, parent)
        QWidget.__init__(self, parent)

        # Here is a hack to add MarginBase into a list of base classes
        # See qutepart/sideareas.py for details
        extend_instance(self, MarginBase)

        # Now the MarginBase constructor can be called
        MarginBase.__init__(self, parent, "my margin ID", 2)

    def width(self):
        # The width of the margin in pixels. The hight will be calculated
        # automatically as the height of the editor widget
        return 32

After that the margin could be added to the editor with the addMargin(...) call as described above.

Bits for marking blocks

The example above has the following initialization of the MarginBase:

MarginBase.__init__(self, parent, "my margin ID", 2)

The last argument is a number of bits the margin wants to reserve for marking blocks. The QPlainTextEditor class (a base for Qutepart) supports an integer value associated with each block. That value could be used to store some user information. In case of many margins it is possible that a few of them need to mark blocks, e.g. if a block is bookmarked. So to avoid conflicts in values stored in blocks each margin has to declare how many bits it needs and the bits are reserved for the margin automatically respecting what has already been reserved for the others. If a margin does not use any bits it should have 0 in the MarginBase.__init__(...) call.

Having some bits reserved a margin should not manipulate the block values directly. Instead it should used a couple of members provided by the MarginBase class:

  • setBlockValue(block, value) - checks the value range, do the appropriate shift and sets the block value without damaging the other margin values

  • getBlockValue(block) - retrieves the block value and does the appropriate shift and masking

So regardless of what the exact bits are allocated for a margin the following code will work:

class MyMargin(QWidget):
    ...
    def someMethod(self, block):
        self.setBlockValue(block, 3)
        if self.getBlockValue(block) != 3:
            raise Exception("Cannot happen")