  Introduction
  The overlay commands
  Alpha blending
  Using clips
  Affine transformations
  Cell view
  The oplus package

Introduction

The overlay is a rectangular region of pixels that can be displayed above the current layer. Lua scripts have total control of what the overlay looks like and how the user interacts with it. The Scripts/Lua folder supplied with Golly has a number of scripts that illustrate how the overlay can be used:

- 3D.lua lets people explore three-dimensional cellular automata.
- breakout.lua shows how to use the overlay functions to create a working game.
- browse-patterns.lua browses through patterns in a folder manually or automatically.
- hexgrid.lua creates a true hexagonal grid for rules that use a hexagonal neighborhood.
- overlay-demo.lua demonstrates how to use most of the overlay functions.
- pop-plot.lua displays a plot of population versus time that can be saved as a PNG file.

To study how these scripts work, control-click or right-click on one of the above links to open the script in your preferred text editor, then run the script by clicking on the same link.

The overlay commands

The overlay is manipulated using two script commands called overlay and ovtable.

The first, overlay, takes a single string parameter that contains an overlay command followed by zero or more arguments separated by spaces. Some overlay commands can also return a single string as their result.

The second, ovtable, takes a single table parameter rather than a string and only supports a subset of the overlay commands. It is typically faster to use ovtable than overlay. The supported ovtable commands that return a result are get, which returns individual values, and rgba, which returns a table. In all other ways ovtable is identical to the overlay command.

Here is an alphabetical list of all the valid overlay commands:

  blend camera celloption cellview copy create cursor delete |  | drawcells ellipse fill flood font get line lines |  | lineoption load optimize paste position replace resize rgba |  | save scale set target text textoption theme transform |  | update updatecells xy

Here is an alphabetical list of the subset of overlay commands supported by ovtable:

  fill get |  | line lines |  | paste rgba |  | set

All of the drawing commands use the current render target. This is initially the overlay but can be changed to a clip with the target command.

The examples given below assume a script has started with these lines:

  local g = golly()
  local ov = g.overlay
  local ovt = g.ovtable

blend i
  Set alpha blending off (i = 0), full (i = 1) or fast (i = 2) and return the previous blend state as a string ("0", "1" or "2"). The fast mode should only be used when the target pixels are opaque. The commands affected by alpha blending are: ellipse, fill, flood, line, lines, load, paste, scale and set. Note that setting alpha blending to full or fast also forces ellipses and lines to be antialiased.
  Example: local oldblend = ov("blend 1")

camera setting value(s)
  Change a camera setting for the current cell view. The valid camera settings and their allowed values are:

  angle d |  | – set camera angle to d degrees where d is from 0.0 to 360.0
  xy x y |  | – set camera pan position to x,y
  zoom z |  | – set camera zoom to z where z is from 0.0625 (-16x) to 32.0

  Example: ov("camera angle 90")
  Example: ov("camera xy -32 100")
  Example: ov("camera zoom 3.5")

  The cellview command initializes the camera angle to 0 degrees, the x,y position to the centre of the view, and the zoom value to 1.

celloption option value
  Set a display option for the current cell view. The valid options and their allowed values are:

  depth d |  | – set layer depth to d where d is from 0.0 to 1.0
  grid i |  | – set grid lines display on (i = 1) or off (i = 0)
  gridmajor g |  | – set grid lines major interval to g where g is an integer from 0 to 16
  hex i |  | – set hex display on (i = 1) or off (i = 0)
  layers n |  | – set number of layers to n where n is an integer from 1 to 10
  stars i |  | – set stars display on (i = 1) or off (i = 0)

  Example: ov("celloption depth 0.2")
  Example: ov("celloption layers 6")
  Example: ov("celloption hex 1")
  Example: ov("celloption grid 1")
  Example: ov("celloption gridmajor 8")
  Example: ov("celloption stars 1")

  The cellview command initializes the depth to 0.05, the number of layers to 1, hex display to 0, grid to 0, gridmajor to 10 and stars to 0.

cellview x y wd ht
  Create a cell view enclosed by the given rectangle that can be drawn on the overlay. The width and height must be from 16 to 4096 and a multiple of 16.
  Example: ov("cellview -1024 -1024 2048 2048")

copy x y wd ht clipname
  Copy the pixels in the given rectangle from the current render target into the named clip for later use in a command like paste or scale. If the given width or height is less than 1 then it is treated as an inset from the render target's current width or height (this makes it easy to copy the entire render target with a command like "copy 0 0 0 0 all"). Any parts of the rectangle outside the render target are filled with transparent pixels. The clip name can contain any characters except a space.
  Example: ov("copy 0 0 100 200 tempbox")

