Class Block

START HERE.

Parent of every element in the system.

Introduction

(words/letters in bold in this section refer to the ones in the Fig. 1 below)

  • A block is used to denote an element of a graphical user interface in this library (BLOCK), another famous name for this is widget but I will be using element / block interchangeable here.
  • The coordinate system as it is in love2d.
  • A rectangle we define by the coordinate of its upper-left corner and its width and height. I.e. it is a tuple (x, y, w, h). In Lua a rectangle would be a table with 4 keys x, y, w, h:
    local rectangle = {
      x = 10,
      y = 20,
      w = 100,
      h = 50,
    }
    
  • The enclosing cell of a block is a rectangle which the block is placed in, (X, Y, W, H) . In order to place the block use its place method. NOTE: you are not supposed to use this method on every block in your GUI, you usually call it once on the root block. See Layout. So placing an element on the screen requires not only the coordinate but the whole rectangle. NOTE: place itself doesn't draw anything. Use the block's draw method to actually draw it.

likeliHUD was created with the following objectives:

  • Declarative construction (similar to QML)
  • Everything is a rectangle
  • Automatic layout (but see the offset parameter below)

A typical user workflow consists of at least 3 steps when using this library

  • Create
  • Place
  • Draw

Create

Declarative construction means you create a block tree which represents your UI. Blocks can have properties and embedded (children) blocks. Properties go in the hash part of the block (in the end every block is a Lua table) i.e. key-value pairs; children elements is the array part of the block. However, see the inside property in the description of the new method. A simple example of an object tree which has the following diagram (properties and their values are written in the parentheses)

A1 (a: 1)
├───B1 (b: 2)
│   ├───B2 (b: 3)
│   ├───B3 (b: 4)
│   ├───B4 (b: 5)
│
├───C1 (c: 1)
    ├───C2 (c: 2)

can be created with the following code:

local root = A1 {
  a = 1,

  B1 {
    b = 2,

    B2 {
      b = 3,
    },

    B3 {
      b = 4,
    },

    B4 {
      b = 5,
    },
  },

  C1 {
    c = 1,

    C2 {
      c = 2,
    }
  }
}

Place

This library treats every block (BLOCK) as a rectangle of some width a and height b placed inside its enclosing cell (X, Y, W, H). It may also have some pads pad and/or offset (Xo, Yo, Wo, Ho). Below you can see a figure which we'll be referring to in this documentation a lot:

Fig.1
                     Enclosing cell
                           ┆
                           ┆       offset
                           ┆          ┆
(X, Y)                     ▼          ┆
  ■───────────────────────────────────┆────────────────────╮
  │          ▲                        ┆                    │
  │          Yo                       ┆                    │
  │          ▼                        ▼                    │
  │       ■──────────────────────────────────┬──────╮      │
  │       │              ▲                   │      │      │
  │◀︎ Xo  ▶︎│             Pad                  │      │      │
  │       │   (Xs, Ys)   ▼                   │      │      │
  │       │       ■──────────────────╮       │      │      │
  │       │       │                  │       │      │      │
  │       │◀︎ Pad ▶︎│      BLOCK       b       B      │      │
  │       │       │                  │       │      Ho     H
  │       │       ╰────────a─────────╯       │      │      │
  │       │                                  │      │      │
  │       │                                  │      │      │
  │       │                                  │      │      │
  │       ├─────────────────A────────────────╯      │      │
  │       │                                         │      │
  │       ╰───────────────────Wo────────────────────╯      │
  │                                                        │
  │                                                        │
  │                                                        │
  ╰───────────────────────────W────────────────────────────╯

This is the code that corresponds to the figure:

local BLOCK = ui.Rectangle {
  w = a,
  h = b,

  offset = {
    x = Xo,
    y = Yo,
    w = Wo,
    h = Ho,
  },

  pad = Pad,
}

BLOCK:place(X, Y, W, H)

One more time: to place an element you call its place method with the enclosing cell as an argument (actually it is 4 arguments, but you get the idea). Don't be afraid - you are not going to call this method on each element in your UI - usually only the root element is placed explicitly.

Draw

In order to draw an element call its draw method. Similarly to place you usually call it once (per frame) for the root element.

See below for details.

Class Block

block:new () Constructor.
block:size (includePad) Returns the size of the block.
block:cell () Enclosing cell.
block:place (x, y, w, h) Places the block within specified enclosing cell.
block:draw () Draws the block.
block:traverse () Block iterator.
block:mousemoved (x, y, dx, dy, istouch) Mouse movement handler.
block:mousepressed (x, y, button, istouch, presses) Mouse press handler.
block:mousereleased (x, y, button, istouch, presses) Mouse release handler.

