This is a layout manager I wrote to help me break up the display of a Pimoroni Inky-pHAT into seperate drawable areas.
You might find other uses for it - let me know if it's handy!
rpi-inky-layout at the Python Package Index
The outline process is:
- Use the
Layoutclass to create a top-level Layout object. - Next, add new layers to a
Layout- it automatically resizes the otherLayouts at the same level. - Take each added sublayer
Layout, and use itssizeto define a new PILImageto draw on. - Draw on the image, Set the
Imageon the appropriateLayout. - Invoke the top-level
Layout'sdraw()method to merge them all together, drawing borders as necessary.
And you end up with a nicely-spaced regions.
Create a new Layout:
layout = Layout( size, packingMode, border)
where:
sizeis a 2-part tuple of the form(width, height).packingModeis the packing direction: currently eitherh(horizontal) orv(vertical).borderis either a) the width of border (colour defaults to2) or b) a 2-tuple containing(width, colour).
Next, add multiple sub-layouts to layout
sublayout1 = layout.addLayer()
sublayout2 = layout.addLayer()
Then, for leach sublayout, use sublayout.size as the size of the image to draw on.
im1 = Image.new(mode, sublayout1.size, bgColour)
...
Draw on the image; Set it back on the sublayout:
sublayout1.setImage(im1)
...
And finally, draw the top level layout and write to file:
layout.draw()
layout.write(filename)
You can then do what you want with the file, e.g., load it onto an Inky display using setImage
Here's a detailed example.
Assuming you already have pip3 installed:
python3 -m pip install rpi-inky-layout
And of course, later upgrade with:
python3 -m pip install --upgrade rpi-inky-layout
Ready to use!
Import the core classes from rpi_inky_layout package:
from rpi_inky_layout import Layout, Rotation
You will also need some sort of image manipulation library, such as
pillow
(and rpi-inky-layout uses the pillow library internally anyway):
from PIL import Image, ImageDraw
Optionally, if you're using it with Pimoroni's Inky display library (its original purpose), then you will probably want to import that, too:
from inky.auto import auto
Create the top-level Layout:
topLayout = Layout((400, 100), packingMode='h', border=(1, 2))
Or, if you're using your the inky library:
board = auto()
topLayout = Layout(board.resolution, 'h', (0, 0))
Add as many new layers as you want:
sublayout1 = topLayout.addLayer()
sublayout2 = topLayout.addLayer()
sublayout3 = topLayout.sddLayer()
sublayout31 = sublayout3.addLayer()
sublayout32 = sublayout3.addLayer()
Use the sub-layouts to create images:
mode = "P"
bgColour = 0
image31 = Image.new(mode, sublayout31.size, bgColour)
draw = ImageDraw.Draw(image31)
draw.text(tuple(s/2 for s in sublayout31.size), "Hello",1)
sublayout31.setImage(image31)
image32 = Image.new(mode, sublayout32.size, bgColour)
draw = ImageDraw.Draw(image32)
draw.text(tuple(s/2 for s in sublayout32.size), "World!",1)
sublayout32.setImage(image32)
topLayout.draw()
topLayout.write("hello-world.png")
If you're using the Inky, you can load the image up:
inky_image = Image.open("hello-world.png")
board.set_image(inky_image)
And you're done!
Alternate packing mode is an implicit mechanism.
You can specify a different packingMode in the addLayer method:
layout.addLayer(packingMode='v')
By default Layouts added using addLayer inherit their parent's packing mode.
Figure 1.1: Alternate Packing Mode example.
Three Layout layers are illustrated, each with different packing modes.
The top Layout uses packingMode='h', the left Layout also uses
packingMode='h', and the right Layout uses packingMode='v'.
If you want to render the Layout in a rotated orientation, you can set the Rotation parameter. It takes the values:
- UP - normal, no rotation; (Default behaviour)
- LEFT - rotation by -90 or 270 degrees
- RIGHT - rotation by +90 degrees
- DOWN - rotated 180 degrees (up side down)
For all the following rotation examples, packingMode='v'.
Figure 2.1 Rotation.UP (the default)
Figure 2.2: Rotation.LEFT
Figure 2.3: Rotation.DOWN
Figure 2.4: Rotation.RIGHT
When adding a layer, you can specify packing bias:
layout = new Layout()
sublayout1 = layout.addLayer(packingBias=3)
sublayout2 = layout.addLayer() # default packingBias=1
In this example, sublayout1 will take up 3/4s of the space (3/(1+3)),
while sublayout2 will be left with the remaining 1/4.
Figure 3.1: Two layers, the first uses the default packingBias,
the second uses packingBias=3.
Subclassing the Layout class allows you to create pre-decorated layouts, which
dynamically re-draw themselves.
Ensure that Layout.__init__() is called from your
subclass's constructor method. Implement the default draw behaviour
by overriding the Layout.drawOverride(self) method, too. Remember that this
method is called after resizing, so you should be able to resize the
information that you display at runtime.
layout = new Layout()
child = new DynamicLayout() # your subclass, overrides `Layout.draw()`
layout.addLayout(child) # returns child, resized. will be auto-redrawn.





