Skip to content

Intro to Grids

When layout out widgets in a panel, you can do so with the add method as we've seen in previous articles, and it will work just fine. however, when you create UIs you normally have to add several widgets in some kind of ordered fashion. Actually, if you take a look, many UIs can be broken down into grids for layout and positioning. Take a look at this example screen from Stardew Valley character creation screen, which is a relatively complex UI (screenshot taken from Interface in Game). We can imagine the layout as a set of nested rectangular grids. One possibility for this is the one depicted below (click the headers to change between the original image and the imagined grid overlays from that image:

Stardew Valley

Stardew Valley

In the example above, there would be a panel depicting the main character creation UI, then a 2x2 grid (depicted in red lines). Within the red grid, in cell 1,0 (second row, first column) there would be a nested grid (depicted in white), of size 6x1, where the player attribute widgets would be added; similar nested grids would be added to cell 0,1 of the red grid (a 3x1 grid for player name, farm name and favorite thing) and to position 1,1 (a 5x1 grid for animal preference, player color and the OK button). Note that the rows in this last grid are not all the same size - the last one is clearly bigger.

Furthermore, we can see that the farm selection panel to the right of the main panel would have a 6x1 grid to display the farm icons (depicted in green). Finally, the tooltip shown over one of the farms would also be a panel, with a 2x1 grid (depicted in yellow).

The grid component of gooey lets you do exactly this: add a grid to a panel, and then you can add a grid inside another grid. You can configure the grid column/row proportions, the margin and spacing of the grid. After you do this, you can add widgets to a specific cell of the grid (this is, a specific row and column the grid) instead of directly adding it to a position within the panel.

Proportionality

Grids in gooey are proportional by default. This means they take up the entire space of the panel (you can specify margins and spacing to lay out content) and are responsive - if the panel changes size, so will the grid.

Constructor

The constructor for grids is UIGrid and its signature is:

UIGrid(_id, _rows, _columns)

Here:

  • id is the string ID.
  • rows and columns are the rows and columns needed for the rectangular grid.

Adding a widget to a cell

When working with grids, one adds the grid to the panel/parent as usual (i.e. using the add method - for example, _panel.add(_grid)). However, once we have a grid, we want to add child widgets like buttons, text, sprites, etc. to a grid cell. We can do that by using the addToGrid method of the grid (not the panel):

_grid.addToCell(<widget_ref>, <row>, <col>);

where the row and col are the indices (starting at 0).

Setting up the grid margins and spacing

Grids in gooey take up the complete space of the panel (or parent widget). However, you normally want to have some margins towards the borders, and you could also want some spacing between each row/column. gooey includes methods to do this:

  • You can use setMargins to set up all the margins (the space between the border of the panel/parent and the grid), or individually for top, bottom, left or right (e.g. setMarginTop) and specify the margin in pixels.
  • You can use setSpacings to set up all the spacings simultaneously, or use setSpacingHorizontal and setSpacingVertical individually, to set up spacing between columns and rows (respectively).

Setting up the row/column proportions

Additionally, you can change the proportion of the rows or columns. By default, the rows and columns are all of equal size, and are calculated in percentage terms (to respond accordingly when a panel is resized). To change this, you can use the setRowProportions and setColumnProportions. These methods require an array of proportions (in percentage terms). This array must be of the same size than the number of rows/columns, and its proportions need to add up to 1.

Showing a debug overlay

A grid in gooey can be thought of as an invisible container of widgets1. However, to debug the margins, spacing or proportions, you can use setShowGridOverlay to temporarily draw the grid. After everything is correctly set up, you can simply remove that call (or set to false).

Example

Let's create a main menu, but using a Grid to set up the widgets. For this example I'm using etahoshi's Fantasy Minimal GUI pack. Let's think of a menu with Play, Tutorial, Settings and Quit buttons, and finally two sprites at the bottom, one on each side.

Let's begin by creating the panel, creating the grid (5 rows x 1 column) and adding it to the panel. Let's also activate the grid overlay, to visually understand how the grid is being rendered and make sure it's how we want it:

