Graphite/gui
2021-02-14 15:07:18 -08:00
..
header Store content as a separate field 2020-07-15 12:03:37 +03:00
input Rename the component content special attribute children for consistency with React 2021-02-14 14:30:18 -08:00
viewport Add conversion from component AST to flat component with content attribute (resolves #3), add XML attribute parsing, fix template string attribute parsing bug 2020-07-15 01:11:52 -07:00
window Refactor layout system and abstract data types to separate definitions and tags 2020-08-02 21:41:01 -07:00
box.xml Rename the component content special attribute children for consistency with React 2021-02-14 14:30:18 -08:00
col.xml Rename the component content special attribute children for consistency with React 2021-02-14 14:30:18 -08:00
icon.xml Rename the component content special attribute children for consistency with React 2021-02-14 14:30:18 -08:00
if.xml Rename the component content special attribute children for consistency with React 2021-02-14 14:30:18 -08:00
README.md Add the GUI markup language spec to the docs 2021-02-14 15:07:18 -08:00
row.xml Rename the component content special attribute children for consistency with React 2021-02-14 14:30:18 -08:00
text.xml Rename the component content special attribute children for consistency with React 2021-02-14 14:30:18 -08:00

GUI System Explainer

This directory contains the XML files describing the components which make up Graphite's GUI.

Principles

The framework is inspired by Vue.js. Each component's layout is defined in an XML, and recursively made out of lower-level components.

Interactivity is provided by script files which expose reactive variables. As these variables are mutated, the component is updated to match the current state.

Layout

The layout engine does a top-down pass through the component tree in order to determine what to render.

Layout is controlled using predefined attributes, such as width, height, x-align, y-align, gap or padding.

Component lifetime

The children of a component are passed to it as a children attribute. For example, looking at the row component:

<row children="INNER_XML: (Layout) = [[]]">
    {{INNER_XML}}
</row>

The children attribute defines a new variable INNER_XML of type Layout which can contain more XML layout structure. It has a default value of [[]] which refers to an empty layout— XML syntax (for the Layout data type) written in a tag's attribute is wrapped in [[ (opening) and ]] (closing) symbols. In this case the INNER_XML variable defaults to empty XML, however it is not strictly useful here because the children attribute will always have its value replaced by whatever exists between opening and closing tags when this component is called from elsewhere.

This is then expanded in the body of the row: {{INNER_XML}}.

Defining new components

Component files

To define a new component, create a new .xml file in this directory. Subdirectories become namespaces for the components (e.g. the file window/main.xml defines a component <window:main>).

Parameters

User-defined parameters start with a colon (:).

They are created by adding attributes to a component source file: :parameter="VARIABLE_NAME: (VariableType) = defaultValue"

GUI System Markup Language Specification

Layouts

  • XML files laying out interface structure with tags for layouts and primitives
  • Namespaced with folder name like <namespace:layout-name>
  • Inner XML content bound to the variable specified in the children attribute of the root element definition
  • All custom attributes are prefixed with a : when used as arguments and as parameters
  • Root element in each file is the layout and its accepted arguments with a bound variable and default value
  • Templating using {{mustaches}} for bound variables and computed values in the associated script
  • Each layout has a companion script (Rust or WASM) that exposes computed values for templating
  • Each layout acts as a container element used in computing layout measurements

GUI layout tree data structure

  • Stores purely the data used by the renderer and shaders
  • Updated by the layout system

Primitive layouts

<box> | <box /> Draws a box

  • children [xml | none = none]
    Inner XML stays in the document
  • :fill [color | none = none]
    Fill color for the box
  • :round [size | size size size size = 0px]
    Rounds the corners
  • :border-thickness [size = 0px]
    Thickness of the border inside the box
  • :border-color [color | none = none]
    Color of the border inside the box

<icon> | <icon /> Draws an icon from an SVG file and optionally contains child elements

  • children [xml | none = none]
    Inner XML stays in the document
  • :svg [string = `missing_svg_alert.svg`]
    Location of the SVG file
  • :style [string = ``]
    CSS styling to be applied to the SVG, useful for applying templated variables

<text> Draws text

  • children [string = ``]
    The text to be drawn (eventually this could become XML for styling)
  • :color [color | none = [middlegray]]
    The color of the text
  • :size [size = 12px]
    The size of the text

<row> | <row /> Wraps content laid out across vertically-adjacent sections, or acts as a spacer

  • children [xml | none = none]
    The elements inside the row

<col> Wraps content laid out across horizontally-adjacent sections, or acts as a spacer

  • children [xml | none = none]
    The elements inside the column

<if> Conditionally enables or disables child content if :a equals :b

  • children [xml | none = none] The elements to be shown if :a equals :b
  • :a [TypeValue = true]
    The first variable that must equal the second variable
  • :b [TypeValue = true]
    The second variable that must equal the first variable

Layout calculation

width [Dimension = inner] Set the exact content width of the element

height [Dimension = inner] Set the exact content height of the element

x-align [Dimension::Percent = 0%] Factor from left (0%) to right (100%) to align content inside this larger element

y-align [Dimension::Percent = 0%] Factor from top (0%) to bottom (100%) to align content inside this larger element

gap [Dimension Dimension Dimension Dimension = 0px 0px 0px 0px] Collapses between neighbors, pushes/expands parent set to inner, not part of click target (negative values count against the interior dimension instead of adding to the outside of the dimension?)

  • gap [Dimension → a a a a]
    Sugar: Single value for all sides
  • gap [Dimension Dimension = a b a b]
    Sugar: Two values for top/bottom and left/right
  • x-gap [Dimension = 0px a 0px a]
    Sugar: Single value for left/right
  • x-gap [Dimension Dimension = 0px a 0px b]
    Sugar: Two values for left and right
  • y-gap [Dimension = a 0px a 0px]
    Sugar: Single value for top/bottom
  • y-gap [Dimension Dimension = a 0px b 0px]
    Sugar: Two values for top and bottom

padding [Dimension Dimension Dimension Dimension = 0] Doesnt collapse between neighbors, pushes/expands parent set to inner, part of the click target (negative values count against the interior dimension instead of adding to the outside of the dimension?)

  • padding [Dimension → a a a a]
    Sugar: Single value for all sides
  • padding [Dimension Dimension = a b a b]
    Sugar: Two values for top/bottom and left/right
  • x-padding [Dimension = 0px a 0px a]
    Sugar: Single value for left/right
  • x-padding [Dimension Dimension = 0px a 0px b]
    Sugar: Two values for left and right
  • y-padding [Dimension = a 0px a 0px]
    Sugar: Single value for top/bottom
  • y-padding [Dimension Dimension = a 0px b 0px]
    Sugar: Two values for top and bottom

scroll [Dimension::Percent = 0%] When child elements overflow their container, keep them visible on the top/left (0%) or bottom/right (100%) while clipping on the opposite side

Variables

Parameter

  • Attribute: ?: (T1 | … | Tn) = ?
    Declares a parameter with a list of possible types and a required default value
    • ^\s*({{)\s*(\w*)\s*(:)\s*(\()\s*(\w*\s*(?:\|\s*\w*\s*?)*)\s*(\))\s*(=)\s*(\w*)\s*(}})\s*$
    • {{ THE_NAME : (bool | color | inner | percent ) = none }}
    • Value Type: (String, Vec<TypeName>, TypeValue)

Argument

  • Attribute: {{?}} In an attribute, string, or between tags, evaluates to another type value via environment lookup
    • ^\s*({{)\s*(\w*)\s*(}})\s*$
    • {{THE_NAME }}
    • Value Type: String

Types

Layout

  • Attribute: [[<? ...>...</?>]]
    The XML layout language wrapped in double square brackets
    Body: <? ...>...</?>
    XML data
    • Value Type: Abstract syntax tree?

AbsolutePx

  • Attribute: ?px
    Absolute size in UI pixels
    • ^\s*(-?\d*(?:\.\d*)?)([Pp][Xx])\s*$
    • Value Type: f32

Percent

  • Attribute: ?%
    Percentage of the total size of the parent container
    • ^\s*(-?\d*(?:\.\d*)?)(%)\s*$
    • Value Type: f32

PercentRemainder

  • Attribute: ?@
    Percentage of the remainder of unfilled space within the parent container
    • ^\s*(-?\d*(?:\.\d*)?)(@)\s*$
    • Value Type: f32

Inner

  • Attribute: inner
    Use the width/height of the content, where any child percent-based values become inner
    • ^\s*([Ii][Nn][Nn][Ee][Rr])\s*$
    • Value Type: N/A

Width

  • Attribute: width
    Copies the computed width from the current element
    • ^\s*([Ww][Ii][Dd][Tt][Hh])\s*$
    • Value Type: N/A

Height

  • Attribute: height
    Copies the computed height from the current element
    • ^\s*([Hh][Ee][Ii][Gg][Hh][Tt])\s*$
    • Value Type: N/A

TemplateString

  • Attribute: `? … {{?}} …`
    A string with arguments inside, wrapped in backticks
    Body: ? {{?}} ? … ? {{?}}
    Not to be mixed with other sibling XML tags
    • ^\s*`(.*)`\s*$
    • Value Type: Vec<String | Argument>

Color

  • Attribute: ['?']
    Literal name read from the standard color palette
    Attribute: [?]
    CSS color parsed by rust-css-color
    • ^\s*(\[)(.*)(\])\s*$
    • Value Type: Color

Bool

  • Attribute: true
    The true value
    Attribute: false
    The false value
    • ^\s*([Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee])\s*$
    • Value Type: bool

None

  • Attribute: none
    Indicates the absence of a value
    • ^\s*([Nn][Oo][Nn][Ee])\s*$
    • Value Type: N/A

Drawing procedure

Depth or breadth first traversal, shallow nodes drawn before deeper nodes.

Updating and damaged flag

For any element marked damaged, it and all its children are redrawn.

Resizing panels marks all affected panel containers as damaged so the resized contents are drawn.

Antialiased corners

Pass along the parent nodes uniform, for any fragment located within a corner region, render the parent and blend antialiased GUI rectangle over it based on signed-distance function corner.

Pixels in the corner regions must be wholly from the parent (must live within the borders of the parent, parent cant be transparent, parent cant have a wider overlapping border radius).

Requires a special case for overlapping parent and child with same border radius in same location so only the child is shown to avoid bleeding doubled antialiased edges.