2 releases

Uses old Rust 2015

0.1.1 Nov 25, 2018
0.1.0 Nov 24, 2018

#886 in GUI

MIT/Apache

470KB
3.5K SLoC

FunGUI

A UI layout system that seperates the description of the interface and the styling/layout. This is designed to be used in games and is currently used in UniverCity.


lib.rs:

FunGUI is a UI layout system that seperates the description of the interface and the styling/layout.

In FunGUI there are two main systems that come into play that the rest is built around: Nodes and Styles.

Nodes

Nodes are used to describe the user interface without any information about how it should look, only the structure. There are two types of nodes: Elements and Text.

Elements are simply a name which could be anything, there are no special names as everything is controled by the style rules. Elements may contain child nodes.

Text as the name implies is just text. Unlike elements, text may not have any child nodes.

Any node may have properties on it. Properties are used to provide configuration to a node which is useful if you use the same node type multiple times. For example an url property may be used on a text node to allow the style rules to color it differently or make it clickable.

Example

An example of the node format:

alert(level="warning") {
    title {
        "This is an alert"
    }
    content {
        "If you would like more info click "
        "here"(url="http://....")
        "."
    }
    buttons {
        button(focused=true) {
            "Accept"
        }
        button {
            "Ignore"
        }
    }
}

Styles

Styles are used to define the behaviour of a node. This can be something like how the node will render or how the node will react to events.

Styles apply using matching rules to find what nodes they will apply too. Rules can specific a hierarchy of nodes and what properties the node should have and their values. This allows for a title inside an alert to act differently to a title inside an window for example.

Once a match is found the style rules are applied to the node. Rules can be a simple constant value or an expression. Expressions perform basic math (+-/*%) and boolean operations (|| && <= etc), reference properties that were matched and execute functions. Functions can be used for complex properties instead of spliting them across multiple rules.

Variables and types

Variables are typed and floats/integers are treated as seperate and not casted automatically, this includes constants in style rules as well. For constants defining a number as 5 will be an integer whilst 5.0 will be a float. For variables you can cast using int(val) or float(val).

Special variables

There are two special variables that can be used without using them in a matching rule: parent_width and parent_height. These allow you to size things relative to the parent's size without needing a custom layout to handle it. Whilst these are useful in some cases they do come with a larger cost. In order to handle this the interface may have to re-run the layout system multiple to resolve the variables causing a slowdown however this will generally only happen the first time the node has its layout computed.

Example

An example of the style format:

alert {
    center = true,
    layout = "rows",
    width = 500,
    height = 400,
}
alert(level="warning") {
    background_color = rgb(255, 255, 0),
}

alert > title {
    layout = "lined",
    width = parent_width,
}
alert > title > @text {
    font_color = rgb(0, 0, 0),
    font_size = 24,
}

alert > content {
    layout = "lined",
    width = parent_width,
}
alert > content > @text {
    font_color = rgb(0, 0, 0),
    font_size = 16,
}
alert > content > @text(url=url) {
    font_color = rgb(0, 120, 0),
    on_mouse_up = action("visit", url),
}

Layouts

Layouts take some of the style rules and use that to position and size a node. These can be added via add_layout_engine and selected using the layout style property.

Extension

The Extension trait paired with the RenderVisitor trait is the main way that is used to actually make the user interface do something. By itself FunGUI only does layout, the extension trait can be used to add events and rendering by adding its own properties to use in style rules. In UniverCity these are things like image and background_color for rendering and on_mouse_down for events where events are lua code defined inline with the styles:

button {
    border_width = border_width(15.0),
    border = border_image("ui/button", 15, 15, true),
    shadow = shadow(2.0, 2.0, rgba(0, 0, 0, 0.3), 3.0, 0.0, "outset"),
    layout = "center",
    can_hover = true,
}

button(theme="blueprint") {
    border_width = border_width(15.0),
    border = border_image("ui/button", 15, 15, true),
    tint = rgba(0, 255, 255, 0.4),
}
button(on_click=click) {
    on_mouse_up = list(click, "init#
        audio.play_sound('click')
        return true
    "),
}

Dependencies

~1.5MB
~25K SLoC