create wd ht (clipname)
  Create the overlay or if a clip name is specified create a new clip with the given width and height. All pixels are initially transparent (their RGBA values are set to 0,0,0,0). When creating the overlay the following are also set:

  The initial RGBA values used by later drawing commands are set to 255,255,255,255 (opaque white). The overlay's initial position is set to topleft, the cursor is set to the standard arrow, the transform values are set to 1,0,0,1 (identity) and alpha blending is off. The initial font for drawing text is the default system font at a size of 10pt (see the font command). The text options are set to left alignment (for multi-line text) and a transparent background. The initial line width (used by the ellipse, line and lines commands) is set to 1. The render target is set to be the overlay.
  Example: ov("create 400 300")
  Example: ov("create 400 300 myclip")

  Note that the when creating the overlay this command automatically ticks the Show Overlay option to ensure the overlay will be displayed when the viewport is updated (by calling g.update() or the update command).

cursor name
  Specify which cursor to use when the mouse moves over a non-transparent pixel within the overlay. The valid cursor names are:

  arrow |  | – standard arrow
  cross |  | – crosshairs
  current |  | – Golly's current cursor (no change)
  hand |  | – hand
  hidden |  | – invisible cursor
  pencil |  | – pencil
  pick |  | – color picker
  wait |  | – a lengthy task is in progress
  zoomin |  | – magnifying glass with "+"
  zoomout |  | – magnifying glass with "-"

  The previous cursor name is returned.
  Example: local oldcursor = ov("cursor pencil")

delete (clipname)
  Delete the overlay or if a clip name is specified delete the named clip. When deleting the overlay this is equivalent to selecting Delete Overlay from the Layer menu. Note that it is an error to delete a clip that is the current render target.
  Example: ov("delete")
  Example: ov("delete myclip")

drawcells
  Draw the cells from the current cell view onto the render target. The cells will be drawn using the camera settings and colored using the current theme. Further drawing commands can then be used to draw on top of the cell display. Pixels outside of the current cell view are drawn in the current grid border color.
  Example: ov("drawcells")

ellipse x y wd ht
  Draw an ellipse inside the given rectangle using the current rgba values onto the render target. Any parts of the ellipse outside the render target are automatically clipped. A width or height less than 1 is relative to the render target's width or height. If the width equals the height (and both are positive) then the result is a circle. If alpha blending is turned on then the edges of the ellipse are antialiased. The lineoption width command determines the thickness of the ellipse.
  Example: ov("ellipse 10 10 60 40")

fill x y wd ht (...x y wd ht)
  Fill the given rectangles in the render target with the current rgba values. Any parts of the rectangles outside the render target are automatically clipped. If no rectangle is given then the entire render target is filled. A width or height less than 1 is relative to the render target's width or height, so a command like ov("fill 1 1 -2 -2") would fill all of the render target except for a 1 pixel border around the edges.
  Example: ov("fill 10 10 30 50")
  or
  Example: ovt{"fill", 10, 10, 30, 50}

flood x y
  Flood a connected region of pixels in the render target that match the given starting pixel with the current rgba values.
  Example: ov("flood 10 20")

font fontsize fontname
  Set the font used by later text commands. If the font name is not supplied then only the font size will be changed. The valid font names are:

  default |  | – standard system font
  default-bold |  | – bold system font
  default-italic |  | – italic system font
  mono |  | – mono-spaced font
  mono-bold |  | – bold mono-spaced font
  mono-italic |  | – italic mono-spaced font
  roman |  | – roman font
  roman-bold |  | – bold roman font
  roman-italic |  | – italic roman font

  The previous font is returned as a string of the form "fontsize fontname".
  Example: local oldfont = ov("font 15 roman-bold")

get x y
  Return the RGBA values of the given pixel in the render target. All values will be from 0 to 255.
  For the string version the values are returned as a string of the form "red green blue alpha". If the given pixel is outside the render target then "" is returned.
  Example: local RGBA = ov("get 10 20")
  For the table version the values are returned individually. If the given pixel is outside the render target then -1 is returned for each component.
  Example: local R, G, B, A = ovt{"get", 10, 20}