1
2
3
4
5
var _panel = new UIPanel("TestPanel", 0, 0, 300, 450, spr_Panel, UI_RELATIVE_TO.MIDDLE_CENTER);
_panel.setTitleFormat("[fnt_Title]").setTitle("Main Menu").setTitleOffset({x:0, y:20});
var _grid = new UIGrid("ParentGrid", 5, 1);
_panel.add(_grid);
_grid.setShowGridOverlay(true);

Up to now, we have our grid set up, and it looks like this:

Grid, first stage

This has several problems: first, there is no margin, so if we plan to expand the buttons to cover the complete cells, they will be too big and they will also overlap the menu title. Also, there's no spacing, which always looks great on UI - properly spaced UI elements allow for much better readability and usability. Let's fix the margins to have some space from the borders of the panel, setting up a bigger top margin, so the grid does not overlap with the title, and let's set up some spacing between rows.

Let's also make the last row bigger, since we want to show the sprites. Let's use the proportion (say, 40% for that row, and the rest for the other 4 rows):

6
7
8
_grid.setMargins(20).setMarginTop(50);
_grid.setSpacingVertical(15);
_grid.setRowProportions([0.15,0.15,0.15,0.15,0.4]); 
Grid, 2-4 stages

Much better! Let's add our buttons. We will set each button to inherit its width and height from the parent (in this case, the cell from the grid):

var _button = new UIButton("Play_Button", 0, 0, 0, 0, "Play", spr_Button, UI_RELATIVE_TO.MIDDLE_CENTER);
_button.setInheritWidth(true).setInheritHeight(true);
_grid.addToCell(_button, 0, 0);
var _button = new UIButton("Tutorial_Button", 0, 0, 0, 0, "Tutorial", spr_Button, UI_RELATIVE_TO.MIDDLE_CENTER);
_button.setInheritWidth(true).setInheritHeight(true);
_grid.addToCell(_button, 1, 0);
var _button = new UIButton("Settings_Button", 0, 0, 0, 0, "Settings", spr_Button, UI_RELATIVE_TO.MIDDLE_CENTER);
_button.setInheritWidth(true).setInheritHeight(true);
_grid.addToCell(_button, 2, 0);
var _button = new UIButton("Quit_Button", 0, 0, 0, 0, "Quit", spr_Button, UI_RELATIVE_TO.MIDDLE_CENTER);
_button.setInheritWidth(true).setInheritHeight(true);
_grid.addToCell(_button, 3, 0);
Grid, 5-6 stages

Finally, let's add a child grid, to layout our two sprites. We now want a 1x2 grid (one row, two columns), as a child of the "parent" grid:

var _child_grid = new UIGrid("ChildGrid", 1, 2);
_grid.addToCell(_child_grid, 4, 0);
_child_grid.setShowGridOverlay(true);

The bottom part of our menu is now looking like so:

Grid, 7 stages

Great, now we can add our sprites to the cells of our child grid. Let's add them each aligned to the outer lower corner of each one and offset a little towards the center:

var _sprite = new UISprite("BuffSprite", 10, -10, spr_Icons,64,64,,UI_RELATIVE_TO.BOTTOM_LEFT);
_child_grid.addToCell(_sprite, 0, 0);
_sprite = new UISprite("HeartSprite", -10, -10, spr_Heart,64,64,,UI_RELATIVE_TO.BOTTOM_RIGHT);
_child_grid.addToCell(_sprite, 0, 1);

We're done! After turning setShowGridOverlay off for both grids, the result can be seen in the following interactive example. The example shows the end result, but you can use Left and Right keys to toggle between the different stages of code we've seen, up until the final result, where we see our nice main menu fully rendered!

Not working?

If interaction is not working, click on the black bar just above the game canvas, to activate the iframe element - otherwise keys are processed by the site itself.


  1. Actually, a grid in gooey is a collection of UIGroup widgets (one per cell) that do not have a sprite set - so they are effectively invisible.