Layout Guide

Pygame GUI elements are positioned in three different axes - x (horizontal), y (vertical) and a layer.

Horizontal & Vertical positioning

Just as in regular pygame, the x and y axis used by pygame GUI run from 0 in the top left corner down to the pixel size of whatever surface/window you are positioning your elements on.

The standard way of positioning elements is through using a ‘relative rectangle’; this rectangle’s position is always relative to the container it is inside of. If you do not supply a container when creating your element, they will be assigned the default ‘root container’ which is created when you make the GUI’s UI Manager and is the same size as the supplied window_resolution parameter.

If you do supply a container when creating an element, by default it will normally be positioned relative to the top left corner of the container. For example, if we were to position a ‘hello’ UIButton element inside of a UIWindow container, and set it’s relative_rect parameter like so:

1
2
3
4
5
6
 button_layout_rect = pygame.Rect(30, 20, 100, 20)

 UIButton(relative_rect=button_layout_rect,
          text='Hello',
          manager=manager,
          container=ui_window)

You would get a result something like this:

_images/layout_default_anchors.png

The button would maintain it’s relative x and y position to the top left corner of the window it’s contained inside of, no matter where the window is moved to.

Layout Anchors

What if you don’t want to position your element relative to the top left hand corner of a container? That’s where layout anchors come in, by changing the anchors for an element you change what the relative layout rectangle is relative _to_.

The most straight forward use is to switch both layout axes to track different sides of the container. So instead of being relative to the top left we anchor to, say the bottom right. That would look something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 button_layout_rect = pygame.Rect(0, 0, 100, 20)
 button_layout_rect.bottomright = (-30, -20)

 UIButton(relative_rect=button_layout_rect,
          text='Hello', manager=manager,
          container=ui_window,
          anchors={'left': 'right',
                   'right': 'right',
                   'top': 'bottom',
                   'bottom': 'bottom'})

Note that both the left and right sides of the button are anchored to the right of our container, and both the top and bottom are anchored to its bottom. This will keep the button the same size whatever size the container is and will produce a layout looking a bit like this:

_images/layout_bottom_right_anchors.png

Sometimes though you want a layout to change size with it’s container so we make maximum use of the available space. In those cases we can simply set the appropriate axis anchors of our button to their counterparts on the window. So to stretch in the x axis (horizontal) set ‘left’ to ‘left’ & ‘right’ to ‘right’. To stretch in the y axis (vertical) set ‘top’ to ‘top’ & ‘bottom’ to ‘bottom’. For example, here is a hello button with a stretch (both x & y axes) anchor setup:

1
2
3
4
5
6
7
8
9
 button_layout_rect = pygame.Rect(30, 20, 100, 20)

 UIButton(relative_rect=button_layout_rect,
          text='Hello', manager=manager,
          container=ui_window,
          anchors={'left': 'left',
                   'right': 'right',
                   'top': 'top',
                   'bottom': 'bottom'})

Here’s what it might look like placed in a small UIWindow:

_images/layout_before_stretch_anchors.png

And here’s what happens to it when we resize the UIWindow to be a bit larger:

_images/layout_after_stretch_anchors.png

You’ll note the gaps between the edges of the window have been maintained.

UI Layers

UI Layers start at 0, which represents the lowest level, and progress upwards as they are needed. Things in higher layers will be drawn on top of things in lower layers if they overlap.

Most of the time using Pygame GUI you don not have to interact too much with the layer system. UIs don’t tend to be designed with their interactive bits overlapping that often, and when they do they tend to be in windows. The main exception is for groups of elements, used for things like, HUDs which may overlap UI elements that appear ‘in’ game worlds; such as monster health bars. For these occasions there is the UIPanel element which works as a container, much like a UI Window, except you specify what layer of the UI it will draw on (and thus what it will appear on top of).

So how do you know where to position your UI Panels? Well for that purpose and for any other time you might need to interrogate the layer system there is a layer debug mode that you can activate by calling a function on the UI manager. This should let you figure out how many layers are being used for your ‘in game’ UI stuff and thus where to position your Panel. Here’s how to turn it on:

1
ui_manager.set_visual_debug_mode(True)

It gives you information as a snapshot of the current state of the UI, so I recommend temporarily binding it to a keypress - then you can toggle it on and off at different times in your game. It will not keep track of any changes in the UI after being turned on.