line x1 y1 x2 y2 (...xn yn)
  Draw one or more connected lines of pixels between the supplied coordinates x1 y1 to xn yn on the render target using the current rgba values. Any pixels outside the render target edges are automatically clipped. If alpha blending is turned on then the lines are antialiased. The lineoption width command determines the thickness of the lines.
  Examples:
  -- draw line from (10, 20) to (50, 60)
  ov("line 10 20 50 60")
  or
  ovt{"line", 10, 20, 50, 60}
  -- draw triangle with vertices at (0, 0), (100, 0) and (50, 100)
  ov("line 0 0 100 0 50 100 0 0")
  or
  ovt{"line", 0, 0, 100, 0, 50, 100, 0, 0}

lines x1 y1 x2 y2 (...xn1 yn1 xn2 yn2)
  Draw one or more separate lines of pixels between the supplied pairs of coordinates x1 y1 to x2 y2 on the render target using the current rgba values. Any pixels outside the render target edges are automatically clipped. If alpha blending is turned on then the lines are antialiased. The lineoption width command determines the thickness of the lines.
  Examples:
  -- draw line from (10, 20) to (50, 60)
  ov("lines 10 20 50 60")
  or
  ovt{"lines", 10, 20, 50, 60}
  -- draw line from (0, 0) to (100, 0) and another line from (50, 25) to (150, 25)
  ov("lines 0 0 100 0 50 25 150 25")
  or
  ovt{"lines", 0, 0, 100, 0, 50, 25, 150, 25}

lineoption option value
  Set an option used by the ellipse, line and lines commands. There is currently one valid option:

  width w |  | – set the line width to an integer from 1 to 10000.

  The previous line width is returned as a string. The create command initializes the line width to 1.

  Example: local oldwidth = ov("lineoption width 3")

load x y file
  Load the given BMP/GIF/PNG/TIFF file into the render target at the given location. Any pixels outside the render target edges are automatically clipped. Return the total size of the image (including any clipped portions) as a string of the form "width height". Note that it's sometimes desirable to call this command twice: the 1st call can specify a location completely outside the render target just to get the image's width and height; the 2nd call can then use those values to do things like center the image within the render target.
  Example: local wdht = ov("load 99999 99999 foo.png")

optimize clipname
  Optimizes the named clip for improved paste performance when using alpha blending. Returns the bounding box of non-zero alpha pixels within the clip as a string of the form "x y width height". A clip that is modified after optimization must be optimized again before use to get the performance benefit. Especially effective for text rendering and used automatically by the op.maketext function.
  Example: local x, y, w, h = gp.split(ov("optimize textclip"))

paste x1 y1 (...xn yn) clipname
  Paste the named clip (created by an earlier create, copy or text command) into the render target at the given location(s). Any pixels outside the render target edges are automatically clipped.
  Examples:
  -- paste the tempbox clip at (10, 20)
  ov("paste 10 20 tempbox")
  or
  ovt{"paste", 10, 20, "tempbox"}
  -- paste the tempbox clip at (10, 20), (100, 20) and (100, 50)
  ov("paste 10 20 100 20 100 50 tempbox")
  or
  ovt{"paste", 10, 20, 100, 20, 100, 50, "tempbox"}

  If multiple locations are given then the clip is drawn at the locations in the order specified.

position pos
  Specify where the overlay is to be displayed within the current layer. The valid positions are:

  topleft |  | – top left corner
  topright |  | – top right corner
  bottomright |  | – bottom right corner
  bottomleft |  | – bottom left corner
  middle |  | – middle of layer

  Example: ov("position middle")