Events

block:push (event) Pushes an event to the block and to all of its child down the tree.
block:filter (event) It says whether the event should propagate further down the tree or not.

User defined blocks

block:doDraw () A block must override this function to be drawn.
block:doPlace (x, y, w, h) Placement.
block:doMousemoved (x, y, _, _, _) Mouse moved.
block:doMousepressed (_, _, _, _, _) Mouse pressed.
block:doMousereleased (_, _, _, _, _) Mouse released.


Class Block

Represents a block.
block:new ()
Constructor. The user is not supposed to explicitly call this method. It's called automatically when an instance of Block is created. See here for details. When created a block can be given properties. The list of the properties below is common for all blocks in this library. NOTE: though can be given some properties might be ignored by a block either because of the type of the block and/or different circumstances. F.e. the fill property only makes sense when the block is placed inside a Layout.

  • visible : boolean. true (default) means the element is visible (drawn). Otherwise it is not visible

  • color: a color like in love2d (the table variant). For different type of a block it has different meaning. See concrete type. Default is nil.

  • pad : a non-negative number. The minimum gap between the block's border and the enclosing cell (see Fig. 1). It can be greater than the pad because of the offset parameter. NOTE: the pad along the x-axis is eqaul to the pad along the y-axis.

  • align : Alignment of the block inside its enclosing cell. A string containing one or two words 'center' (default), 'top', 'bottom', 'left', 'right' delimited by the + sign. For example, 'top+right' (equivalent to 'right+top'). NOTE: this string must be consistent: it doesn't make sense to have something like 'top+bottom' ('top' will be set), or 'left+right' ('right' will be set). In other words there are only 9 options of alignment (* means default):

    Fig.2
    
    ╭────────────────┬────────────┬────────────────╮
    │ top + left     │    top     │    top + right │
    │                │            │                │
    │                │            │                │
    ├────────────────┼────────────┼────────────────┤
    │                │            │                │
    │ left           │   center*  │          right │
    │                │            │                │
    ├────────────────┼────────────┼────────────────┤
    │                │            │                │
    │                │            │                │
    │ bottom + left  │   bottom   │ bottom + right │
    ╰────────────────┴────────────┴────────────────╯
    
  • fill : a table of the form { x = boolean, y = boolean }. Tells whether the block should occupy free space (along the corresponding axis) if placed inside a Layout. See Layout:new.

  • offset : a rectangle (Xo, Yo, Wo, Ho). Modifies the enclosing cell (X, Y, W, H) of the element (which was given by calling the place method) by adding (Xo, Yo) to (X, Y) and overriding (W, H) by (Wo, Ho). In other words, placing the element with the offset field (Xo, Yo, Wo, Ho) inside the cell (X, Y, W, H) is the same as placing this element inside the cell (X + Xo, Y + Yo, Wo, Ho). See Fig. 1. Usually used together with the inside element (see below).

    -- Rectangle is a Block
    local element = ui.Rectangle {
      w = 100,
      h = 100,
    
      offset = {
        x = 10,
        y = 20,
        w = 200,
        h = 200,
      }
    }
    
    element:place(10, 10, 300, 300) -- actually placed in (20, 30, 200,
    200)
    
  • inside : a block. Special property which value must be a block. Let us explain the meaning of the inside property looking at the following example:

    local UI = ui.Rectangle {
      id = 'A'
    
      w = 100,
      h = 50,
    
      inside = {
        ui.Rectangle { -- the enclosing cell of this element is A itself
          id = 'B',
    
          w = 60,
          h = 30,
        }
      }
    }
    
    UI:place(20, 20, 200, 200)
    

    which produces the following diagram:

    Fig.3
    
                          Enclosing cell of A
                                 ┆
                                 ┆
                                 ┆  Enclosing cell of B
    (0, 0)                       ┆       ┆
      ■──────────────────────────┆───────┆─────────────────╮
      │          ▲               ┆       ┆                 │
      │          20              ┆       ┆                 │
      │          ▼               ▼       ┆                 │
      │       ■──────────────────────────┆──────────╮      │
      │       │                          ┆          │      │
      │◀︎ 20  ▶︎│                          ┆          │      │
      │       │                          ▼          │      │
      │       │       ╭────────────────────╮        │      │
      │       │       │A                   │        │      │
      │       │       │   ╭────────────╮   │        │      │
      │       │       │   │B           │  50        │      │
      │       │       │   │           30   │       200     H (screen)
      │       │       │   ╰─────60─────╯   │        │      │
      │       │       │                    │        │      │
      │       │       ╰────────100─────────╯        │      │
      │       │                                     │      │
      │       │                                     │      │
      │       │                                     │      │
      │       ╰───────────────────200───────────────╯      │
      │                                                    │
      │                                                    │
      │                                                    │
      ╰───────────────────────────W (screen)───────────────╯
    

    as you can see now the enclosing cell of B is A itself, namely, (A.x, A.y, A.w, A.h). In other words B is automatically placed inside A. This property together with the offset one makes it possible to integrate elements (usually Label) into images. F.e., suppose you drew a health bar image:

    ╭─────────────────╮
    │■───────────────■│◀︎- cool health bar image
    ││ area for text ││
    │■───────────────■│
    ╰─────────────────╯
    

    and you want the text showing the health is always centered inside this image wherever the bar is placed. All you need is to place a Label inside this image with the right offset:

    local hp = ui.Image {
      path = 'path/to/image.png',
    
      inside = {
        ui.Label {
          text = '100',
          offset = {
            -- area for text
          }
        }
      }
    }
    

    Now wherever hp is placed the text inside it is placed correctly automatically.

  • filter : a function. It is supposed to filter the events if pushed to the element. See the Events section for details.

  • mouse : a table or boolean. Used to make a block react to mouse events (can be used to make buttons). A boolean used by some basic blocks in this library. In most cases this is a table containing mouse callbacks. There are 4 mouse callbacks available:

    • onExit : called each time the mouse (cursor) leaves the block
    • onEnter : called each time the mouse enters the block
    • onPress : called each time the mouse is pressed inside the block
    • onClicked : called each time the mouse is pressed and released inside the block

