this documentation is work-in-progress, edit here (md).

GUI

sections in this chapter:
Elements »
Attributes »
Form fields »
Dialogs »
Network »
JSON »
Vault »
Images, Fonts and Colors »
Datapacks »
Building a datapack »
FFI »
[ Font ] source: [String] size: [Number] »

The GUI plugin in Xoscript offers functionality to display graphics and widgets, play sounds, store sensitive data and send or retrieve data from the internet.

The best way to use the GUI plugin is to load the Guihelper library. To load the GUI helpers library:

Gui use: Path guihelpers.

Make sure the guihelpers library file is in the working directory. Plugins like Gui are loaded automatically, so you can address the Gui object without importing it first. Instead of Program use:, the code reads Gui use:, this is important because the former will load from the filesystem while the latter will first attempt to load from a datpak, which is useful when exporting the app to a binary (.exe) or mobile app.

After loading the GUI and its helpers with this single line of code, you are ready to use GUI functionality.

To create a new view:

>> view := View new.

view
    component
    elements
        view
        extends: ['object'],
        elements
            ...your elements...
        close
    close.

Each view is structured like a tree. The top-element must always be component. Child elements must be listed under the elements section. The first child of the first elements block always must be view and must extend object. In the second element section you can list your own view elements. Here is a full example:

>> app := Gui new.
>> view := View new.

view
    component
    events: True,
    elements
        view
        extends: ['object'],
        elements
            label
            text: ['Hi!'],
            close
        close
    close.

app width: 300 height: 200,
screen: view string.

After defining the view tree you can display it by sending it to the Gui with the screen: message. It is wise to first set the dimensions though (width/height). To receive events, an element and all its parents must set events:True. Events are send as messages to the GUI instance:

app on: ['click:'] do: { :id
    ...your event handler...
}.

The ID parameter tells you which element has been clicked/touched. You must set a unique ID number for the element:

...
button
id: ['101'],
events: True,
elements
    label
    events: True,
    text: ['click me'],
    close
close
....

After processing the event, you can update the GUI by replacing a part of it using:

gui xml: fragment string name: ['counter'] at: ['102'].     

Where fragment is just another view component, name must be the name of the sub view and at: is the parent ID where the sub view must be inserted (replacing all children of the parent node).

Elements

Element Description
component Starts the definition of a new widget
elements Starts the enumeration of sub-elements
view Starts the definition of a new view (only needed inside a component).
object A visual object without a specific view, similar to a div in HTML.
button A clickable button. A button does not contain text; use a label instead.
label An element for displaying text (with the attribute text:). A label is
required inside a button to create a caption.
image An image element.
textarea A text input field.
dropdown A collapsible dropdown menu.
roller A selection menu in the form of a wheel.
tabview A view with tabs, as commonly seen on mobile phones.
tabview-bar Container for tabs inside a tabView.
tabview-tab A tab inside the tabContainer. Clicking it changes the active tab.
maxcontainer Simple container with width and height set to 100%, no padding, no margin and no border

Attributes

Attribute Description
extends: [String] Specifies which other component this is based on (usually object).
events: [Bool] Specifies whether this element is interactive or not. If interactive, all parent elements must be too.
width: [Number] Specifies the width of an element.
height: [Number] Specifies the height of an element.
text: [String] Sets text inside the element (label or textField).
active: [Bool] Sets a tab as active (used in tabView).
scrollable: [Bool] Allows scrolling within an element.
selectable: [Bool] Specifies whether text within the element can be selected.
password: [Bool] Specifies whether text is hidden like in password fields.
one-line: [Bool] Specifies whether a text field allows only a single line of text.
tab-bar-position: [String] Sets tab bar position in a tabView. Options: left, right, top, bottom.
border: [Number] Border thickness of the element.
border-color: [Color] Border color of the element.
ink: [Color] Text color of the element.
background-color: [Color] Background color of the element.
background: [Image] Sets a background image for the element.
image: [Image] Sets an image for an image element.
font: [Font] Sets the font for text inside the element.
shadow: [Number] Sets the shadow thickness of the element.
outline: [Number] Sets the outline thickness (not the border).
radius: [Number] Sets the corner rounding level.
bg-opa: [Number] Sets the background opacity level.
layout: [String] Sets the layout of sub-elements. Options: grid or flex.
flex-flow: [String] Direction of flexible layout. Options: row or column.
flex-align: [String] Sets the alignment in flexible layouts.
margin-left: [Number] Sets left margin.
margin-right: [Number] Sets right margin.
margin-bottom: [Number] Sets bottom margin.
margin-top: [Number] Sets top margin.
margin: [Number] Sets all margins.
padding-left: [Number] Sets left padding.
padding-right: [Number] Sets right padding.
padding-bottom: [Number] Sets bottom padding.
padding-top: [Number] Sets top padding.
padding: [Number] Sets all paddings.
maxwh Sets width/height to 100%