replace red green blue alpha
  Replace pixels with color red green blue alpha in the render target with the current rgba values. Returns the number of pixels replaced as a string.
  Example:
  -- replace opaque black pixels with semi-transparent blue pixels in clip named 'myclip'
  local oldtarget = ov("target myclip")
  ov("rgba 0 0 255 128")
  local replaced = ov("replace 0 0 0 255")
  ov("target "..oldtarget)

  There are two special characters that can be used in the color specification for more advanced matches: ! and *. A color component may be specified as the wildcard * which means match any value for that component.
  Example:
  -- replace any opaque pixel with opaque blue
  ov(op.blue)
  local replaced = ov("replace * * * 255")

  If the match specification is prefixed with ! then pixels that don't match the specification are replaced.
  Example:
  -- replace any pixel that isn't white with yellow
  ov(op.yellow)
  local replaced = ov("replace !255 255 255 255")

  Alternatively if the alpha specification is prefixed with ! then pixels that don't have the specified alpha value are replaced.
  Example:
  -- replace any non-opaque pixel with opaque blue
  ov(op.blue)
  local replaced = ov("replace * * * !255")

  Normally when a match is found the clip pixel is replaced with the current rgba values. This can be overridden by postfixing one or more color components with r, g, b, a or #. Each color component in the clip pixel can either be left unchanged (in the case of #) or replaced with the specified color component from the clip pixel.
  Examples:
  -- make transparent pixels opaque (r g b 0 -> r g b 255)
  ov("rgba 0 0 0 255")
  local replaced = ov("replace *# *# *# 0")

  -- swap the red and green components (r g b a -> g r b a)
  local replaced = ov("replace *g *r *# *#")

  -- set the pixels to opaque gray based on the alpha level (r g b a -> a a a 255)
  ov("rgba 0 0 0 255")
  local replaced = ov("replace *a *a *a *")

  If the postfix character is followed by - then the component value is inverted.
  Examples:
  -- invert the r g b components but leave alpha unchanged (r g b a -> 255-r 255-g 255-b a)
  local replaced = ov("replace *#- *#- *#- *#")

  -- make transparent pixels opaque and vice versa (r g b a -> r g b 255-a)
  local replaced = ov("replace *# *# *# *#-")

  Color components can also be adjusted by using -- to decrement, ++ to increment, -value to subtract a constant or +value to add a constant. Component values are clamped to the range 0 to 255.
  Examples:
  -- increase the brightness of all pixels
  local replaced = ov("replace *#+50 *#+50 *#+50 *#")

  -- fade all pixels to black
  while tonumber(ov("replace *#-- *#-- *#-- *#")) > 0 do
  ov("update")
  end

  The postfixes can also be used without a target component. In which case the current rgba values are adjusted.
  Example:
  -- replace green pixels with the current drawing color minus 32 alpha (0 255 0 255 -> 255 0 0 96)
  ov("rgba 255 0 0 128")
  local replaced = ov("replace 0 255 0 255-32")

resize wd ht (clipname)
  Resize the overlay or if a clip name is specified resize the named clip. The previous size is returned as a string of the form "width height". This command is typically used if a window resize is detected and you wish to keep the overlay covering all of the current layer. Note that all pixels in the resized overlay/clip become transparent (their RGBA values are reset to 0,0,0,0).
  Example: local oldsize = ov("resize 1000 800")
  Example: local oldsize = ov("resize 300 240 myclip")

rgba red green blue alpha
  Set the current RGBA values used by later drawing commands and return the old values. All values are from 0 to 255. The commands that use the current RGBA values are: ellipse, fill, flood, line, lines, replace, set and text.
  For the string version the values are returned as a string of the form "red green blue alpha".
  Example: local oldrgba = ov("rgba 255 0 0 255")
  For the table version the values are returned as a table of the form {"rgba", red, green, blue, alpha}.
  Example: local oldrgba = ovt{"rgba", 255, 0, 0, 255}

save x y wd ht file
  Save the pixels in the given rectangle of the render target in the given PNG file. An error will occur if any part of the rectangle is outside the render target. If the given width or height is less than 1 then it is treated as an inset from the render target's current width or height (this makes it easy to save the entire render target with a command like "save 0 0 0 0 overlay.png").
  Example: ov("save 0 0 100 80 "..g.getdir("temp").."foo.png")

scale quality x y wd ht clipname
  Paste the named clip into the current render target, scaling it so it fits into the specified rectangle. Any pixels outside the render target edges are automatically clipped. The given quality must be one of these strings:

  best |  | – use a high quality, but slow, scaling algorithm
  fast |  | – use a fast, but lower quality, scaling algorithm

  Example: ov("scale best 10 10 100 200 image")

set x1 y1 (...xn yn)
  Set the specified pixels in the render target to the current rgba values. Pixels outside the render target are silently ignored.
  Examples:
  -- set pixel at (10, 20)
  ov("set 10 20")
  or
  ovt{"set", 10, 20}
  -- set pixels at (10, 20), (15, 25) and (16, 25)
  ov("set 10 20 15 25 16 25")
  or
  ovt{"set", 10, 20, 15, 25, 16, 25}

target (clipname)
  Set the render target to the named clip or to the overlay if no clip is specified. All subsequent drawing commands will use the new render target. Returns the previous target as a string (an empty string if it was the overlay). It is an error to attempt to delete a clip while it is the render target. The commands that use the render target are: copy (as the source), drawcells, ellipse, fill, flood, get (as the source), line, lines, load, paste, replace, save (as the source), scale and set.
  Example: local oldtarget = ov("target myclip")

