over 5 years ago - MatroseFuchs - Direct link

Declarative Markup Language and S-expressions

A markup consists of S-expressions . There are four types of S-expressions, each intended for a specific action:


Call method


( * *
+
)
:= =


(bind isEnabled "$event.enabled" init=false
(event "isEnableChanged")
)


bind -


isEnabled, "$event.enabled" - *


init=false - *


(event "isEnableChanged") - +




Add definition


(def (*) *
+
)
:= : [ = ]

:= =


This definition is essentially a specific instance of an S-expression method. It was introduced only for the special syntax, used for declaring parameters.


(def element TestView(name:str = '', count:number) layout=true
(block
)
)







Set a property value


( = )


(style
(width = 100px)
)

(tf
(text = 'Hello world!')
)







Get a property value


(.
+
)


(.graphics
(lineStyle 1 0xffffdc84 1)
(beginFill "0xff414141" "0")
(drawRect 0 0 450 64)
(endFill)
)




The entire markup is based on these four types of expressions.


Macros

A macro is a named and parametrized markup fragment, which is added to the place where it's called on the parsing stage.

Macros are implemented on the AST(Abstract syntax tree) level.

Definition of a macro:

(def macro (*)
+
)
:= : [ = ]

(def macro StatusesVehicleTypes(width:number=100%, height:number=100%, renderer:str='VehicleTypeItem', name:str='statusesVehicleTypes')
(element List "name" "renderer" "width" "height"
(scope
(containerFlow = "Flow.HORIZONTAL")
(listVscrollPolicy = 'off')
(listHscrollPolicy = 'off')
)
)
)

You can run a macro with the help of the key word — macro.

(macro * *)

(macro StatusesVehicleTypes 160 height=32)

Though it looks like an ordinary method call, it's not. The macro's content is added on the parsing stage.

In the definition of the macro, you can use the macros that were defined before. The resolve operation is done recursively.

(def macro ComponentStateBase (statesDict:expression)
(macro ComponentStateBaseScope "statesDict")
(macro ComponentStateBaseContent)
)


Markup Execution

The engine that executes the markup isn't tied to any specific features. It doesn't keep any knowledge base on sprites, scopes, etc.

A "target object" is the current object, subjected to the operations that are described in the S-expressions. S-expressions are divided into types: method, setter, and getter. On this level, even a definition is simply a method.

The first execution of a markup happens after the file's text has been uploaded to the framework. After the file is parsed, we get a list of S-expressions, contained by the file (as a rule, these are definitions and setups of global constants). A fake object is created to execute this list of S-expressions (though, in fact, these methods don't need it).

Once a definition has been declared, the engine starts executing the list of S-expressions. The engine creates the corresponding object and S-expressions, which are contained in the definition's body and applied to it.

As the S-expressions are being executed, the target object changes. This happens along with the execution of nested S-expressions. For them, the target object will be the object, returned by the parent S-expression. If the S-expression didn't return anything or returned something other than an object, the nested S-expressions won't be executed. Values (including objects) can be returned by methods and getters.

The example below shows how a target object is changing:


Data Types

In markup, variable must be strictly divided into types (arguments of definitions, variables of scope). Types are verified on the execution stage (except for macros — they are verified on the parsing phase).

This helps you identify errors much faster.

Type


Description


Syntax


Comments

number


number


12.34


For numbers, you can specify the unit of measure.




percent


12.34%







pixels


12px




bool


boolean expression


true / false




str


string


'text123'


single quotes

dict


dictionary


{a : 1, b: 2}




array


array


[1, 2, 3]




expression


calculated expression


"a ? 1 : 2"



inside double quotation marks


A constant can't be defined inside this expression.


gfx


указатель на любой GFx::Value


no


a constant cannot be defined in the layout and in the expressions

object


указатель на оперируемый объект


no


a constant cannot be defined in the layout and in the expressions














Note:


An important peculiarity of working with string literals and variables is that you don't need to use single quotation marks, because the parser interprets any value as a string. Consequently, there are two ways of declaring strings.

This peculiarity reveals itself when you use binding structures (bind, bindcall, sync, dispatch). Example:

# Dispatch of the evBtnUpEvent event
(dispatch evBtnUpEvent on=mouseUp)

The first argument of the dispatch function is a string-type variable, but you don't need to use single quotes.

Keep this peculiarity in mind when working with markup.


Enums

In expressions, you can use the enumerations that were set in the core c++ part of Unbound.

Enum name


Properties


Description


Example


Comments

Flow



HORIZONTAL


VERTICAL - by default value


TILE_HORIZONTAL


TILE_VERTICAL


REVERSE_HORIZONTAL


REVERSE_VERTICAL



These properties determine how nested display objects are positioned.



(block
(style
(flow = "Flow.HORISONTAL")
)
)


# This is the equivalent to what's written above:
(hblock
)







For blocks with a specified flow value, you can use the following aliases:

block — vertical block


hblock — horizontal block


vtile — vertical tile block


htile — horizontal tile block


reverse — vertical block with a reverse order of elements in it


hreverse — horizontal block with a reverse order of elements in it

For block property flow = Flow.VERTICAL


ZIndex



FOREGROUND


BACKGROUND



Set the z-index of the display object, and it will determine the object's z-positioning in the parent container.



(block
(style
(zindex = "ZIndex.BACKGROUND")
)
)








Easing



line


elastic_in


elastic_out


bounce_in


bounce_out


back_in


back_out


cubic_in


cubic_out


quint_in


quint_out


expo_in


expo_out


expo_in_out


sine_in


sine_out


sine_in_out



Types of easing for animation.



(controller $Animation
(play duration=0.3 to={alpha:0} easing="Easing.cubic_out")
)

over 5 years ago - MatroseFuchs - Direct link

Base blocks of markup language

Constant

Unbound constants have the same purpose as those in other languages: they serve to store fixed values.

Two types of constants can be used in Unbound:


Global constants
The (def function is used to declare a global constant. The value of the constant is added after its name. In the example below, C_ALLY is the constant's name, and 0xFF80c0ff is the constant's value.







Local constants
These constants are declared in the element's scope and can be used only inside this element.

over 5 years ago - MatroseFuchs - Direct link

Controllers

A controller is an entity that applies one type of action to the assigned object. For the $Instance, $FxInstance, and $Repeat controllers, specify the object in the renderer field. The $Animation controller targets the parent object. The $Sector controller is an object itself.

$Instance

This controller adds an instance of the element to the stage.

renderer sets the element, with which the controller will perform its operations. Available for binding.


layout determines whether the layout system is enabled or not. By default, the value is false.


args is a controller method. It passes the value from the parent scope to the renderer.


exprs is carried out inside the renderer, but this method has access to the parent scope. exprs can contain expressions and bindings. With the help of this method, the controller allows you subscribe to changes in variables from the parent scope.


enabled assigns the expression, which runs the controller. The controller is triggered if the expression is true.

In some cases, you don't need to create a separate element — you can add all the blocks to exprs and set the controller's layout parameter as true.

$FxInstance

This controller temporarily adds an instance of the element to the stage. The instance is removed from the stage when its lifetime expires. The lifetime is measured in seconds.

renderer, args, exprs, enabled, and layout — the same as in the $Instance controller.


create — this controller method creates an instance of the element. Calls of this method can be subscribed to an event in the scope.


lifetime determines how long the element will exist on the stage. If not set, the default lifetime is 15 seconds.

$Repeat

This controller creates the specified number of renderer copies.

renderer, args, exprs, enabled, and layout — the same as in the $Instance controller.


count sets the number of renderers. In count, you can specify any number or an expression, which will return a number.


removeChildAt(index) removes from the stage a renderer, whose id is index.


$index — an integer, which shows the child's ordinal number from 0 to the last element. The first created element will have $index=0, etc. By default, this variable is in the child's scope since the child's creation.

$Animation

This controller animates values of:

Properties of the target display object


Variables from scope


Variables from styles

Available controller methods with examples of how to fill in the parameters:


play — launch one animation







playSeq — launch a sequence of animations







stop — stop an animation


(stop
id="anmId" # id of the animation that needs to be stopped. The id is not set by default. If it is set, all the animations launched by this controller will be stopped.
)







stopSeq — stop an animation sequence


(stopSeq
id="anmId" # The id of the sequence, which needs to be stopped. The id is not set by default. If it is set, all the animations launched by this controller will be stopped.
)




Available easings:

Examples:


This is an example of an animation, triggered when you click the button. The text block displays changes of animationVariable.







Example of an animation


trigger — the condition that triggers the animation. This animation is triggered when the value in the condition changes to the opposite value. Its difference from enabled is that enabled is triggered only when the condition is true.

Warning: The peculiarity of this controller is that it memorizes the animated values in the to parameter without taking into account the delay. Therefore, if the animated values change during the delay, the controller will keep operating old values.


$ToolTipEvent

This controller adds the following functionality: a tooltip is created when you point the cursor to the target display object.

Note: The content property is necessary to be sent to create a tooltip.

Example of creating a simple text tooltip:

You can add localization keys to the header, body, note, and alert:

The controller allows you to create a customized tooltip with unique content. To do this, you need create an element with the content in the markup.

Then create ViewModel and View. The View must be inherited from ViewImpl.

Override the createToolTipContent method in the view, which needs to show the tooltip.


$ContextMenuEvent

This controller adds the following feature: a context menu is created when you right-click the target display object.

# Here is context menu.
(controller $ContextMenuEvent
# Unique ID of context menu. Context menu uses constant.
(bind content "exampleMenuID")
)

where exampleMenuID is a unique id for identifying the context menu in the view.

Override the createContextMenuContent method in the view, which needs to show the context menu.

def createContextMenuContent(self, event):
if event.contentID == ContextMenuID.EXAMPLE_ID:
return WTypesContextMenuContent(self.uniqueID)

return None


$PopOverEvent

This controller adds the following functionality: a popover is created when you click the target display object.

# Here is pop up.
(controller $PopOverEvent
(flow = "Flow.VERTICAL")
)

flow is the direction, in which the popover shows up.

Flow.VERTICAL — the popover is displayed above or below the target object, depending on the screen size.


Flow.HORIZONTAL — the popover is displayed to the left or right of the target object, depending on the screen size.

The controller tries to position the popover in such a way so that its borders don't go beyond the screen.


$AdjustPosition

This controller adjusts the target object's position in such a way so that it fits into the client screen.

(controller $AdjustPosition
(original_x = 10) # The x coordinate of the starting point for calculations. If not set, by default it is the x coordinate of the target object.
(original_y = 15) # The y coordinate of the starting point for calculations. If not set, by default it is the y coordinate of the target object.
(offset = "10.0") # Offset from original_x and original_y.
(default = "15.0") # If the coordinates are negative, this value will be set.
)


$Sector

This controller allows to draw sector using flash.display.Graphics of that controller target

over 5 years ago - MatroseFuchs - Direct link

Element

An element is a top-level object. An element has its own name, so it can be called (inter alia, from outside the document that contains it) or reused. There are two ways to reuse an element: create its instance by calling a Controller or create its instance by calling the element method with the element's name as the argument. An element has its individual scope, but variables of the parent scope can be set to it.

Element has params:

the layout boolean parameter, which enables and disables the layout system. Possible values: layout=true|false.


the isReadyTracked boolean parameter, which turns on (it equals true) tracking of dependency resolving for each child of element. Also tracking that additional conditions are ok for some specific blocks. For example, image block has additional condition - image is loaded. Element is hidden while tracking works. Event $evReadyChanged is triggered when dependencies are resolved and additional conditions are ok. If isReadyTracked equals false, than $evReadyChanged is triggered when nodes tree is build.



the entrance boolean parameter, determines root element for View. Possible values: entrance=true|false. Please read the view resource usage for the details




the initType dict/map parameter, used to specify that the run-time unbound object will be not the container block (for element definition by default) but it will be the block associated with initType. When you defining the type different from CONTAINER you have to use only the syntax of that block. For example, BUTTON is inherited from CONTAINER, you can define all kind of standard blocks inside, but at the same time you can use (label =) setter which is part of (button) block syntax.

Usage example:

over 5 years ago - MatroseFuchs - Direct link

Event

An event is an object, generated and dispatched upon any action of the user (a mouse click, a button pressed, etc.). To distribute the event, the dispatch method is used.

Events are defined in the scope.

(event valChanged)

(event evKilled)
...
(dispatch evKilled args={} dir="EventDirection.DOWN" (event $datahub.getEntity(entityId).health.evKilled))

dir sets the direction of the event in a hierarchy. By default, dispatch dispatches an event only within the element itself. To send an event to the parent, you need to specify EventDirection.UP in dir. In the child - EventDirection.DOWN. In siblings - just declare the event in the desired siblings, and dir can be omitted. For dir, a dict with values is entered in hud_replaces. By default, dir = 0.

(def constant EventDirection { NONE: 0,
UP: 1,
DOWN: 2
})

In Unbound, events can be generated from:


The core C++ part. For example, the valueChanged event is generated in the slider block, when its value changes.


(dispatch valChanged on='valueChanged' dir=1)







The Scaleform part. For example, the event of clicking on the display object.


(block
(style
(width = 100)
(height = 100)
(backgroundColor = 0xff00ff00)
)
(bind alpha "0.5" init=false on='click')
)




Difference Between Subscription to Events with the Help of on and event

Subscription of binding structures can be implemented in two ways:


By passing the event's name to the on argument.


(bind eventArgs "$event" init=false on='eventScope')







By passing the nested event object.


(bind text "$event" init=false (event "eventScope"))




The event can be generated in:

Scalefom; for example, the click event of the mouse, or the keyDown event of the keyboard.


The Core C++ part of Unbound; for example, the slider block generates the sliderPositionChanged event when the slider thumb's position changes.


Markup, i.e., the event has been defined in the element's scope and is generated in its definition.

(def element TestView() layout = true entrance=true
(scope
(event eventScope)
)

(element Button
(dispatch eventScope on='click')
)
)


Essentially, it isn't generation of an event; it is transformation from a Scalefom/Core C++ event (in this example, it is 'click') into the event of the scope (in this example, it is eventScope)

Let's consider how these two approaches differ.

If the event is generated in Scaleform or Core C++ Unbound, you can create subscription only by using the on argument.

If the event is defined in the element's scope, there are two subscription cases, depending on where the subscription is located.


Subscription inside the scope can be done both via on and event







Subscription outside of the scope can be done only via event




Consequently, you can use the on argument to subscribe only to the events, generated by the target object.

Let's consider separately subscription to events inside the scope when an element is created.

(element Button
(scope
(label = 'default text')
(bind label 'leftClick' init=false on='evBtnLeftClickEvent')
(bind label 'rightClick' init=false on='evBtnRightClickEvent')
)
)

The 'evBtnLeftClickEvent' and 'evBtnRightClickEvent' events are generated in the definition of the Button element.

If you use the event structure, the events must be defined in the parent scope.

over 5 years ago - MatroseFuchs - Direct link

Functions for calculated expressions

The list of functions is arranged in the form of a table.

Function name in markup


Description


Example


round(number)


Mathematical rounding to an integer





"round(0.423456)" # 0


toUpper(str)


Converts lower case symbols to upper case symbols





toLower(str)



Converts upper case symbols to lower case symbols



(var test:number = "clamp(smth, 0, 10)")


tr



IDS string localization






abs(number)


Mathematical module





radToGrad(radNumber)



Conversion from radians to degrees








tan(radNumber)



Tangent of an angle in radians








floor(number)


The closest integer that is less than or equal to the specified number





ceil(number)


The closest integer that is greater than or equal to the number







pow(basis, exponent)



The basis number is raised to the power of the exponent










formatSeparator(number)


Grouping the integer part into 3-digit segments, separated by a space. Rounding the fractional part to the second decimal place.


"formatSeparator(1103569353.789254232)" # result 110 123 123 123.79


formatFloatingPoint(number, numberOfDigits=1)


Rounds the fractional part to the numberOfDigits decimal place. By default, numberOfDigits = 1.



"formatFloatingPoint(1.193454334123)" # result 1.2


"formatFloatingPoint(0.423456, 3)" # result 0.423



subst(str, array_values, dict_values)


Substitution of the arguments into the placeholders.



"subst('first number is %d, second is %d', [50, 51])"


subst('%(min)d - %(max)d', [], {min:1, max:2})



countdownFormat(numberSeconds, numberOfDigits, isShowMinutes)



Formats the number of seconds into the min:secongs format.


If the number of minutes is 0, it displays 00



"countdownFormat(125, 0, true)"


min(x, y)


Minimum number of the two. return x < y ? x : y



(var test:number = "min(smth, smth2)")



max(x, y)


Maximum number of the two. return x > y ? x : y


(var test:number = "max(smth, smth2)")

over 5 years ago - MatroseFuchs - Direct link

Layout

Unbound has a layout system, which serves to position the blocks, located in one container, based on certain parameters. To turn on the layout system, set layout=true|false in the element's definition. The description of the element with layout=true is equivalent to def layout.

Layout's parameters are described in style.

Example:

Positioning of Blocks

The layout system positions the blocks based on the values of the position property. Position can have the following values:


flow — the layout system positions nested blocks one by one (a block's position depends on the position of the previous block); by default, position="flow"



absolute — the layout system excludes the block from the flow (positioning list)

To position blocks relative to each other with position="flow" you can use the following style properties:


paddingLeft / paddingRight / paddingTop / paddingBottom — left/right/top/bottom padding for nested blocks.


If you need to set all four parameters at once, you can use the following structure:


(style
(padding = [5, 10, 15, 20]) # [paddingLeft, paddingTop, paddingRight, paddingBottom]
)



marginLeft / marginRight / marginTop / marginBottom — left/right/top/bottom margin from the current block.


If you need to set all four parameters at once, you can use the following structure:


(style
(margin = [5, 10, 15, 20]) # [marginLeft, marginTop, marginright, bottom]
)



Note:



The principal difference between margins and paddings is that the paddings parameters are set in the parent block and determine the positioning of nested blocks, while margins determine the position of the current block.






gap, hgap, vgap — the distance between each of the nested blocks horizontally/vertically.


If the distance between blocks is the same horizontally and vertically, you can use the gap parameter.


Usage example:


As a result, you'll see the following:

Highlighted white is the size of the htile block.


align — positioning of all nested blocks as a single block. It can have the following values: left — the content's alignment with the left margin right — the content's alignment with the right margin top — the content's alignment with the top margin bottom — the content's alignment with the bottom margin center — the content's alignment with the central horizontal line middle — the content's alignment with the central vertical line


Example of the block's alignment with the left edge:


You can use several values at a time, by dividing them with "|" (for example, if you need to center the content both vertically and horizontally).

(align = "center | middle")

To position the blocks with position="absolute" the abovementioned properties aren't applied. In this case, you should use the following ones:


left / right / top / bottom — padding from the left/right/top/bottom edge of the container, which contains the block.
Example:


As a result, you'll see the following:


hcenter / vcenter — padding from the center horizontally/vertically


As a result, you'll see the following:




Note:



The size of the block whose position="flow" equals the sizes of the blocks, nested in it.


The size of the block whose position="absolute" equals 0 by default.

over 5 years ago - MatroseFuchs - Direct link

Macro

A macro is a named and parametrized markup fragment, which is added to the place where it's called on the parsing stage. This allows using a markup fragment several times.

Usage example:


Once defined, the macro can be called at any place.

# A structure that calls a macro
(macro trace expr="variable")


This mechanism is used for autogeneration of the scope, which will be bound with a Python model.

over 5 years ago - MatroseFuchs - Direct link

Scope

A scope is a storage of data, available in the body of the element's description. It is not inherited from parent elements. The markup features strong typing — all the used variables and their types, as well as events, must be defined before they are used in the calculated expression. Otherwise, they must be passed from an external scope when calling the element.

A scope can contain:

Variables (var)


Constants (const)


Definition of an event


Call of the bind method


Dispatch of an event


The $Animation controller for animating variables in the scope

Example:


The scope can be described in different parts of the element (for example, the level variable). On the execution stage, all the parts will be integrated into one scope. Display of the scope's content:

(trace "$scope")

result:

UBTRACE: Scope:
Events: __onParamChange
Vars:
color : 1.67738e+07
level : 0
radius : 13



Note:



The variables, passed to the element as arguments of a definition, are NOT added to the scope. In the example above, the textStyle variable is not in the scope.




When creating an instance of an element, you can change the variables in its scope:

Creating an instance of an element:

(element LevelView 'PromoTitleTextStyle'
(scope
(level = 10)
(radius = 40)
)
)

When an element is called, variables in its scope can be synced with the parent scope's variables.

Creating an instance of an element

(scope
(var parentLevel:number = 15)
)

(element LevelView 'PromoTitleTextStyle'
(scope
(bind level "parentLevel")
)
)

When scope is updated evScopeUpdated event is dispatched.

Note: It this moment evScopeUpdated event is dispatched only if model was changed.

evScopeUpdated event has the parameter "type". By default it equals "default". It is "model" in case of model updating.

(bind enableTutorialHint "!showUnavailableConfirm" init=false watch=false
(event "evScopeUpdated")
(enabled="$event.type == 'model'")
)

over 5 years ago - MatroseFuchs - Direct link

toplevel def

(def) or Definition

Construction (def object Name) allows to define global object that can be invoked from any file in working directories.


Warning! Name of the object have to be unique. No matter in the same or separate files this definitions placed. Otherwise you'll get error and only first object will be created.

(def element TestView())

(def element TestView())


ERROR: Duplicate element definition: 'TestView'

over 5 years ago - MatroseFuchs - Direct link

toplevel exec

Top level function exec is used to execute any calculated expression. Optionally possible to set event that will trigger execution of target expression.

Syntax:

(exec "someExpression" (event "someScopeEvent"))

Examples:

1. Play sound by mouse click:

(exec "playSound(R.sounds.gui.yes1)" on='click')

2. Play sound by event from scope:

(exec "playSound(R.sounds.gui.yes1)" (event "evBtnLeftClickEvent"))

over 5 years ago - MatroseFuchs - Direct link

Top-Level Trace

A top-level trace returns a message to the log and has all the capabilities of a top-level method:

Bindings to events (both events of the scope and the events whose names are passed via the *on* parameter).


Bindings to changes in parameters (if an expression is passed as a parameter).

Examples:

(trace 'Some message')
(trace 'Some message' init=false (event SomeEvent))
(trace "'Some message:' + someValue" init=false watch=false on='eventName')
(trace "someValue1 + ': ' + someValue2" watch=true)
# Below is an example of a trace upon condition: for example, if you've placed it inside some general macro and want to cut off irrelevant actuations
(trace 'Some message' init=false on='eventName'
(bind enabled "name == 'anyName'")
)

over 5 years ago - MatroseFuchs - Direct link

UI Widgets

Symbol

Adding a MovieClip to the stage by linkage. Symbols are used inside definitions of elements, whose layout parameter is set as false. Layout system is disabled.

Example:

(style
(backgroundImage = "'symbol:minimap_aim_position'")
)

'symbol:' + toLower('minimap_' + markerIcon)

Sprite

Adding a Sprite instance to the stage. Sprites are used inside definitions of elements, whose layout parameter is set as false.

Example:


MC

Adding a MovieClip instance to the stage by linkage. MovieClips are used inside definitions of elements, whose layout parameter is set as true. Layout system is enabled.

Example:

(def element TestView() layout=true
(mc 'FWCloseButtonSlimMC'
(name = 'closeBtnCrossAnim')
(bindcall gotoAndPlay "stateFrame")
)
)

TextField

Adding a TextField instance to the stage. This is supported for all elements, whose layout=true|false. To display a text, use the text or htmlText property. When text and htmlText will set at the same time, only last action will applied

Example:

(tf
(text = 'Hello world!')
)


When the text is too large and doesn't fit into the text field, you can use the elideMode property. If elideMode=true, the text that doesn't fit into the block is cut off, and the last three symbols of the text inside the block are replaced with dots. Every time a text is entered, the block generates the textElideStatus event with the value argument, which indicated whether the text has been cut or not.

Example:

substitute

substitute - textblock method that allows replacing substrings with pictures.

init=true - required argument

(tf
(class $TextDefault19NM)
(bindcall substitute imageOffset="_frameTextCount"
substitutionMap={'[test_icon]' : 'icon_ground_radar_ally' }
sourceText='radar: [test_icon] mouse: [KEY_LEFTMOUSE]'
postfix='_bg'
init=true
)
)


Element

Block

It adds a Sprite container-instance to the stage. All nested blocks will be added to this container and positioned one after another, based on the value of the flow property in the block's style.

A block has the following aliases:

block - vertical block


hblock — horizontal block


vtile — vertical tile block


htile — horizontal tile block


reverse — vertical block with reverse order of elements in it


hreverse — horizontal block with reverse order of elements in it


backgroundImage

It adds a Bitmap instance to the stage. In the source property, specify the following:

The path to the file (specify the relevant object of the R-class global object)


The texture name from the atlas


URL of the image

If the block's size hasn't been set in style, the block will become of the same size as the image, once the image is loaded.

(bind backgroundImage "markerIcon")
----------------
(style
(bind backgroundImage "'bitmap:' + toLower(markerIcon)")
)
----------------
(block
(style
(backgroundImage = 'url:../aircraft/icon_lock.png')
)
)


Slider

This component is just a regular Slider.

The component is configured through the following variables in its scope:

value (number) — current value of the slider between the minimum and maximum values.


minimum (number) — minimum value.


maximum (number) — maximum value.


enabled (true/false) — whether the slider is available or not.

The slider can dispatch the following events:


evValueChanged — the slider value has changed.

over 5 years ago - MatroseFuchs - Direct link

Styles and CSS

General Description

A block's layout parameters can be customized via its style. Each block has its own set of style parameters.

Customizing style for the tf block:

(tf
(style
(fontSize = 32)
(textColor = 0xFFFFFFFF)
)
(text = 'Hello world!!!')
)

Customizing style for the block-type block:

(block
(style
(backgroundColor = 0xffff0000)
(width = 100px)
(height = 100px)
)
)

Customizing style for the mc block:

(mc 'Window_BG'
(style
(width=100)
(height=50)
...
)
)


Styles can be described in a separate definition and transferred to the block's class property.

(def element TestView() layout = true
(block
(class BlockStyle)
)
)

(def css BlockStyle()
(backgroundColor = 0xffff0000)
(width = 100px)
(height = 100px)
)


The value of the class property can be calculated in an expression. This allows you to adjust the blocks' styles depending on the conditions.


If several styles with the same properties are applied to a block, the subsequent ones will overwrite the values of the previous ones. The application sequence is important.

(block
(class BlockStyle_1)
(class BlockStyle_2)
)

Note:


But if you change the style's property directly in the style and transfer CSS as a parameter with the same property, the sequence of style application does not matter. The style block will be the last one applied.

Table of Styles

Block types:

Basic blocks: tf, mc, image, and text_input.


Container blocks: block (and all its aliases — hblock, vtile, gtile, reverse, and hreverse), list, view_holder, slider, scroll_bar, progress. and scrollArea. Container blocks inherit the properties and methods of their base block.


Property


CSS analog


The property is supported by:


Value types


Example of a possible valie

width


width


all blocks


number, %, px


10px; 10%

minWidth


min-width


all blocks


number, %, px


100px; 50%

maxWidth


max-width


all blocks


number, %, px


100px; 50%

height


height


all blocks


number, %, px


10px; 10%

minHeight


min-height


all blocks


number, %, px


100px; 50%

maxHeight


max-height


all blocks


number, %, px


100px; 50%

position


position


all blocks


absolute, flow


absolute

left


left


all blocks


number, %, px


10px; 10%

right


right


all blocks


number, %, px


10px; 10%

top


top


all blocks


number, %, px


10px; 10%

bottom


bottom


all blocks


number, %, px


10px; 10%

center


offset from the center


all blocks


number, %, px


-170

hcenter


offset from the center horizontally


all blocks


number, %, px


10px; 10%

vcenter


offset from the center vertically


all blocks


number, %, px


10px; 10%

marginLeft


margin-left


all blocks


number, %, px


10px

marginRight


margin-right


all blocks


number, %, px


10px

marginTop


margin-top


all blocks


number, %, px


10px

marginBottom


margin-bottom


all blocks


number, %, px


10px

paddingLeft


padding-left


container blocks


number, %, px


10px

paddingRight


padding-right


container blocks


number, %, px


10px

paddingTop


padding-top


container blocks


number, %, px


10px

paddingBottom


padding-bottom


container blocks


number, %, px


10px

padding


padding


container blocks


number, %, px


10px

backgroundColor


background-color


container blocks


0xARGB


0x1000ff00

backgroundImage


background-image


container blocks


str, 'url: {url}', 'bitmap: {linkage}', 'symbol: {linkage}'


backgroundImage = 'url:..\icons\ico.png'

backgroundSize



background-size


background-repeat



container blocks


fill; crop; cover; repeat; autosize


backgroundSize = "crop"

flow


flex-direction


container blocks


Flow.HORISONTAL, Flow.VERTICAL, Flow.TILE_HORIZONTAL, Flow.TILE_VERTICAL


flow = "Flow.HORISONTAL"

align



justify-content


align-items



container blocks


left, right, bottom, top, center, middle


align = "middle|right"

alpha


opacity


all blocks


number from 0 to 1


1; 0; 0.4

fontSize


font-size


tf


number


36

leading


inter-string interval


tf


number




letterSpacing


letter-spacing


tf


number


2

fontFamily


font-family


tf


str




textColor


color


tf


0xRGB


0xCFC7A8

textAlign


text-align


tf


left; right; center


textAlign = "center"

multiline


white-space


tf


bool


true; false

ubScaleX


transform: scaleX()


all blocks


number



changes the block's scale horizontally


1.25


ubScaleY


transform: scaleY()


all blocks


number



changes the block's scale vertically


1.25


rotation



block rotation,


suitable for blocks which are located in absolute position



all blocks in absolute position


number (value in degrees)



(style
(rotation = 30)


)

pivotX



zero-point position by X


used for rotation, scale, absolute position



all blocks in absolute position


number, %, px



(style
(pivotX = 50%)


)


or


(style
(pivotX = 100px)


)

pivotY



zero-point position by Y


used for rotation, scale, absolute position



all blocks in absolute position


number, %, px



(style
(pivotY = 10%)


)


or


(style
(pivotY = 20px)


)

scaleX



scale by X


could be < 0, applied to block itself and its children



all blocks


double



(style


(scaleX = 1.2)


)

scaleY



scale by Y


could be < 0, applied to block itself and its childre



all blocks


double



(style


(scaleY = -1.0)


)


BackgroundSize

(def element NationFlagsSmall () layout=true
(style
(bind backgroundImage "'url:../nation_flags/small/flag_USA.png'" init=false)
(backgroundSize = "fill")
(width = 117)
(height = 72)
)
)

cover - растягиваем текстуру по размеру контейнера с сохранением пропорций текстуры, чтобы она заполняла всю площадь, с обрезанием текстуры за пределами контейнера.


crop - обрезаем изображение по размеру контейнера.


fill - растягиваем изображение по размеру контейнера без сохранения пропорций.


align - позиционируем изображение по центру контейнера с обрезанием текстуры за пределами контейнера.

over 5 years ago - MatroseFuchs - Direct link

CSS Tips and Tricks

Usage of style objects (similar to css-classes)

Create style objects:

(def css SomeStyleObject()
(position = "absolute")
(width = 100%)
(height = 100%)
)

Invoke:

(block
(class SomeStyleObject)
)

Example of implementing the Hover pseudo class

The Hover is triggered when you point to the cursor to a specific area, and not the entire block

If you need to set a certain area as hitArea, add a block whose name='hoverArea' and pass the block's name to the hitArea property of the parentElement element with the help of the $target object.

Styles change depending on the screen's width/height (similar to media requests)