For any ['Number'] you may use:

  • a Number (i.e. 1,2,100...)
  • a String number (['100'])
  • a Percentage string (i.e. ['50%'])

Form fields

To read the value of a form field use:

gui field-value: ['1'].

As a parameter, pass the id of the form field element.

Dialogs

To show a simple dialog using the GUI:

Gui show: ['hello world!'].

Network

To send a POST-request to a website:

>> net := Network new.
new send: ['postdata'] to: ['https://www.xoscript.com/login'].

You can send a GET-request by replacing the post data with None.

JSON

The JSON object allows you to convert dicts to JSON as well as the other way around:

>> json := JSON jsonify: mydict.
>> dict2 := JSON object: json.

Vault

To store sensitive data like tokens on the client side, you can use the vault object:

>> vault := Vault new: ['myvault'].
vault set: ['mytoken'] password: mytoken.

To retrieve a sensitive object:

>> token := vault get: ['mytoken'].

Images, Fonts and Colors

In your GUI definition you can attach resources, like fonts, images and colors. You can create these as follows:

>> top := Image new: ['topbar.png'].

>> white := Color new 
            red: 255
            green: 255
            blue: 255.

>> icons := Font new source: ['remixicon.ttf'] size: 40.

Attach them to your GUI using the attributes listed above, i.e. border-color, background-color, background, font etc.

Datapacks

Instead of loading code, images or music from files you can also add them to a data package and have your program retrieve them from this package as well. The advantage of a data package that your resources are bundled in one, opaque package (so people can’t see the images or listen to the music files separately). Data packages are also required for exports to other platforms like mobile.

With the Package object, you can place files into a data package. You can then link this package to Media, and from that moment, all files will be retrieved from your data package:

>> data := Package new: ['datapackage'].
data add: ['rabbit.png'].

To use the data package:

Gui link: ['datapackage'].

Building a datapack

To make your own datapack, simply do:


>> package := Package new: ['mydatapack'].
package append: (File new: ['__1__']).
package append: (File new: ['file2']).
etc...

The main file should be named:

__1__

This way, the self-executing binary/app knows how to start your app.

You can also use the datapack generator tool (available on download page):

xo datapack.xo /path/to/app myapp.xo image.png etc...

The reason you have to specify a base path is to avoid having to type the same path over and over again...

FFI

FFI stands for Foreign Function Interface. It allows you to use functionality written by others in different programming languages, provided through DLL files, SO files, or Dylib files. These could be a variety of functions, and there's a vast range of available functionality through this method. Let's start with an example:

>> gui := Gui new.
gui link: (
 List new ;
 ['/usr/lib/x86_64-linux-gnu/libc.so.6'] ;
 ['printf'] ;
 ( List new ; ['pointer'] ; ['int'] ) ;
 ['void'] ;
 ['Printf'] ;
 ['template:number:']
).
>> s := Blob utf8: ['FFI has %d letters.\n'].
Printf template: s number: 3.
s free.

The result of this code is that you’ll see the following on the command line: FFI has 3 letters. Now, you're probably thinking, "That's a lot of code for something so simple." I mean, couldn't we just solve this with a Gui show command? The answer is a resounding yes! But this is meant as an illustrative example. FFI is usually used for more complex tasks, but those don't make good examples, so I chose something trivial.

The arguments for link method:

  • Argument #1: The DLL or SO file you want to use.
  • Argument #2: The function in that file you want to link.
  • Argument #3: A sequence with the names of the data types of the function’s arguments.
  • Argument #4: The name of the function's return type.
  • Argument #5: The name of the object you want to link this function to (if it doesn’t exist, it will be created automatically).
  • Argument #6: The message that this function should be linked to.

In the example above, we want to link the printf function from libc.so. You can find the data type names in the documentation of the software you are linking to. The available types are: void, pointer, float, double, int, uint, char, uchar, intX, and uintX, where X can be 8, 16, 32, or 64.

These types refer to the number of bytes required to store the data. For printf, we are linking to a new object called Printf and the message template:number:. You translate the external function into the Xoscript dialect before using it. The message template:number: expects a buffer with the template text as its first parameter. We create this buffer using a Blob object, which allows you to manually allocate memory. You are responsible for freeing this memory afterward with the free message.

You can fill a memory blob in various ways. In our example, we fill it with text, so we use the utf8: message (UTF-8 is an encoding to convert text into bytes). You can also fill a blob with fill:, passing a sequence of byte values. To read the contents of a blob, use from:length:. You’ll get the bytes back as a sequence. You can even create a C-struct with a Blob using the struct: message, passing a sequence of C types. This may be necessary when calling a C function in an external software library that expects a pointer to a struct.

[ Font ] source: [String] size: [Number]

example:


Gui init.
>> f := Font new source: ['../../../examples/passwordapp/remixicon.ttf'] size: 20.
Out write: f name, stop.

output:

font1