text clipname one or more lines of text ...
  Create a named clip containing the given text in the current font (as set by the most recent font command). Return the dimensions of the clip as a string of the form "width height descent". The descent is the number of pixels under the baseline (useful if you want to place text with different sized fonts on the same line).

  The text's color depends on the most recent rgba command. The text background color can be set with the textoption background command. By default the text has a transparent background, so you'll probably need to set blend to 1 before drawing the text with paste. If you specify an opaque background then there's no need to turn on alpha blending when doing the paste, so drawing such text will be significantly faster. You can also specify the alignment of multi-line text with the textoption align command.

  Example: local dimens = ov("text tempclip First line.\nSecond line.")

textoption option value
  Set a display option for the text command. The valid options and their allowed values are:

  align alignment |  | – set the alignment of multi-line text to left, right or center
  background r g b a |  | – set the text background to the given RGBA values (all from 0 to 255)

  The create command initializes the text options to left alignment and a transparent background. Both options return their previous setting as a string: the returned alignment value will be "left", "right" or "center"; the returned background will be a string of the form "red green blue alpha".

  Example: local oldalign = ov("textoption align right")
  Example: local oldbackground = ov("textoption background 255 0 0 255")

theme r1 g1 b1 r2 g2 b2 r3 g3 b3 r4 g4 b4 r5 g5 b5 (alivea, deada, unoccupieda, bordera)
  Define the color theme for drawing the current cell view. Themes allow better visualization of patterns because they highlight history and longevity of cells. The arguments define 5 colors:

  r1 g1 b1 |  | born | cell just born
  r2 g2 b2 |  | alive | cell alive for at least 63 generations
  r3 g3 b3 |  | died | cell just died
  r4 g4 b4 |  | dead | cell dead for at least 63 generations
  r5 g5 b5 |  | unoccupied | cell never occupied

  Example: ov("theme 0 255 255 255 255 255 0 0 255 0 0 47 0 0 0")
  New cells are drawn in the born color (cyan 0 255 255).
  If they stay alive they fade from the born color to the alive color (white 255 255 255) over the next 63 generations. If the cell stays alive after that it remains in the alive color. This provides a visual representation of cell longevity.
  Cells are drawn in the died color (blue 0 0 255) when then they die.
  If they stay dead they fade from the died color to the dead color (dark blue 0 0 47) over the next 63 generations. If the cell stays dead after that it remains in the dead color. This provides a visual representation of cell history.
  Cells that have never been occupied are drawn in the unoccupied color (black 0 0 0).

  Optionally you can specify the alpha values for the different cell types:

  alivea | born to alive
  deada | died to dead
  unoccupieda | unoccupied
  bordera | border

  The border color RGB components are read from the View Preference grid border color. If you don't want a border drawn around the cell view then set bordera to 0 (transparent).

  If you omit alpha values then they all default to 255 (opaque).

  If no theme is specified then Golly's default colors for the pattern are used. If you want to switch off the theme then use the command ov("theme -1").

  There is a set of predefined themes in the oplus package using which the example above would become: ov(op.theme1) or ov(op.themes[1]).

transform axx axy ayx ayy
  Set the affine transformation values used by later paste commands and return the old values as a string of the form "axx axy ayx ayy".
  Example: local oldt = ov("transform 0 -1 1 0")

update
  Tell Golly to update the overlay without drawing the underlying layer. This will be faster than calling g.update() but should only be used in cases where the overlay covers the entire layer and all pixels in the overlay are opaque.
  Example: ov("update")

updatecells
  Update the current cell view using the cells in the current universe. This command should typically be used every time the universe changes.
  Example: ov("updatecells")

xy
  Return the current mouse position within the overlay as a string of the form "x y", or "" if the mouse is outside the overlay. The x and y values are pixel coordinates. The top left pixel in the overlay is "0 0"; x values increase to the right and y values increase downwards.
  Example: local mousepos = ov("xy")

Alpha blending

Alpha blending is a way of drawing translucent pixels on top of existing pixels to get nicer looking results. When an overlay is created, alpha blending is initially turned off. To turn it on a script needs to call "blend 1", for blending with any target, or "blend 2", for faster blending when you know the target pixels are opaque. Consider this simple script which draws a translucent blue square on top of a translucent red square (both on top of an opaque white background):

  local g = golly() local ov = g.overlay ov("create 100 80") ov("fill") ov("blend 1") ov("rgba 255 0 0 128") ov("fill 10 10 50 50") ov("rgba 0 0 255 128") ov("fill 30 20 50 50") |  |
  blend 1
  blend 0

The left image shows the resulting overlay. The right image shows the overlay produced by the same script but with the "blend 1" line removed (the grid lines are from the layer underneath the overlay).

