Control structures
Binding
/* main.sma */
use core
use base
use display
use gui
_main_
Component root {
Frame f ("Hello World!", 0, 0, 500, 400)
Exit quit (0, 1)
Clock cl (1000)
cl.tick->quit
}
The line cl.tick->quit
creates a component called a Binding
.
A Binding
creates an activation link between a source component, here the tick of a
Clock
, and a destination component, here an Exit
component.
Each time the source is activated, the
Binding
propagates the activation to the destination. Because a Binding
is itself a Component, it can be activated or deactivated.
Connector
/* main.sma */
use core
use base
use display
use gui
_main_
Component root {
Frame f ("Hello World!", 0, 0, 500, 400)
Exit quit (0, 1)
f.close->quit
FillColor fc (200, 50, 50)
Rectangle r (0, 0, 50, 100, 0, 0)
f.height => r.height
f.width =:> r.width
}
The line f.height => r.height
creates a component called a Connector
.
A Connector
is a data-flow component that copies the value of a source property to
a destination property each time the value of the source is changed. In this program, the height
of the Rectangle
will be always the same as the one of the Frame
.
The next line is also a Connector
. The difference is that there is a first copy on tree traversal. Thus the width of the rectangle will be changed at the start of the program while the height will be changed only if there is a change in the window geometry.
The left side of the Connector
operator can be any arithmetic or logical expression.
For example, if one wants that the width of the rectangle be proportional to the width of
the frame, one can write f.width / 5 => r.width
.
Assignment
/* main.sma */
use core
use base
use gui
_main_
Component root {
Frame f ("Hello World!", 0, 0, 500, 400)
Exit quit (0, 1)
f.close->quit
FillColor fc (200, 50, 50)
Rectangle r (0, 0, 50, 100, 0, 0)
f.height =: r.height
}
The line f.height =: r.height
creates a component called an Assignment
.
An assigment copies the value of a source property (left side) to a destination property (right side) but only one time, on
activation. In this piece of code, the assignment is activated on tree traversal when the root
component
is started. To activate it another time, it is necessary to embed it into a named AssignmentSequence so that we can bind another component to it:
/* main.sma */
use core
use base
use gui
_main_
Component root {
Frame f ("Hello World!", 0, 0, 500, 400)
Exit quit (0, 1)
f.close->quit
FillColor fc (200, 50, 50)
Rectangle r (0, 0, 50, 100, 0, 0)
AssignmentSequence a (1) {
f.height =: r.height
}
r.press->a
}
Within the AssignmentSequence declaration, a special parameter has been set to 1. This parameter specifies if the AssignmentSequence must be activated on tree traversal or not. If set to 1, it is not activated on tree traversal.
Switch
A Switch
is a container, that is a component to which it is possible to add any number of children.
Its main feature is that only one of its children can be active at a time.
A Switch
has a built-in child named state
which is a text property.
Each time the value of this property is changed, the Switch
looks for a child with the same name.
If one is found, then the current activated child is deactivated and the other one is activated.
/* main.sma */
use core
use base
use gui
_main_
Component root {
Frame f ("f", 0, 0, 500, 300)
Exit ex (0, 1)
f.close -> ex
/* style */
FillColor bg (70, 151, 255)
OutlineColor oc (240, 240, 240)
OutlineWidth w (2)
/* shape */
Rectangle r (10, 10, 200, 110, 5, 5)
/* behavior */
Switch sw (greater) {
Component greater {
f.width / 2 => r.x
}
Component lower {
Double x (10)
x =: r.x
}
}
f.width > 400 ? "greater" : "lower" => sw.state
}
In this example, the string "greater"
or "lower"
is assigned to the state of the Switch
depending
on the size of the frame, thus changing the position of the rectangle.
Finite State Machine (FSM)
The Finite State Machine
works in a very usual way, that is by specifying states and transition.
States are container to which any kind of components can be added, including another FSM. A component can be activated on transition.
Below is a code for a very simple button.
/* main.sma */
use core
use base
use gui
_main_
Component root {
Frame f ("f", 0, 0, 500, 300)
Exit ex (0, 1)
f.close -> ex
Spike click
FSM fsm {
State idle {
FillColor fc (50, 50, 50)
Rectangle r (0, 0, 100, 70, 10, 10)
}
State pressed {
FillColor fc (150, 50, 50)
Rectangle r (0, 0, 100, 70, 10, 10)
}
idle->pressed (idle.r.press)
pressed->idle (pressed.r.release, click) // here click is activated
pressed->idle (f.release)
}
}
Combining Switch and FSM
A FSM
has also a built-in child named state
whose value equals the name of the current state of the machine.
It is thus possible to combine a FSM
and a Switch
by connecting their state
properties.
If you adopt this pattern, be careful to choose the same name for Switch's children and FSM's states.
/* main.sma */
use core
use base
use gui
_main_
Component root {
Frame f ("f", 0, 0, 500, 300)
Exit ex (0, 1)
f.close -> ex
Spike click
Switch sw (idle) {
Component idle {
FillColor fc (50, 50, 50)
Rectangle r (0, 0, 100, 70, 10, 10)
}
Component pressed {
FillColor fc (150, 50, 50)
Rectangle r (0, 0, 100, 70, 10, 10)
}
}
FSM fsm {
State idle
State pressed
idle->pressed (sw.idle.r.press)
pressed->idle (sw.pressed.r.release, click) // here click is activated
pressed->idle (f.release)
}
fsm.state => sw.state // don't forget to connect FSM and Switch
}