The mouse actually is an FSM (wiki) which diagram you can see below:

Fig.4 Mouse FSM

               outside/onExit
*     ┌───────────────────────────────┐                      ┌─────┐
│     │                               │                 ┌────▶State├───┐
│     │                               │                 │    └─────┘   │
│ ┌───▼─────┐    inside/onEnter    ┌──┴──────┐          │              │
│ │  Idle   │──────────────────────▶  Hover  │          │ event/action │
└─▶(initial)│                      │         │          └──────────────┘
  └─▲───────┘                      └───┬───▲─┘
    │              press/onPressed     │   │
    │                    ┌─────────────┘   │
    │                    │                 │
    │                    │                 │
    │                  ┌─▼─────────┐       │release/onClick
    │  outside/onExit  │  Pressed  │       │
    └──────────────────│           ├───────┘
                       └───────────┘

So there are 4 events managing the mouse FSM:

  • press
  • inside
  • outside
  • release

Each mouse callback accepts up to 1 (one) argument: if passed it is supposed to be the block itself (self). This is how it can be used:

ui.Rectangle {
    w = 200,
    h = 200,
    color = { 1, 0, 0 },
    mouse = {
        onExit  = function () print('Bye, cursor !') end,
        onEnter = function () print('Hello, cursor !') end,
        onPress = function (self) self.color = { 0, 0, 1 } end,
        onClick = function (self) self.color = { 0, 1, 0 } end,
    }
}

Note how in the example above the onExit and onEnter callbacks don't have parameters. But each time the mouse is pressed or clicked inside the rectangle onPress and onClick are used to change the color property of the rectangle.

block:size (includePad)
Returns the size of the block. The size of the block is the minimum rectangle which the block can be placed in, in the form of a table { x = width, y = height }.

Parameters:

  • includePad If true then the pads of the block are included (AxB in Fig. 1). If nil (default) or false the pads are not included (axb in the figure above)

Returns:

    A table of the form { x = width, y = height }
block:cell ()
Enclosing cell. Returns the enclosing cell of the block.

Returns:

    The enclosing cell rectangle i.e. a table of the form { x = cell.x, y = cell.y, w = cell.w, h = cell.h }, or nil. NOTE: the enclosing cell is initialized only after the block was placed by calling its place method. Otherwise it stays nil.

Usage:

    local r = ui.Rectangle {
      w = 100,
      h = 200,
    }
    
    local c = r:cell() --> c == nil
    
    r:place(10, 10, 300, 300)
    
    local c = r:cell() --> c = { x = 10, y = 10, w = 300, h = 300 }
block:place (x, y, w, h)
Places the block within specified enclosing cell.

Parameters:

  • x x coordinate of the cell (X in the Fig. 1)
  • y y coordinate of the cell (Y in the Fig. 1)
  • w width of the cell (W in the Fig. 1)
  • h height of the cell (H in the Fig. 1)