Note that drawing with alpha blending on is significantly slower than drawing with it off, so it's a good idea to only turn it on when necessary. The overlay commands that can do alpha blending are: ellipse, fill, flood, line, lines, load, paste, scale, set.

Using clips

Overlay scripts can use multiple "clipboards" called clips. A clip is simply a chunk of memory containing a rectangular area of pixels. Each clip has a unique name consisting of any characters except a space. Clips can be created using three commands: create, copy and text. Clips can be the render target for any of the drawing commands.

The following script illustrates the use of clips. It creates a tiled background pattern on which some translucent text is drawn. The image on the right shows the resulting overlay.

  local g = golly() local ov = g.overlay ov("create 199 177") ov("rgba 255 255 0 255") ov("fill") -- create the tile ov("rgba 0 0 0 255") ov("line 10 0 0 20") ov("line 10 0 20 20") ov("line 0 20 20 20") ov("rgba 200 200 255 255") ov("flood 10 10") ov("copy 0 0 21 21 mytile") -- tile the overlay for y = 0, 177, 21 do for x = 0, 199, 21 do ov("paste "..x.." "..y.." mytile") end end -- create some translucent red text ov("rgba 255 0 0 180") ov("font 60 roman-bold") ov("text mytext Golly") ov("blend 1") ov("paste 10 10 mytext") |  |

Affine transformations

The transform command allows a limited set of affine transformations, namely rotation by multiples of 90 degrees and reflection about the x, y or diagonal axes. The following script shows how text can be rotated or reflected. Instead of using explicit transform commands it uses mnemonic synonyms defined in the oplus package. The image on the right shows the resulting overlay.

  local g = golly() local ov = g.overlay local op = require "oplus" ov("create 200 380") ov("fill") ov("blend 1") ov("font 12 default-bold") -- do rotations ov("rgba 0 0 255 255") ov("text temp ROTATE") ov("set 100 100") ov("paste 100 100 temp") ov(op.rcw) ov("paste 100 100 temp") ov(op.racw) ov("paste 100 100 temp") ov(op.r180) ov("paste 100 100 temp") -- do reflections ov("rgba 255 0 0 255") ov(op.identity) ov("text temp - REFLECT") ov("set 100 270") ov("paste 100 270 temp") ov(op.flip_x) ov("paste 100 270 temp") ov(op.flip_y) ov("paste 100 270 temp") ov(op.swap_xy) ov("paste 100 270 temp") ov(op.swap_xy_flip) ov("paste 100 270 temp") |  |

Cell view

A cell view is a flexible way of displaying cells from the universe onto the overlay. A number of steps are required:

1. Use the cellview command to specify the rectangle of cells from the universe that you want to display.
2. Either use the current pattern colors or pick a theme with the theme command.
3. Use the camera and celloption commands to determine how you want to project the cells onto the overlay.
4. Whenever cells change in the universe you should use the updatecells command to refresh the cell view.
5. To draw the cells onto the overlay use the drawcells command. If the cells don't change and you want to change the camera or theme then just use drawcells after the appropriate camera and theme commands.

Here is a simple example:

  -- create an overlay the size of the current layer local g = golly() local ov = g.overlay local viewwd, viewht = g.getview(g.getlayer()) ov("create "..viewwd.." "..viewht) -- open example pattern g.open(g.getdir("app").."Patterns/Life/Methuselahs/rabbits.lif") -- create a cell view using a theme ov("cellview -256 -256 512 512") ov("theme 0 255 255 255 255 255 0 0 255 0 0 47 0 0 0") -- set camera 14.5x zoom and 30 degree rotation ov("camera zoom 14.5") ov("camera angle 30") ov("drawcells") ov("update") -- run for 1000 generations for i = 1, 1000 do g.run(1) ov("updatecells") ov("drawcells") ov("update") end -- delete the overlay ov("delete")

To see the above script in action, select and copy the lines to the clipboard, then select Run Clipboard from the File menu.

The oplus package

The oplus package provides a high-level interface to the overlay commands which implement graphics, text, user interface and utility functions. The package consists of a set of .lua files stored in the Scripts/Lua/oplus directory. The following functions are available after a script calls local op = require "oplus" (see init.lua for the implementation details).

Graphics commands

op.draw_line(x1, y1, x2, y2)
  Draw a line from x1,y1 to x2,y2.
  Example: op.draw_line(0, 0, 10, 10)

op.fill_ellipse(x, y, w, h, borderwd, fillrgba)
  Draw an ellipse (or circle) inside the given rectangle. If borderwd is greater than zero then an antialiased ellipse of the given thickness is drawn using the current color. If fillrgba is not an empty string then the ellipse is filled with the given color.
  Example: op.fill_ellipse(200, 450, 140, 99, 2, "rgba 255 255 0 200")

op.fill_rect(x, y, wd, ht)
  Draw a filled rectangle with its top left corner at x,y and of the given width and height.
  Example: op.fill_rect(0, 0, 40, 30)

op.round_rect(x, y, w, h, radius, borderwd, fillrgba)
  Draw a rounded rectangle where the given radius determines the curvature of each corner. If borderwd is greater than zero then an antialiased border of the given thickness is drawn using the current color. If fillrgba is not an empty string then the rectangle is filled with the given color.
  Example: op.round_rect(200, 300, 60, 30, 15, 0, "rgba 255 0 0 128")

Text commands

op.minbox(clipname, wd, ht)
  Find the minimal bounding box of non-transparent pixels in the given clip. This can be used to determine the real dimensions of some text. If all pixels in the clip are transparent then the returned values are all zero.
  Example: local minx, miny, minwd, minht = op.minbox("textclip", 80, 10)

op.maketext(text, clipname, color, shadowx, shadowy, shadowcolor)
  A simpler and more powerful way of creating text that can then be drawn with pastetext. Only the first argument, text, is required.
  Example:
  -- draw the string "Hello World" at 0, 0 on the current render target
  op.maketext("Hello World")
  op.pastetext(0, 0)

  Usually the text clip is created using the current rgba values. This can be overridden by specifying the color argument. The text may also be given a shadow at a specific x, y pixel offset defined with the shadowx and shadowy arguments. The shadow will be drawn in opaque black unless a different color is specified with the shadowcol argument.
  Example:
  -- create a clip named "hello" with the text "Hello World" in blue with a yellow shadow offset by -1, -2 pixels.
  local w, h = op.maketext("Hello World", "hello", op.blue, -1, -2, op.yellow)

  The function returns the width and height of the created clip (including any shadow).

op.pastetext(x, y, transform, clipname)
  Paste text onto the current render target. Only the first two arguments x, y are required. Returns the clip name.
  Example:
  -- paste a text clip at 0, 0 on the current render target
  local textclip = op.pastetext(0, 0)

  The transform argument can be used to specify an affine transformation. The clipname may be used to specify a non-default clipname.
  Example:
  -- paste the clip named "hello" at 0, 0 and rotated clockwise on the current render target
  op.pastetext(0, 0, op.rcw, "hello")

User interface commands

op.button(label, onclick)
  Create and return a table representing a button. The button width depends on the given label text. If the op.process function detects a click in this button then the given onclick function will be called.
  Example: cancel_button = op.button("Cancel", g.exit)

  The button will only appear after its show function is called.
  Example: cancel_button.show(10, 10)

op.checkbox(label, labelrgba, onclick)
  Create and return a table representing a check box. The label text will be drawn using the given color to the right of a tickable button. If the op.process function detects a click in this check box (including the label) then the given onclick function will be called.
  Example: line_box = op.checkbox("Show lines", op.black, toggle_lines)

  The check box will only appear after its show function is called.
  Example: line_box.show(10, 40, true)

op.radiobutton(label, labelrgba, onclick)
  Create and return a table representing a radio button. The label text will be drawn using the given color to the right of a radio button. If the op.process function detects a click in this radio button (including the label) then the given onclick function will be called.
  Example:
  draw_option = op.radiobutton("Draw", op.black, set_draw_mode)
  select_option = op.radiobutton("Select", op.black, set_select_mode)
  move_option = op.radiobutton("Move", op.black, set_move_mode)

  The radio button will only appear after its show function is called.
  Example:
  draw_option.show(10, 40, mode == "draw")
  select_option.show(10, 40, mode == "select")
  move_option.show(10, 40, mode == "move")

op.slider(label, labelrgba, barwidth, minval, maxval, onclick)
  Create and return a table representing a slider. The label text will be drawn using the given color to the left of the slider's horizontal bar. The bar width must be greater than 0. The minimum and maximum values of the slider can be any integer values, as long as minval is less than maxval. If the op.process function detects a click in this slider, and the slider value has changed, then the given onclick function will be called.
  Example: red_slider = op.slider("Red:", op.black, 64, 0, 255, new_red)

  The slider will only appear after its show function is called.
  Example: red_slider.show(10, 70, 255)