block:draw ()
Draws the block. Used to draw the block. Usually you don't want to call it on every block in your GUI - only once for each root element.
block:traverse ()
Block iterator. Used to iterate over blocks in the hierarchy.

Usage:

    local UI = ui.Layout {
      rows = 1,
      columns = 2,
    
      ui.Label {
        text = 'foo'
      },
    
      ui.Label {
        text = 'bar'
      }
    }
    
    for i, b in UI:traverse() do
      b.border = true
    end
block:mousemoved (x, y, dx, dy, istouch)
Mouse movement handler. . Parameters are the same as in love.mousemoved

Parameters:

  • x
  • y
  • dx
  • dy
  • istouch
block:mousepressed (x, y, button, istouch, presses)
Mouse press handler. Mouse press handler. Parameters are the same as in love.mousepressed

Parameters:

  • x
  • y
  • button
  • istouch
  • presses
block:mousereleased (x, y, button, istouch, presses)
Mouse release handler. Mouse release handler. Parameters are the same as in love.mousereleased

Parameters:

  • x
  • y
  • button
  • istouch
  • presses

Events

Communication with the external world is defined through the use of Events. An Event is any table with the mandatory id key and optional data. For example, this table can be an Event:

local event = {
  id = 'button.pressed',
  key = 'space',
}

The block which is supposed to react on events must have the corresponding on property of the following structure:

local l = ui.Label {
  text = 'hello',
  on = {
    ['text.changed'] = function (self, event)
      self.text = event.message
    end
  }
}

i.e. it is a table where keys are events' IDs and values are callbacks to those events. A callback accepts two arguments: the block itself (self), and the event.

To send an event to a block you call the push method on the block with the event as the only argument:

l:push { id = 'text.changed', message = 'world' }

This call will propagate the event to the label and call the corresponding function with 2 arguments: self is the label object, and the event itself.

NOTE: this means you cannot easily push an event to a non-root block. Also it means that triggering an event propagation from one block to another is not straightforward: you probably want to emit a signal from one block which in turn will push the corresponding event to the root element. See the buttons.lua for an example.

See the events.lua file for an example.

block:push (event)
Pushes an event to the block and to all of its child down the tree.

Parameters:

  • event A table. NOTE: it MUST have the id key which is often just a string.
block:filter (event)
It says whether the event should propagate further down the tree or not. And also can be used to modify the event: so the children blocks will get a modified event.

Parameters:

  • event Event to be passed. NOTE: DON'T modify this event inside this function (if overriden). If you want to modify the event create a new one inside this function and return it (see the 2nd return value).

Returns:

  1. A boolean. true means that event propagates down the tree (i.e. to the children). false means the event is filtered out and the propagation breaks.
  2. [optional] A table. If returned it MUST be a new event table. This new event will replace the original one (but only for the subtree starting from self). NOTE: you can either pass this function as a property in the constructor or override the method. See events.lua for an example.

User defined blocks

⚠️ This section is not complete and to be done. ⚠️
block:doDraw ()
A block must override this function to be drawn. Does nothing by default.
block:doPlace (x, y, w, h)
Placement. A block should override this function to be placed. Used to place the block within specified enclosing cell.

Parameters:

  • x x coordinate of the window
  • y y coordinate of the window
  • w width of the window
  • h height of the window
block:doMousemoved (x, y, _, _, _)
Mouse moved. A block can override this function.

⚠️ Care must be taken when overriding this function. As stated in Block:new this function manages the internal mouse FSM - if overridden incorrectly it can cause inconsistent behaviour. If you need to override this function you probably want to doMousepressed and doMousereleased also.

See Block:mousemoved for parameter description.

Parameters:

  • x
  • y
  • _
  • _
  • _
block:doMousepressed (_, _, _, _, _)
Mouse pressed. A block can override this function.

⚠️ Care must be taken when overriding this function. As stated in Block:new this function manages the internal mouse FSM - if overridden incorrectly it can cause inconsistent behaviour. If you need to override this function you probably want to doMousemoved and doMousereleased also.

See Block:mousepressed for parameter description.

Parameters:

  • _
  • _
  • _
  • _
  • _
block:doMousereleased (_, _, _, _, _)
Mouse released. A block can override this function.

⚠️ Care must be taken when overriding this function. As stated in Block:new this function manages the internal mouse FSM - if overridden incorrectly it can cause inconsistent behaviour. If you need to override this function you probably want to doMousemoved and doMousepressed also.

See Block:mousereleased for parameter description.

Parameters:

  • _
  • _
  • _
  • _
  • _
generated by LDoc 1.5.0 Last updated 2025-11-16 10:17:18