op.menubar()
  Create and return a table representing a menu bar. You can then use its addmenu function to add menus to the menu bar, then the additem function to append items to these menus. If the op.process function detects a click in this menu bar then it will track the mouse and call the specified callback function if a menu item is selected.
  Example:
  mbar = op.menubar()
  -- add some menus
  mbar.addmenu("File")
  mbar.addmenu("Edit")
  -- add items to File menu
  mbar.additem(1, "New Pattern", NewPattern)
  mbar.additem(1, "Open Pattern...", OpenPattern)
  mbar.additem(1, "Save Pattern...", SavePattern)
  mbar.additem(1, "---", nil) -- separator
  mbar.additem(1, "Exit", g.exit)
  -- add items to Edit menu
  mbar.additem(2, "Undo", Undo)
  mbar.additem(2, "Redo", Redo)

  The menu bar will appear when its show function is called. Menu items can be enabled or disabled using the enableitem function, and ticked or unticked using the tickitem function.
  Example:
  mbar.enableitem(2, 1, CanUndo())
  mbar.enableitem(2, 2, CanRedo())
  mbar.show(0, 0, 600, 30)

op.process(event)
  Process the given event (normally the string returned by a getevent command). If it detects a click in a previously created button, check box or slider then it will call the appropriate onclick function and return an empty string to indicate the event was handled, otherwise it returns a copy of the given string so the caller can process the event.
  Example: local event = op.process( g.getevent() )

op.popupmenu()
  Create and return a table representing a pop-up menu. You can then use its additem function to append an item with a given label and a callback function that will be called if the user selects the item.
  Example:
  editmenu = op.popupmenu()
  editmenu.additem("Cut", CutSelection)
  editmenu.additem("Copy", CopySelection)
  editmenu.additem("Clear", ClearSelection)
  editmenu.additem("---", nil)
  editmenu.additem("Paste", PasteClipboard)

  The pop-up menu will appear when its show function is called (note that you need to pass in the overlay's width and height).
  Example:
  editmenu.setbgcolor("rgba 0 128 0 255") -- dark green background
  editmenu.show(mousex, mousey, ovwd, ovht)

Utility commands

op.hexrule()
  Return true if the current rule uses a hexagonal neighborhood.
  Example: if op.hexrule() then do_hex_stuff() end

The oplus package also defines a number of synonyms for some frequently used overlay commands.

Opaque colors:

  op.white |  | = "rgba 255 255 255 255"
  op.gray |  | = "rgba 128 128 128 255"
  op.black |  | = "rgba 0 0 0 255"
  op.red |  | = "rgba 255 0 0 255"
  op.green |  | = "rgba 0 255 0 255"
  op.blue |  | = "rgba 0 0 255 255"
  op.cyan |  | = "rgba 0 255 255 255"
  op.magenta |  | = "rgba 255 0 255 255"
  op.yellow |  | = "rgba 255 255 0 255"

Affine transformations:

  op.identity |  | = "transform 1 0 0 1"
  op.flip |  | = "transform -1 0 0 -1"
  op.flip_x |  | = "transform -1 0 0 1"
  op.flip_y |  | = "transform 1 0 0 -1"
  op.swap_xy |  | = "transform 0 1 1 0"
  op.swap_xy_flip |  | = "transform 0 -1 -1 0"
  op.rcw |  | = "transform 0 -1 1 0"
  op.rccw |  | = "transform 0 1 -1 0"
  op.racw |  | = op.rccw
  op.r180 |  | = op.flip

Themes:

  op.theme0 |  | = "theme 255 255 255 255 255 255 0 0 0 0 0 0 0 0 0"
  op.theme1 |  | = "theme 0 255 255 255 255 255 0 0 255 0 0 47 0 0 0"
  op.theme2 |  | = "theme 255 144 0 255 255 0 160 0 0 32 0 0 0 0 0"
  op.theme3 |  | = "theme 0 255 255 255 255 255 0 128 0 0 24 0 0 0 0"
  op.theme4 |  | = "theme 255 255 0 255 255 255 128 0 128 0 47 0 0 32 128"
  op.theme5 |  | = "theme 176 176 176 255 255 255 104 104 104 16 16 16 0 0 0"
  op.theme6 |  | = "theme 0 0 0 0 0 0 255 255 255 255 255 255 255 255 255"
  op.theme7 |  | = "theme 0 0 255 0 0 0 0 255 255 240 240 240 255 255 255"
  op.theme8 |  | = "theme 240 240 240 240 240 240 240 240 240 240 240 240 0 0 0"
  op.theme9 |  | = "theme 240 240 240 240 240 240 160 0 0 160 0 0 0 0 0"

  You can also access the themes via an array: local mytheme = op.themes[2].

For a good example of how to use the oplus package, see the 3D.lua script.