Перейти к содержимому
Для публикации в этом разделе необходимо провести 1 боёв.
MatroseFuchs

Unbound 2.0 (документация)

В этой теме 17 комментариев

Рекомендуемые комментарии

Разработчик
33 публикации
572 боя

Системный уровень

Вычисляемые выражения

Unbound предоставляет возможность работать с так называемыми вычисляемыми выражениями (не путать с s-expressions). Это выражения, которые вычисляются на этапе исполнения. Содержимое выражения заключено в " ". Для удобства будем называть их просто expression, если речь будет идти об s-expressions, то это будет явно выделено. 

Выражения предназначены для несложной обработки данных, формирования значения свойств или параметров вызова метода. В выражениях можно использовать variables и events, объявленные в scope, а также числовые, строковые, логические литералы и использовать операторы.

(tf
    (text = "' ' + tankmanName + ' — '")
)
(mc AimForShipIcon_pro
    (gotoAndPlay "isAimed ? 'in' : 'out'")
)

Такие выражения будут вычислены при исполнении верстки, непосредственно при вызове методов. Выражение можно использовать как для вызова метода, как пример gotoAndStop, так и вызове s-expression как пример  (element …)

(def element List(hscroll_bar:str) layout=true
    ...
    (element "hscroll_bar" "name + 'HorScrlBar'")
    
)

 

Важно понимать, что эти выражения будут вычисляться один раз и никто не будет следить за обновлением данных, слежение за обновлением данных нужно использовать механизм биндинга.

 

Т.к за основу взят синтаксис action script, в выражениях можно использовать соответствующие операторы.

Скрытый текст

(trace "2 + 4")
(trace "name + 'HorScrlBar'") # аналогично: -, /, *, %

(trace "keyCode == 13") # аналогично: >, <, >=, <=, !=

(trace "isFocused && keyCode == 13") # аналогично: !, ||, &, ~, |

(width = "400 >> 1") # аналогично: <<

(scope
    (var testDict:dict = "{
        'up' : 'bitmap:button_black_bg',
        'hover' : 'bitmap:button_black_bg_hover',
        'down' : 'bitmap:button_black_press'
    }")
)
(text = "testDict['up']")

(text = "(count1 + count2) + '/' + (total1 + total2)")

(bind class "currStateClass ? currStateClass.style ? currStateClass.style : [] : []")

(trace "(str)count + '/' + (str)total")

 

 

Грамматика

Скрытый текст
root ternary_expr
ternary_expr logical_or ('?' expression ':' ternar_expr)?
logical_or  logical_and ('||' logical_and)*
logical_and  inclusive_or ('&&' inclusive_or)*
inclusive_or  exclusive_or ('|' exclusive_or)*
exclusive_or  exclusive_or ('|' exclusive_or)*
exclusive_or and ('^' and)*
and equality ('&' equality)*
equality  relational ([== !=] relational)?
shift  additive ([<< >>] additive)?
additive multiplicative ([+ -] multiplicative)*
multiplicative  cast ([* / %] cast)*
cast  '(' TYPE_NAME ')' cast | unary
unary  postfix | [- !] cast
postfix  primary ('[' ternary_expr ']' | '(' ')' | '(' argument_list ')' | '.' IDENTIFIER)*
argument_list assignment (',' assignment)*
assignment IDENTIFIER '=' ternar_expr | ternar_expr
primary IDENTIFIER | constant | '(' expression ')'
constant  IDENTIFIER | TYPE_NAME | STR | NUMBER | HEX | BOOLEAN | LIST | MAP
LIST '[' ']' | '[' ternary_expr (',' ternary_expr)* ']'
MAP '{' '}' | '{' IDENTIFIER ':' ternary_expr (',' IDENTIFIER ':' ternary_expr)* '}'
IDENTIFIER  $?[a-zA-Z]+[a-zA-Z0-9]*
NUMBER  [0-9]+ (.[0-9]+)?
PERCENT  [0-9]+ (.[0-9]+)? '%'
STRING  '/'' .* '/''
BOOL  true | false

 

 

Также в expressions можно вызывать функции.

(trace "toUpper('Skorpion G')")

 

  • Плюс 1

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

Базовая функциональность

 

Базовая функциональность определяет базовые возможности фреймворка:

  • формирование сцены (создание и добавление sprites, textfields, symbols, blocks)
  • scope, bindings system
  • построение definitions - element, css, animation, macro, constant.
  • holders глобальных данных (enums, глобальные константы, глобальные указатели на объекты, глобальные методы)

Build stage

Основной возможностью языка разметки unbound является создание, конфигурация и добавление instance of display objects (DO) в соответствующий target-объект в display list'е . Target-объектом является родительский DO для текущего фрагмента верстки  Все DOs разделяются на 2 группы по наличию/отсутствию layout system. Layout system отвечает за позиционирование DO на сцене.

(block
    (tf
    )
)

где нода block является target-объектом для DO tf.

 

Display objects without layout system

методы верхнего уровня описание
sprite Create empty instance of Sprite
symbol  Create instance of Symbol (MovieClip or Sprite) from library by linkage
bitmap  Create instance of Bitmap from library by linkage
tf Create instance of TextField
element Создание экземпляра элемента описанного в верстке
bitmapImage Create instance of Bitmap with argument BitmapData

 

 

 

 

 

 

 

 

 

 

 

 

 

Определение элемента

Верхнеуровневым DO верстки является element. Element – именованный параметризированный фрагмент верстки на базе спрайта. Element может иметь Scope, который содержит данные, доступные в теле element. Работа с элементом разделяется на 2 стадии: definition и create instance. Для определения элемента используется метод def.

(def element CommanderPersonalInfo() layout=true
)

Создание экземпляра:

(element CommanderPersonalInfo)

Scope

Scope - это хранилище данных и событий, доступных в теле определения элемента. Scope может иметь только Element, остальные DO могут работать только со scope родительского Element.

В scope должны быть объявлены все переменные и события, которые используются в теле element. Попытка обращения к несуществующему свойству или событию вызывает ошибку: access of undefined scope event 'nameEvent'

методы верхнего уровня описание
scope  Метод возвращает scope элемента для дальнейшей работы.

 

 

 

 

(scope
    (var lvlVal:str = '')
    (var title:str = '')
    (var cost:str = '')
    (var text:str = '')
    (var lvlTextColor:number = 0xffcac8c1)
    (var imageUrl:str = '')
)

Байндинги

Общее описание

Байндинги отвечают за простую синхронизацию данных (свойство, вызов метода, диспатч события). Существует три элемента синхронизации

  • свойство
  • вызов метода
  • событие

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

 

методы верхнего уровня описание
scope -> object  
bind запись значения в свойство объекта
bindcall вызов метода у объекта
object -> scope  
sync значение переменной в scope-е синхронизируется с значением свойства объекта
dispatch событие в scope-е синхронизируется с событием у объекта (диспатчится событие в scope-е по событию от объекта)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Все байндинги имеют общие свойства:

  • watch - следить ли за изменением значения свойств scope-а, которые используются в выражениях
  • init - производить ли действие (соответствующее типу байндинга) при инициализации байндинга
  • on - событие target-объекта, по которому будет срабатывать байндинг
  • enabled - можно использовать для включения и выключения срабатывания, может принимать выражения типа (enabled = "$event.buttonIdx == 1")

и общие методы:

  • event - добавляет произвольное событие в качестве триггера к байндингу

Bind

Синтаксис:

(bind scopeVar|property "scopeVar|$target|$event.field" [init=false|true] [watch=false|true] [on='scopeEventName|flashEventName|cppEventName']|[(event "scopeEventName")] [(enabled "expression")]), по-умолчанию init=true watch=true

Синхронизировать можно как переменную из scope, так и свойство target-объекта. 

  • Для синхронизирования переменной из scope, bind нужно поместить в scope.

    (scope
        (var count:number = 30)
        (var total:number = 100)
        (var percent:number = 0)
        (bind percent "count / total")
    )

     

  • Для синхронизации свойства target-объекта, bind должен вызываться в target-объекте, свойство которого мы синхронизируем.

    (scope
        (var vehicleType:str = 'vehicleHeavy')
    )
    (tf
        (bind text "vehicleType")
    )

     

В обоих случаях изменение любой переменной из выражения приводит к его вычислению, а результат записывается в синхронизируемую переменную или свойство. Управлять этим поведением можно через параметр watch=true|false.

 

Второй способ вызвать синхронизирование выражения - подписаться на событие. Поддерживается 2 способа для подписки на событие

  • Передать в аргумент on имя ивента как строку. Используется для подписки на флешовые события или события, которые распространяются из core c++. Если в этом ивенте есть аргументы, к ним можно получить доступ через объект $event. На момент выполнения выражения в bind все переменные должны уже быть известны. Но в $event аргументы попадут, если распространится событие. Так как события никакого еще не было, но на старте $event не определен, для этого у всех типов биндингов существует параметр init=true|false, которое позволяет настроить выполнение выражения при инициализации.

    (tf
        (class GrandTitleTextStyle)
        (text = 'default text')
        (bind text "$event.localX" init=false on='click')
    )

     

  • Передавать из scope объект event

    (scope
        (event onCustomEvent)
    )
    (tf
        (bind text "$event.localY" (event "onCustomEvent"))
        (dispatch onCustomEvent on='click')
    )

     

Примечание:

Подписаться на событие конкретного экземпляра элемента можно в его скоупе. Тогда передавать event нужно с использованием аргумента on.

Пример:

(element ButtonPrimary
    (scope
        (bind label "$event.localX+ $event.localY" init=false on='evBtnLeftClickEvent')
    )
)

Управлять исполнением синхронизации можно через вложенную конструкцию enabled, которая принимает выражение, результатом которого должно быть булевское значение. В свою очередь, если требуется подписать изменение enabled на event или выражение, нужно использовать bind.

Скрытый текст

(scope
    # Объявляем event
    (event changedToogle)
  
  
    # Объявляет булевскую переменную - условие для отключения/включение условия выполнения конструкции bind   
    (var toogleFlag:bool = true)     
    (bind toogleFlag "!toogleFlag" watch=false init=false (event "changedToogle"))
)
# Создаем кнопку, по клику которой будем выводить координату мыши
(element ButtonPrimary
    (scope
        # Подписываем переменную скоупа label на синхронизацию по клику на кнопку. Условие выполнения подписки - если toogleFlag имеет значение true
        (bind label "'localX: ' + $event.localX" init=false on='evBtnLeftClickEvent' (bind enabled "toogleFlag"))
    )
)
# Создаем кнопку, по клику которой диспатчится событие, которое переключает флаг toogleFlag.
(element ButtonPrimary
    (scope
        (bind label "'toogleFlag: ' + toogleFlag")
        (dispatch changedToogle on='evBtnLeftClickEvent')
    )
)

 

 

Bindcall

Синтаксис:

(bindcall functionName "scopeVar|$target"* [init=false|true] [watch=false|true] [on='scopeEventName|flashEventName|cppEventName']|[(event "scopeEventName")] [(enabled "expression")]), по умолчанию init=false watch=true

Используется для вызова метода у target-объекта по условиям (событие, изменение аргумента).

Пример использования при подписке вызов метода у DO:

(mc 'CloseBtnCrossAnim'
    (bindcall gotoAndPlay "stateFrame")
)

 

Таким образом, при изменении переменной stateFrame будет вызван метод gotoAndPlay. 

Другой пример - вызов методов у контроллеров:

(controller $Animation
    (bindcall play duration=0.2 from={alpha:0} to={alpha:0.5} (event "evBtnOverEvent") (bind enabled "_isPressed"))
)

Поведение параметров eventenabled такое же, как у конструкции bind.

Dispatch

Синтаксис:

(dispatch scopeEventName on='flashEventName|scopeEventName|cppEventName'|[(event "scopeEventName")] [args="{key1: value1, ...}"] [dir=0|1|2] [(enabled "expression")]), по умолчанию dir=0

Рассылка события по событию, которое генерируется scaleform или core c++ unbound. Перед тем как рассылать событие, его нужно объявить в scope.

(scope
    (event onClick)
)
(dispatch onClick on='click')

Передача аргументов

При рассылке события можно передавать аргументы. Аргументы передаются как dict. По умолчанию если не задан параметр args, то все свойства исходного event'a (тот ивент, который выступает тригером) передаются в рассылаемый event.

(scope
    (event onClick)
) 
(element ButtonPrimary
    (dispatch onClick on='click')
)
(trace "$event" init=false (event "onClick"))

Результат в ub_player_errors.log:

========================================================================
-------------------------------------------
UBTRACE: {altKey:false,bubbles:true,buttonDown:false,buttonIdx:0,cancelable:false,clickCount:0,commandKey:false,controlKey:false,ctrlKey:false,currentTargetFЧ',delta:0,eventPhase:2,localX:41,localY:18,mouseIdx:0,nestingIdx:0,relatedObject:[null],shiftKey:false,stageX:41,stageY:18,target:°FЧ',type:click}

Если же передать аргументы, то передача свойств исходного ивента не происходит.

Направление распространения события

Направлением распространения event можно управлять параметром dir. Поддерживаются 3 значения:

  • 0 - event распространяется внутри element. По умолчанию dir=0.
  • 1 - event распространяется от ребенка к родителю.
    Скрытый текст
    
    (def element TestView() layout = true  
        (scope
           (event onClick)
        )
      
        (element ChildElement)
      
        (tf
            (class HeroTitleYellowTextStyle)
            (text = 'default text')
            (bind text "$event.key" init=false (event "onClick"))
        )
    )
      
    (def element ChildElement() layout=true
        (scope
            (event onClick)
        )
        (element ButtonPrimary
            (dispatch onClick args={key: 100} dir=1 on='click')
        )
    )

     

    Примечание:

Важно помнить о том, что прежде чем использовать event, он должен быть объявлен в scope. Даже несмотря на то, что в scope определении element ChildElement event уже объявлен, его нужно также объявить и в TestView.

  • 2 - event распространяется от родителя к ребенку.
    Скрытый текст
    
    (def element TestView() layout = true  
        (scope
           (event onClick)
        )
      
        (element ChildElement)
      
        (element ButtonPrimary
            (dispatch onClick args={key: 100} dir=2 on='click')
        )
    )
      
    (def element ChildElement() layout=true
        (scope
            (event onClick)
        )
      
        (tf
            (class HeroTitleYellowTextStyle)
            (text = 'default text')
            (bind text "$event.key" init=false (event "onClick"))
        )
    )

     

     

Разделение событий

В приведенных примерах вложенный элемент распространяет событие и на сцене в родителе был только один экземпляр. Но часто бывают случаи, когда несколько одинаковых элементов лежат на одном уровне вложенности. Тогда отличить, от кого именно пришло событие, будет сложно. Рассмотрим пример:

Скрытый текст

(def element TestView() layout = true  
    (scope
       (event onClick)
    )
  
    (element ChildElement id=0)
    (element ChildElement id=1)
    (element ChildElement id=2)
    (element ChildElement id=3)
  
    (tf
        (class HeroTitleYellowTextStyle)
        (text = 'default text')
        (bind text "'click button id=' + $event.buttonId" init=false (event "onClick"))
    )
)
  
(def element ChildElement(id:number) layout=true
    (scope
        (event onClick)
    )
    (element ButtonPrimary
        (scope
            (label = "'button_' + id")
        )
        (dispatch onClick args="{buttonId: id}" dir=1 on='click')
    )
)

 

 

на сцене 4 экземпляра ChildElement, и каждый из них распространяет событие onClick. Текстовый блок будет ловить события от каждого элемента. Конечно, можно проверять id кнопки в выражении bind. Но также для этого можно передиспатчивать события из scope вложенного элемента в уникальное событие родителя.

Скрытый текст

(def element TestView() layout = true  
    (scope
       (event onClickChild1)
    )
  
    (element ChildElement id=0
        (scope
            (dispatch onClickChild1 on='onClick')
        )
    )
    (element ChildElement id=1)
    (element ChildElement id=2)
    (element ChildElement id=3)
  
    (tf
        (class HeroTitleYellowTextStyle)
        (text = 'default text')
        (bind text "'click button id=' + $event.buttonId" init=false (event "onClickChild1"))
    )
)
  
(def element ChildElement(id:number) layout=true
    (scope
        (event onClick)
    )
    (element ButtonPrimary
        (scope
            (label = "'button_' + id")
        )
        (dispatch onClick args="{buttonId: id}" dir=1 on='click')
    )
)

 

 

Т.е. событие onClickChild1 синхронизируется с событием onClick только у кнопки с id=0, поэтому поле text у текстового блока будет обновляться только при клике на эту кнопку.

Sync

Синтаксис:

(sync scopeVar from='getter|$target|$event.field' [init=false|true] [on='flashEventName|cppEventName']|[(event "scopeEventName")])

Позволяет синхронизировать переменную из scope со свойством объекта.

Скрытый текст

(scope
   (var clickedButton:number = -1)
   (var scopeText:str = 'test')
   (var scopeObject:object = null)
)
(tf
   (text = 'clickMe')
   (sync scopeText from='text' init=false on='click')
   (sync clickedButton from='$event.buttonIdx' init=false on='click')
   (sync scopeObject from='$target' init=false on='click')
)

 

 

В примере выше по событию click будут обновлены переменные scope: поле scopeText примет значение свойства text у текстового блока т.е. 'clickMe', поле clickedButton будет равно индексу кнопки мыши, которую кликнули, и scopeObject станет равен объекту tf, из которого и происходит клик, так как объект $target указывает на текущий блок.

Контроллеры

Сontroller  - это атомарная функциональность над target-объектом. Позволяет расширить функционал за счет выполнения кастомной логики над объектом. 

Controller реализуется на С++. 

 

методы верхнего уровня описание
controller Метод возвращает style текущего DO для дальнейшей работы

 

 

 

 

У каждого блока свой набор пропертей style. Так, например, блоку tf можно задавать font, size и color.

(tf
    (style
        (fontFamily = $TitleFont)
        (fontSize = 36)
        (textColor = 0xf5eed5)
    )
)

Также через изменение свойств style: paddings, margins, position, flow и т.п, - можно управлять позиционированием блока.

(block
    (style
        (position = "absolute")
        (bottom = 18px)
        (paddingLeft = 24px)
        (paddingRight = 24px)
    )
)

Style обладают только объекты с layout-system, а именно element с параметром layout=true и различного рода блоки, унаследованные от BaseBlock в c++. Обращение к свойством style у DO без layout system приводит к ошибке: access of undefined method 'style' through a reference with type element 

 

  • Плюс 2

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

Декларативный язык разметки и S-выражения

 

Верстка состоит из S-выражений. Существует 4 вида s-выражения, каждый из которых предназначен для конкретного действия:

  • Call method
    (<method name> <positional argument value>* <named argument>*
        <nested s-expression>+
    )
    <named argument> := <argument name> = <argument value>
    (bind isEnabled "$event.enabled" init=false
        (event "isEnableChanged")
    )

    bind - <method name>

    isEnabled, "$event.enabled" - <positional argument value>*

    init=false - <named argument>*

    (event "isEnableChanged") - <nested s-expression>+

  • Add definition
    (def <definition type> <difinition name> (<declaration argument>*) <named argument>*
        <nested s-expression>+
    )
    <declaration argument> := <argument name> : <argument type> [ = <default value> ]
    <named argument> := <argument name> = <argument value>
    По сути является частным случаем s-выражения-метода и введен только ради особого синтаксиса декларации параметров.
    (def element TestView(name:str = '', count:number) layout=true
        (block      
        )
    )

     

  • задать значение свойства
    (<property name> = <property value>)
    (style
        (width = 100px)
    )
      
    (tf
        (text = 'Hello world!')
    )
  • взять значение свойства
    (.<property name>
        <nested s-expression>+
    )
    (.graphics
        (lineStyle 1 0xffffdc84 1)
        (beginFill "0xff414141" "0")
        (drawRect 0 0 450 64)
        (endFill)
    )

На этих 4 типах выражений и строится вся разметка.

Скрытый текст

# definition
(def element CommanderPersonalInfo(name:str = '') layout=true
    (mc 'ResearchPageBGFlags'
        # set property
        (name = 'flags')
  
  
        # call method with argument
        (gotoAndStop "nation")
    )
  
    (block
        # get property
        (.graphics
            # nested s-expressions
            (beginFill "0xFF0000" "1")
            (drawCircle 40 40 10)
            (endFill)
        )
    )
)

 

 

Макросы 

Макрос - именованный параметризированный фрагмент верстки, который подставляется в место вызова на этапе парсинга.

Макросы реализованы на уровне AST (Abstract syntax tree). 

Определение макроса:

(def macro <macro name> (<declaration argument>*)
    <nested s-expression>+
)
<declaration argument> := <argument name> : <argument type> [ = <default value> ]
(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')
        )
    )
)

Использовать макрос можно с помощью ключевого слова macro. 

(macro <macro name> <positional argument value>* <named argument>*)
(macro StatusesVehicleTypes 160 height=32)

Несмотря на то что это выглядит как обычный вызов метода, это не так. Подстановка макроса происходит на этапе парсинга.

В определении макроса можно использовать макросы, определенные ранее. Подстановка происходит рекурсивно. 

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

 

Исполнение верстки

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

Здесь есть такое понятие, как таргет-объект. Это текущий объект, над которым выполняются действия, описанные s-выражениями. S-выражения различаются по типам (метод, сеттер, геттер) и не более (даже definition на этом уровне будет просто методом).

Первое исполнение верстки происходит после загрузки текста файла в фреймворк. После парсинга файла - мы имеем список s-выражений, которые содержатся в файле (как правило, это дефенишины, задания глобальных констант). Для исполнения этого списка s-выражений создается фейковый объект (хотя по факту этим методам он не нужен).

Другим частым случаем запуска движка на исполнение списка s-выражений является построение дефинишина, здесь создается соответствующий дефинишину объект и s-выражения, которые содержатся в теле дефинишина, исполняются над ним.

По ходу исполнения s-выражений таргет-объект меняется. Это происходит при исполнении вложенных s-выражений, для них таргет-объектом будет объект, который вернуло родительское s-выражение. Если s-выражение ничего не вернуло или вернуло не объект, то вложенные s-выражения исполняться не будут. Возвращать значения (в том числе объекты) могут методы и геттеры.

 

На примере подробно расписано, как меняется таргет-объект:

Скрытый текст

# метод def не возвращает ничего, поэтому его вложенные s-выражения не будут исполнены
# метод def их сохранит для дальнейшего использования при построении дефинишина
# s-выражения в теле дефинишина CommanderPersonalInfo будут исполнены над объектом sprite
# при построении элемента CommanderPersonalInfo
(def element CommanderPersonalInfo (command:str, toggle:bool = false) layout=true
    # target-object - Sprite
    # метод tf создаст TextField, добавит его в display list к текущему target-объекту
    # вернет созданный объект
    (tf
        # target-object - TextField, который вернул метод tf
        # style возвращает StylePreset для target-object
        # у style будет задано значение 100 свойству width
        (style
            (width = 100px)
        )
    )
  
  
    # метод mc создаст объект класса ResearchPageBGFlags из библиотеки по linkage,
    # добавит его в display list к текущему target-объекту, которым сейчас является Sprite
    # вернет созданный объект
    (mc 'ResearchPageBGFlags'
        # target-object - ResearchPageBGFlags (унаследованый от MovieClip)
        # вызван метод gotoAndStop c строковым аргументом 'ussr'
        (gotoAndStop 'ussr')
    )

 

 

Типы данных

В верстке введена строгая типизация (параметры definitions, свойства скоупа), проверка типов происходит на этапе исполнения (кроме макросов, для них на этапе подстановки, т е на этапе парсинга)

Введение типизации позволяет лучше контролировать ошибки.

тип описание синтаксис комментарии
number number 12.34 для типа number можно уточнить единицы
  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 вычиляемое выражение "a ? 1 : 2"

в двойных кавычках

константа не может быть определена внутри выражения

gfx указатель на любой GFx::Value нет константа не может быть определена в верстке и в выражениях
object указатель на оперируемый объект нет константа не может быть определена в верстке и в выражениях

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Примечание:

Важной особенностью при работе со строковыми литералами и переменными является то, что одинарные кавычки можно не использовать, т.к. парсер при разборе интерпретирует значения как строку. Поэтому существует двойственность при объявлении строковых переменных.

Скрытый текст

# Инициализация строкой переменной переменной
(var vehicleName:str = Skorpion)
  
  
# Объявление ключа в dict'e
(var testDict:dict = "{
    up : 'bitmap:button_black_bg',
    hover : 'bitmap:button_black_bg_hover',
    down : 'bitmap:button_black_press'
}")
(trace "toUpper(testDict['up'])")

 

 

Эта особенность проявляется и при использовании bindings конструкций (bind, bindcall, sync, dispatch), например:

# Dispatch события evBtnUpEvent
(dispatch evBtnUpEvent on=mouseUp)

Первым аргументом toplevel функция dispatch ожидает строку, но явно обозначать, что это строка, не требуется.

 

Enums

В выражениях можно использовать перечисления, которые заданы в core c++ части Unbound.

enum name свойства описание пример комментарии
Flow

HORIZONTAL

VERTICAL - значение по умолчанию

TILE_HORIZONTAL

TILE_VERTICAL

REVERSE_HORIZONTAL

REVERSE_VERTICAL

Свойства определяют то, как будут выстраиваться вложенные display objects.
(block 
    (style
        (flow = "Flow.HORISONTAL")
    )
)
  
  
# Эквивалент записи выше
(hblock
)

 

Для block с выставленным в стиле свойством flow существуют алиасы:

  • block - вертикальный блок
  • hblock - горизонтальный блок
  • vtile - вертикальный tile блок
  • htile - горизонтальный tile блок
  • reverse - вертикальный блок с обратным порядком элементов в блоке
  • hreverse - горизонтальный блок с обратным порядком элементов в блоке

У block параметр flow = Flow.VERTICAL

ZIndex

FOREGROUND

BACKGROUND

Назначить z-index display object в рамках родительского контейнера.
(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")
)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • Плюс 2

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

Конструкции языка разметки

Constant

Константы имеют такое же назначение, как и в других языках, и служат для хранения неизменяемых значений.

В unbound можно использовать 2 типа constant:

  • Глобальные констатнты
    Для объявления глобальной константы используется функция (def. В поле аргумента передается содержимое, которое может принимать переменная при объявлении.

    (def constant C_ALLY 0xFF80c0ff)
    # Далее в любом вычисляемом выражении можно использовать объявленную константу
    (style
        (width = "32px")
        (height = "32px")
        (backgroundColor = "C_ALLY")
    )
    Скрытый текст
    
    (def constant ModuleNames   [  
                                'engine',
                                'maingun',
                                'atba',
                                'aviation',
                                'airdefence',
                                'none',
                                'torpedoes',
                                'wheel',
                                'none',
                                'none',
                                'fire',
                                'flood'
                    ]
    )
      
      
    (var damagedModuleName:str = "(moduleState == 3 ? 'module_dead_' : 'module_crit_') + ModuleNames[moduleIndex]")

     

    Скрытый текст
    
    (def constant BTN_PRIMARY {
            up : {font: ButtonTextStyle, image: {source: 'bitmap:button_normal_bg', scale9: "Rect(15, 7, 135, 5)"} },
            hover : {font: ButtonTextStyle, image: {source: 'bitmap:button_normal_bg_hover', scale9: "Rect(15, 7, 135, 5)"} },
            down : {font: ButtonTextStyle, image: {source: 'bitmap:button_normal_bg_press', scale9: "Rect(15, 7, 135, 5)"} },
            disabled : {font: ButtonTextDisabledStyle, image: {source: 'bitmap:button_normal_bg_disabled', scale9: "Rect(15, 7, 135, 5)"} },
            disabledOverlay : {style: 'BtnNormalDisabledOverlayStyle'},
            focusOverlay : {image: {source: 'bitmap:button_normal_focus', scale9: "Rect(15, 7, 135, 5)"}},
            upSelected : {font: ButtonTextStyle, image: {source: 'bitmap:button_normal_bg_press', scale9: "Rect(15, 7, 135, 5)"} },
            hoverSelected : {font: ButtonTextStyle, image: {source: 'bitmap:button_normal_bg_press', scale9: "Rect(15, 7, 135, 5)"} },
            downSelected : {font: ButtonTextStyle, image: {source: 'bitmap:button_normal_bg_press', scale9: "Rect(15, 7, 135, 5)"} }
        }
    )
    (macro ComponentStateBase "BTN_PRIMARY")

     

     

  • Локальные константы
    Эти константы объявляются в scope element и могут быть использованы только в element'е.

    Скрытый текст
    
    (def element TestView() layout = true
        (scope
            (const STATE_AVAILABLE:number = 0)
            (const STATE_UNAVAILABLE:number = 1)
            (const STATE_LOCKED:number = 2)
      
      
            (var currentState:number = 1)
        )
      
        (tf
            (bind class "currentState == STATE_AVAILABLE ? 'EpicTitleYellowTextStyle' : 'GrandTitleYellowTextStyle'")
            (text = 'Hello Unbound!!!')
        )
    )

     

     

 

  • Плюс 2

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

Controllers

Контроллер -- сущность, выполняющая один тип действий с заданным объектом. У контроллеров $Instance, $FxInstance и $Repeat - объект указывается в поле renderer; контроллер $Animation направлен на родительский объект; контроллер $Sector сам является объектом.

$Instance

Добавляет на сцену экземляр element'a.

Скрытый текст

(controller $Instance renderer='PlayerListTextLine' layout=false
    (args entityId="13123")
    (exprs
        (scope
            (bind width "290")
            (bind isAlive "isAlive")
            (bind isSelf "isSelf")
        )
    )
    (bind enabled "isBoolTrue")
)

 

 

  • renderer задаёт элемент, с которым контроллер будет производить операции. Доступен для биндинга.
  • layout отвечает за то, будет ли работать layout система. Значение по умолчанию false
  • args при вызове передаёт в рендерер значение из скоупа, в котором находится.
  • exprs выполняется на стороне рендерера, но имеет доступ к родительскому скоупу. Может содержать выражения и биндинги. Через этот атрибут позволяет слушать в ребенке переменные из родительского скоупа.
  • enabled задаёт выражение для срабатывания контроллера. Контроллер сработает, если выражение == true.

 

В некоторых случаях не требуется выделять отдельный элемент, тогда блоки можно вложить в атрибут (exprs и выставить layout=true у контроллера.

Скрытый текст

(controller $Instance layout=true
    (exprs
        (tf
            (name = 'level')
            (class HeroTitleTextStyle)
            (selectable = false)
            (bind text "parentLevel")
        )
    )
)

 

 

$FxInstance

Временно добавляет на сцену экземпляр элемента, который будет удалён со сцены через «lifetime» секунд.

Скрытый текст

(controller $FxInstance renderer='LevelView' lifetime=2
    (args textStyle='HeroTitleTextStyle')
    (exprs
        (scope
            (level = "parentLevel")
            (radius = 40)
        )
    )
    (bindcall create (event "onClick"))
)

 

 

Скрытый текст

(def element LevelView(textStyle:str = 'MainTextStyle') layout=true
    (scope
        (event __onParamChange)
        (var radius:number = 13              
            (dispatch __onParamChange on='evChanged')
        )
        (var color:number = 0xfff2ad
            (dispatch __onParamChange on='evChanged')
        )
  
  
        (var index:number = "$index")
    )
  
    (style
        (bind width "radius * 2")
        (bind height "radius * 2")
        (align = "center|middle")
    )
    (.graphics
        (bindcall clear init=true (event "__onParamChange"))
        (bindcall lineStyle 1 "color" 0.3 init=true watch=false (event "__onParamChange"))
        (bindcall drawCircle "radius" "radius" "radius" init=true watch=false (event "__onParamChange"))
        (bindcall endFill init=true (event "__onParamChange"))
    )
    (scope
        (var level:number = 0)
    )
    (tf
        (name = 'level')
        (bind class "textStyle")
        (bind text "level" init=false)
        (selectable = false)
    )
)

 

 

  • renderer, args, exprs, enabled, layout - поведение аналогично поведению в $Instance контроллере
  • create - метод контроллера который создает экземпляр элемента.  Вызов этого метода можно подписать на событие в scope. 
  • lifetime определяет время жизни элемента на сцене. Если не задано - значение по умолчанию  15 секунд.
  •  

$Repeat

Создает указанное число копий рендерера.

Скрытый текст

(scope
    (event onClick)
    (var countRenderers:number = 5)
)
  
(controller $Repeat layout=true
    (bind count "countRenderers")
    (exprs
        (element ButtonPrimary
            (scope
                (label = "'button_' + $index")
            )
            (dispatch onClick args="{index : $index}" on='click')
        )  
    )
  
    (bindcall removeChildAt "$event.index" init=false (event "onClick"))
)

 

  • renderer, args, exprs, enabled, layout - поведение аналогично поведению в $Instance контроллере
  • count задаёт число копий рендерера. Может быть любым expression'ом. В примере выше -- counter равен количеству элементов в коллекции collection.
  • removeChildAt(index) - удаляет со сцены рендерер по index
  • $index - целое число, номер ребенка по порядку от 0 до конечного элемента. У первого созданного элемента будет $index=0 и т.д. Автоматически находится в скоупе ребенка с момента создания.

 

$Animation

Анимирует значения свойств target display object, переменных в scope или стилей.

Доступные методы контроллера  с примерами заполнения параметров

  • play - запуск одной анимации
    Скрытый текст
    
    (play
        duration=1.0  # продолжительность анимации в секундах. Обязательный параметр и должен быть больше ноля.
        to={ alpha:1, y:0, visible:true }  # финальные значения анимации. Обязательный параметр, если не передано имя анимации name(см. ниже), в противном случае пустой по умолчанию.
        from={ alpha:0, y:50, visible:false }  # стартовые значения анимации. Если не указать -- анимация начнется с тех значений, которые находятся в скоупе. Параметр пустой по умолчанию.
        name='AnimX'  # имя заранее объявленной анимации. Например: (def animation AnimX() from={x:0} to={x:300}). Пустое по умолчанию.
        delay=2.0  # указывает задержку перед проигрыванием анимации. По умолчанию равно 0.0.
        easing="Easing.quint_out"  # функция изменения анимации. Параметр пустой по умолчанию (соответсвует Easing.line).
        repeatCount=1  # количество повторений анимаций. Внимание! Параметр задает количество дополнительныйх повторений, т.е. если repeatCount=0, анимация проиграется один раз. -1 - анимация будет проигрываться постоянно. По умолчанию равно 0.
        reverse=false  # условия отыгрывания анимации в обратную сторону, to  from (при условии наличия обоих полей, либо наличии name). По умолчанию равно false.
        callbacks="{  # коллбеки анимаици. По умолчанию коллбеки не заданы.
            onComplete: onCompleteEvent,  # срабатывает, когда анимация закончилась
            onStart: onStartEvent,  # срабатывает, когда анимация стартует
            onRepeat: onRepeatEvent,  # срабатывает каждый раз, когда анимация начинается с начала. В коллбек передается параметр repeatCount - количество оставшихся повторений.
            onUpdate: onUpdateEvent,  # срабатывает каждый раз, когда анимация меняет значение параметра. В коллбек передается dict с текущими значениями параметров переданных в 'to' и 'from'.
        }"
        id='anmId'  # id анимации, по которому ее можно будет остановить через метод stop. По умолчанию id="".
    )

     

     

  • playSeq - запуск последовательности анимации
    Скрытый текст
    
    (playSeq
        "[  # основной обязательный параметр, без имени, идет первым в списке, задает последовательность анимаций. Синтаксис задания анимаций аналогичный методу play. Доступные параметры: duration, to, from, name, delay, easing, repeatCount, reverse, callbacks
             {duration:1.0, to:{scale:2.0, alpha: 0.5}}, delay: 0.4},
             {duration:2.0, to:{scale:1.0, alpha: 1.0}, callbacks: "{onStart: onAnmStart}"},
             .....
        ]"
        delay=2.0  # указывает задержку перед проигрыванием анимации. По умолчанию равно 0.0.
        repeatCount=1  # количество повторений последовательности анимаций. Внимание! Параметр задает количество дополнительныйх повторений, т.е. если repeatCount=0, последовательность проиграется один раз. -1 - последовательность будет проигрываться постоянно. По умолчанию равно 0.
        callbacks="{  # коллбеки последовательности анимаиций. По умолчанию коллбеки не заданы.
            onComplete: onCompleteEvent,  # срабатывает, когда анимация закончилась
            onStart: onStartEvent,  # срабатывает, когда анимация стартует
            onStartItem: onStartEvent # вызывается, когда стартует элемент последовательности. В коллбек передается параметр itemIndex - индекс стартующей анимации.
            onRepeat: onRepeatEvent,  # срабатывает каждый раз, когда анимация начинается с начала. В коллбек передается параметр repeatCount - количество оставшихся повторений.
        }"
        id='anmId'  # id последовательнсти анимаций, по которому ее можно будет остановить через метод stopSeq. По умолчанию id="".
    )

     

  • stop - остановка анимации
    (stop
        id="anmId"  # id анимации, которую необходимо остановить. Если id не задан, а по умолчанию он не задан, то будут остановлены все анимации, запущенные с помощью этого контроллера.
    )
  • stopSeq - остановка последовательности анимаций
    (stopSeq
        id="anmId"  # id последовательности, которую необходимо остановить. Если id не задан, а по умолчанию он не задан, то будут остановлены все анимации, запущенные с помощью этого контроллера.
    )

Доступные изинги:

Скрытый текст

line
bounce_in
bounce_out
back_in
back_out
cubic_in
cubic_out
elastic_in
elastic_out
quint_in
quint_out

 

 

Примеры:

  1. Пример запуска анимации по клику на кнопку и отображение в текстовом блоке изменяющихся значений. Анимация переменной в scope :
    Скрытый текст
    
    (scope
        # Объявить переменную, которую хотим анимировать
        (var animationVariable:number = 0)
      
      
        # Event для вызова метода play
        (event playAnimationEvent)
      
        # Контроллер обязательно должен быть расположен в scope
        (controller $Animation
            (bindcall play
                duration = 10
                from     = "{animationVariable:0}"
                to       = "{animationVariable:360}"
                easing   = "Easing.cubic_out"
                (event "playAnimationEvent")
            )
        )
    )
      
    (tf
        (class HeroTitleYellowTextStyle)
        (bind text "animationVariable")
    )
      
    (element ButtonPrimary
        (scope
            (label = 'Play')
            (dispatch playAnimationEvent on='evBtnLeftClickEvent')
        )
    )

     

     

  2. Пример анимации свойств стилей
    Скрытый текст
    
    (scope
        (event playAnimationEvent)
        (var triggerAnimation:bool = false)
        (bind triggerAnimation "!triggerAnimation" init=false watch=false (event "playAnimationEvent"))
    )
      
    (block
        (style
            (position = "absolute")
            (width = 50)
            (height = 30)
            (top = 100)
            (left = 100)
            (backgroundColor = 0xFFFF0000)
            (alpha = 0)
        )
      
        (controller $Animation
            (bindcall play
                duration=2
                easing="Easing.cubic_out"
                from="{alpha:0, top:100, width: 50, height: 30}"
                to="{ alpha:1, top:200, width: 100, height: 50 }"
                reverse="!triggerAnimation"
                (bind trigger "triggerAnimation")
            )
        )
    )
      
    (element ButtonPrimary
        (scope
            (label = 'Play')
            (dispatch playAnimationEvent on='evBtnLeftClickEvent')
        )
    )

    trigger - условие срабатывания анимации, когда значение условия меняется на противоположное. Отличие от enabled в том, что enabled срабатывает только когда выражение true.

     

$ToolTipEvent

Контроллер добавляет следующую функционалость: при наведении на target display object создает тултип.

 

Примечание:

Для создания тултипа свойство content должно быть передано обязательно.

 

Пример создания простого текстового тултипа:

Скрытый текст

# Here is simple tooltip containing text that is defined from markup.
(controller $ToolTipEvent
    # Double containing delay in seconds after which tooltip is shown on a element.
    (delay = "0.4")
      
    # Header, body, note and alert of simple tooltip are defined in arguments.
    (args header='Header' body='Body' note='Note' alert='Alert')
      
    # Unique ID of content. Tooltip uses resource ID of layout.
    (content = "R.layouts.gui.unbound.views.tooltip_window.views.simple_tooltip_content.resId")
)

 

 

В header, body, note и alert можно передать локализационные строки:

Скрытый текст

# Рere is simple tooltip containing ResGUID for string that is defined from markup.
(controller $ToolTipEvent
    # Double containing delay in seconds after which tooltip is shown on a element.
    (delay = "0.4")
  
    # Header, body, note and alert of simple tooltip are defined in arguments.
    (args header="R.strings.development.wulf.wTypesDemo.tooltip.header.resId" body="R.strings.wuf_example.wTypesDemo.tooltip.body.resId")
      
    # Unique ID of content. Tooltip uses resource ID of layout.
    (content = "R.layouts.gui.unbound.views.tooltip_window.views.simple_tooltip_content.resId")
)

 

 

Контроллер позволяет создавать кастомизируемый тултип с уникальный контентом. Для этого в верстке нужно создать element с контентом:

Скрытый текст

(def element ImagePreviewWindowContent() layout = true
    (macro PreviewImageModel)
    (style
        (minWidth = 150px)
        (align = "center|middle")
        (padding = 6px)
    )
  
    (image
        (bind source "image")
    )
)

 

 

Затем создать ViewModel и View, которая должна наследоваться от ViewImplo  для этого контента.

properties:
  - name: image
    type: resource
    restype: image
Скрытый текст

class ImagePreviewContent(ViewImpl):
  
    __slots__ = ()
  
    def __init__(self, imageID):
        super(ImagePreviewContent, self).__init__(
            R.views.imagePreviewWindowContent, ViewFlags.VIEW, PreviewImageModel, imageID
        )
  
    @property
    def viewModel(self):
        # type: () -> PreviewImageModel
        return super(ImagePreviewContent, self).getViewModel()
  
    def _initialize(self, imageID):
        super(ImagePreviewContent, self)._initialize()
        self.viewModel.setImage(imageID)

 

 

Во view в которой требуется отображать тултип перегрузить метод createToolTipContent

Скрытый текст

def createToolTipContent(self, event):
    if event.contentID == R.views.imagePreviewWindowContent:
        return ImagePreviewContent(R.images.gui.maps.icons.awards.battleSwords)
  
    return None

 

 

$ContextMenuEvent

Контроллер добавляет следующую функционалость: при клике правой кнопкой мыши по target display object создает контекстное меню.

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

где exampleMenuID - уникальный id для индентификации во view. 

В view в которой необходимо создать контекстное меню переопределяем метод createContextMenuContent

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

$PopOverEvent

Контроллер добавляет следующую функционалость: при клике по target display object создает popover.

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

flow - направление отображения popover'а. Принимаемые значения: 

  • Flow.VERTICAL - popover отображается сверху или снизу от target-объекта в зависимости от размера экрана
  • Flow.HORIZONTAL - popover отображается слева или справа от target-объекта в зависимости от размера экрана

Контроллер старается разместит popover на экране так, чтобы он не выходил за экран.

 

$AdjustPosition

Контроллер корректирует позицию target-объекта так, что бы он помещался в экран клиента.

(controller $AdjustPosition
    (original_x = 10) # Координата x начальной точки для расчетов, по умолчанию если не задана, принимает значение координаты x target-объекта
    (original_y = 15) # Координата y начальной точки для расчетов, по умолчанию если не задана, принимает значение координаты y target-объекта
    (offset = "10.0") # Отступ от координат original_x и original_y
    (default = "15.0") # Значение которые будет выставлено, если координаты будут отрицательные
)

$Sector

Рисует сектор используя flash.display.Graphics target объекта

Скрытый текст

(def element SectorControllerSample() layout=true
    (x = 10)
    (y = 10)
    (scope
        (var _circOffset:number = 30)
        (var _circArc:number = 60)
        (var _circRad:number = 200)
        (var _circInRad:number = 50)
        (var _circColor:number = 0xffff0000)
        (var _circGradient:array = [0xffff0000, 0xffff00ff, 0xffffff00])
        (var _circAlphas:array = [1, 0.5, 0.5])
        (var _circRatios:array = [0, 127, 255])
        (var _lineThickness:number = 10)
        (var _lineColor:number = 0xffffffff)
        (var _lineAlpha:number = 0.5)
    )
  
    (block
        (mc 'flash.display.Sprite'
            (controller $Sector
                (offset="_circOffset")
                (color="_circColor" )
                (arc="_circArc" )
                (radius="_circRad" )
                (colors="_circGradient" )
                (alphas="_circAlphas")
                (ratios="_circRatios")
                (lineThickness="_lineThickness")
                (lineColor="_lineColor")
                (lineAlpha="_lineAlpha")
                (innerRadius="_circInRad")
            )
        )
    )
)

 

 

 

  • Плюс 2

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

Element

Объект высшего уровня. Имеет собственное имя, может быть вызван (в том числе извне документа, в котором находится) и переиспользован (с помощью Controllers или прямого объявления). Имеет свой обособленный scope, в который может принимать извне присланные значения. Элемент может быть 2 видов: участвовать в layout (иметь стили) и не участвовать. Это регулируется свойством layout=true или использование алиаса def layout:

Скрытый текст

(def element PlaneMarker() layout=true
    (element PlaneIcon)
)
  
#или
  
#(def layout PlaneMarker()
#    (element PlaneIcon)
#)
  
(def element PlaneIcon()
    (symbol "(isConsumable ? 'catapult': 'fighter') + '_c'"
        (scaleX = 1)
        (scaleY = 1)
    )  
)
(horizontalSlider
      (element "hscroll_bar" "name + 'HorScrlBar'")
)

 

 

 

  • Плюс 1

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

Event

Событие - объект который генерируется и рассылается по какому-либо действию пользователя (например клик мыши, нажатие клавиши и т.п.). Для распространения события используется метод dispatch

События объявляются в scope.

(event valChanged)

События в unbound могут генерироваться:

  • Из core C++ части. Например в блоке slider генерируется event valueChanged когда изменяется его value.
    (dispatch valChanged on='valueChanged' dir=1)

     

  • Из Scaleform части. Например событие клика по display object'у
    (block
        (style
            (width = 100)
            (height = 100)
            (backgroundColor = 0xff00ff00)
        )
        (bind alpha "0.5" init=false on='click')
    )

Различия использования подписки на события с помощью on и event

Биндинг-конструкции могут подписываться на события двумя способами:

  • Передача имени события в аргумент on.
    (bind eventArgs "$event" init=false on='eventScope')
  • Передача вложенного объекта event
    (trace "$event" init=false (event "eventScope"))

Событие может быть сгенерировано:

  • в scalefom, например событие мыши click или событие клавиатуры keyDown
  • в core c++ части unbound, например блок slider генерирует событие sliderPositionChanged когда изменятся положение ползунка
  • в верстке, т.е. событие объявлено в scope элемента и генерируется в его определении.
    (def element TestView() layout = true entrance=true
        (scope
            (event eventScope)
        )
      
        (element Button
            (dispatch eventScope on='click')
        )
    )

    Но по сути своей это не генерация события, а превращение из события scalefom/core c++ (в данном примере 'click')  в событие скоупа (в данном пример eventScope)

Рассмотрим различия между этими двумя способами

Если событие генерируется в scaleform или в core c++ unbound, то подписаться можно только с использованием аргумента on. 

Скрытый текст

(def element TestView() layout = true entrance=true
    (scope
        (event eventScope)
    )
  
    (block
        (style
            (width = 100px)
            (height = 100px)
            (backgroundColor = 0xffff0000)
        )
        (bind alpha "0.5" init=false on='click')
    )
  
    (video original_widht=1920 original_height=1080
        (style
            (width = 320px)
            (height = 180px)
        )
  
        (source = "R.videos.Logo_All" )
        (trace "$event" init=false on='metaDataChanged')
    )
)

 

 

Если событие объявлено в scop'e элемента, то существует 2 случая подписки в зависимости от расположения подписки. 

  • Подписку в scope можно осуществлять и через on и через event
    Скрытый текст
    
    (def element TestView() layout = true entrance=true
        (scope
            (event eventScope)
      
            (var eventArgs:dict = null)
            (bind eventArgs "$event" init=false (event "eventScope"))
            # (bind eventArgs "$event" init=false on='eventScope')
        )
      
        (element Button
            (scope
                (label = 'dispatch scope event')
            )
            (dispatch eventScope on='click')
        )
      
        (trace "eventArgs" init=false)
    )

     

  • Подписку вне скоупа можно осуществлять только через event
    Скрытый текст
    
    (def element TestView() layout = true entrance=true
        (scope
            (event eventScope)
        )
      
        (element Button
            (scope
                (label = 'dispatch scope event')
            )
            (dispatch eventScope on='click')
        )
      
        (trace "$event" init=false (event "eventScope"))
    )

     

 

Таким образом подписываться через аргумент on можно на те события которые генерирует target-объект

Отдельно рассмотрим случай подписки на события scop'а при создании элемента.

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

События 'evBtnLeftClickEvent' и 'evBtnRightClickEvent' генерируются в определении element'а Button.

Если использовать конструкцию event, то события должны быть объявлены в родительском скоупе

Скрытый текст

(def element TestView() layout = true entrance=true
    (scope
        (event eventScope)
    )
  
    (element Button
        (scope
            (label = 'default text')
            (bind label "'keyCode: ' + $event.keyCode" init=false (event "eventScope"))
        )
    )
  
    (dispatch eventScope on='stageKeyUp')
)

 

 

 

  • Плюс 2

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

Функции для вычисляемых выражений

Список глобальных функцией представлен в таблице.

Функция Описание Пример
abs(number)
Математический модуль  
ceil(number)
Наибольшее цело число от данного  
clamp(v, lo, hi)

Ограничивает значение v в пределах lo и hi

if (v < lo) return lo;

if (hi < v) return hi;

return v;

(var test:number = "clamp(smth, 0, 10)")
countdownFormat(numberSeconds, numberOfDigits, isShowMinutes)

Форматирует переданное число секунд в формат min:secongs

Если минут 0, отображается 00

"countdownFormat(125, 0, true)"
floor(number)
Наименьшее цело число от данного  
formatFloatingPoint(number, numberOfDigits=1)

Округление дробной части до numberOfDigits знака после запятой. По умолчанию numberOfDigits = 1

Не учитывает региональные настройки формата.

Нет разделителя разрядов.

"formatFloatingPoint(1.193454334123)" # result 1.2

"formatFloatingPoint(0.423456, 3)" # result 0.423

formatSeparator(number)

Группировка целочисленной части на группы по 3 цифры, разделенных пробелами. Округление дробной части до второго знака.

Не учитывает региональные настройки формата.

Целые числа отображаются без дробной части, а дробные - с 2 знаками после запятой.

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

Примеры:

999.595 => "999.60"

999.59 => "999.59"

1000.5 => "1 000.50"

999 => "999"

1 999.0 => "1 999"

999.001 => "999.00"

formatString(stringId, [<dict_values>, ..., <dict_values>], named)

Объединяет логику функций TextFormat и htmlTextStyle. Позволяет форматировать каждую передаваемую подстроку отдельно.

1-й аргумент - форматируемая строка. Может получаться посредством R-менеджера.

2-й аргумент - массив словарей форматирования.

3-й аргумент - флаг использования именованных ключей. По-умолчанию аргумент named == false (используются позиционные аргументы).

-----------------------

<dict_values> - представляет собой словарь форматирования, содержащий пару ключ-значение.

Обязательные ключи:

1) value - значением является форматируемая подстрока.

Type : str, number, bool.

bool значения преобразуются в строку (true - 'true', false - 'false') - в таком виде и подставляются.

Необязательные ключи:

2) name - ключ, в соответствии к которому будет подставляться значение в строку. Если аргумент (3-й аргумент) named==true, то ключ становится обязательным!

Если используются неименованные агрументы, ключ "name" в словаре форматирования игнорируется - в форматированной строке ключи использовать запрещено (будет ошибка парсинга) !

Type : str.

3) style - название стиля, который будет применен к форматируемой подстроке.

Type : str.

4) align - может принимать значения: left, right, bottom, top, center, middle. Иначе будет сгенерирована ошибка IllegalArgNameError (см. unbound.log). По-умолчанию - 'left'.

Type : str.

5) hardSpace - флаг, указывающий что все пробелы в подстроке будут заменены на непрерывные. По-умолчанию - false.

Type : bool.

Используем именованные аргументы

(htmlText = "formatString(
'*** {key1} of the {key2} ',
[ {value:'dummy text', name:'key1', style:'HighlightTextStyle', align:'middle'},

{value:'printing', name:'key2', style:'AlertTextStyle'}],

true)")

-----------------------

Используем позиционные аргументы

(htmlText = "formatString(
'*** {} of the {} ',
[ {value:'dummy text', style:'HighlightTextStyle'},

{value:'printing', style:'AlertTextStyle'}])")

-----------------------

ОШИБКА!

(htmlText = "formatString(
'*** {key1} *** ',
[ {value:'dummy text', name:'key1', style:'HighlightTextStyle'}])")

gradToRad(gradNumber)
Перевод из градусов в радианы  
hardSpace('some text with spaces')
Функция заменяет обычные пробелы на неразрывные (аналог '&nbsp')

(text = "hardSpace('dummy insert text with nbsp.')")

htmlTextStyle(text, styleName, align='left')

Функция применяет html-форматирование к тексту на основе существующего стиля. Принимает два параметра:

  • text - форматируемый текст
  • styleName - имя стиля (из стиля используются три параметра: 
    fontFamily, fontSize, textColor)
  • align - выравнивание текста, по умолчанию 'left'. Допустимые значения такие же как для TextField в as3: leftrightjustify и center.
(tf
    (htmlText = "htmlTextStyle('Animation Block', 'GoldTextStyle') + htmlTextStyle('!!!', 'MainTextStyle', 'center')")
)
max(x, y)
Максимальное из двух чисел. return x > y ? x : y (var test: number  = "max(smth, smth2)")
min(x, y)
Минимальное из двух чисел. return x < y ? x : y (var test:number = "min(smth, smth2)")
playSound(resourceSoundId)
Проигрывает звуковой файл (exec "playSound(R.sounds.gui.minimize)" on='evBtnLeftClickEvent')
pow(basis, exponent)
Возведение числа basis в степень exponent  
radToGrad(radNumber)
Перевод из радиан в градусы  
randFloat(min=0.0, max=1.0)
Генерирует случайное целое число с плавающей точкой в диапазоне [min, max]. По умолчанию min=0.0, max=1.0

(text = "'rand float = ' + randFloat(10, 20)")

(text = "'rand float = ' + randFloat()")

randInt(min, max)
Генерирует случайное целое число в диапазоне [min, max] (text = "'rand integer = ' + randInt(10, 20)")
Rect(x, y, width, height)
Создает экземпляр класса Rectangle (scale9grid = "Rect(4, 4, 152, 16)")
round(number)
Математическое округление до целого числа "round(0.423456)" # 0
subst(str, array_values, dict_values)
Подстановка переданных аргументов в плейсхолдеры

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

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

tan(radNumber)
Тангенс угла в радианас  
TextFormat(stringId, dict_values)
или
TextFormat(stringId, 'value1', 'value2', ...)
Подстановка переданных аргументов в локализационную строку.  
toLower(str)
Преобразует прописные символы в строчные  
toUpper(str)
Преобразует строчные символы в прописные  
tr
Локализация строк по IDS  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • Плюс 2

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

Layout

Unbound имеет layout system, которая занимается позиционированием блоков, расположенных в одном контейнере по определенным параметрам. Для включения layout system используется атрибут layout=true|false определения element'a. Описание element c атрибутом layout=true эквивалентно def layout

Параметры layout'а описываются в style.

Пример:

Скрытый текст

(def element TestView() layout = true
    (block
        (style
            (width = 1024px)
            (height = 768px)
            (backgroundColor = 0xff191711)
            (marginLeft = 200px)
        )
        (tf
            (style
                (textColor = 0xffffffff)
            )
            (text = 'SandBox')
        )
    )
)
  
#or
  
(def layout TestView()
    (block
        (style
            (width = 1024px)
            (height = 768px)
            (backgroundColor = 0xff191711)
            (marginLeft = 200px)
        )
        (tf
            (style
                (textColor = 0xffffffff)
            )
            (text = 'SandBox')
        )
    )
)

 

 

Позиционирование блоков

Layout system'a позиционирует блоки согласно значения свойства position. Position может принимать следующие значения:

  • flow - layout system'а позиционирует вложенные блоки один за другим (положение одного блока зависит от положения предыдущего), по умолчанию position="flow"

  • absolute - layout system'а исключает блок из потока (списка позиционирования).

Для позиционирования блоков относительно друг друга при position="flow" можно использовать следующие свойства стиля:

  • paddingLeft / paddingRight / paddingTop / paddingBottom - отступ слева / справа / сверху/ снизу для вложенных блоков.
    Скрытый текст
    
    (def element TestView() layout = true
        (style
            (width = 1024px) # ширина элемента
            (height = 768px) # высота элемента
            (backgroundColor = 0xff191711)
            (paddingLeft = 20px) # отступ слева в пикселях для вложенного блока
            (paddingTop = 10%)   # отступ сверху в процентах от текущей высоты для вложенного блока
        )
      
      
        # Координаты вложенного блока равны x:20px (paddingLeft родительского блока), y: 768 * 0.1 = 76.8 (10% от высоты родительского блока)  
        (block
            (style
                (width = 100px)
                (height = 100px)
                (backgroundColor = 0xff0000ff)
            )
        )
          
        # Координаты вложенного блока равны x:20px (paddingLeft родительского блока), y: 76.8 (y-координата блока выше) + 100 (высота блока выше) = 176.8
        (block
            (style
                (width = 100px)
                (height = 100px)
                (backgroundColor = 0xffff0000)
            )
        )
    )

     

    Если нужно задать сразу все 4 параметра можно использовать следующую конструкцию:

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

     

  • marginLeft / marginRight / marginTop / marginBottom - отступ слева / справа / сверху/ снизу для текущего блока

    Скрытый текст
    
    (def element TestView() layout = true
        (style
            (width = 1024px)
            (height = 768px)
            (backgroundColor = 0xff191711)
        )
          
        # Координаты блока x:10px (marginLeft текущего блока), y:20px (marginTop текущего блока)
        (block
            (style
                (width = 100px)
                (height = 100px)
                (backgroundColor = 0xff0000ff)
                (marginLeft = 10px)
                (marginTop = 20px)
            )
        )
      
        # Координаты блока x:20px (marginLeft текущего блока), y:20px (y-координата блока выше) + 100px (высота блока выше) + 5px (margineTop текущего блока) = 125px
        (block
            (style
                (width = 50px)
                (height = 50px)
                (backgroundColor = 0xffff0000)
                (marginLeft = 20px)
                (marginTop = 5px)
            )
        )
    )

     

    Если нужно задать сразу все 4 параметра можно использовать следующую конструкцию

    (style
        (margin = [5, 10, 15, 20]) # [marginLeft, marginTop, marginright, bottom]
    )
    Примечание:
    Главное отличие margins от paddings в том, что параметры paddings устанавливаются в родительском блоке и влияют на позиционирование вложенных блоков. Margins же влияют на позиционирование текущего блока.

     

  • gap, hgap, vgap - отступ по горизонтали / вертикали между каждым вложенным блоком

    Скрытый текст
    
    (def element TestView() layout = true
        (style
            (width = 1024px)
            (height = 768px)
            (backgroundColor = 0xff191711)
            (vgap = 20px)
            (paddingTop = 40px)
            (paddingLeft = 40px)
        )
          
        # Координаты блока x:40px (paddingLeft родительского блока), y: 40px (paddingTop родительского блока)
        (block
            (style
                (width = 20px)
                (height = 20px)
                (backgroundColor = 0xffff0000)
            )
        )
      
        # Координаты блока x:40px (paddingLeft родительского блока), y: 40px (y-координата блока выше) + 20px (высота блока выше) + 20px (vgap) = 80px
        (block
            (style
                (width = 30px)
                (height = 30px)
                (backgroundColor = 0xff00ff00)
            )
        )
          
        # Координаты блока x:40px (paddingLeft родительского блока), y: 80px (y-координата блока выше) + 30px (высота блока выше) + 20px (vgap) = 130px
        (block
            (style
                (width = 40px)
                (height = 40px)
                (backgroundColor = 0xff0000ff)
            )
        )
    )

     

    Если отступ между блоками по горизонтали и вертикали одинаковый, то можно использовать параметр gap.

    Пример использования:

    Скрытый текст
    
    (def element TestView() layout = true
        (style
            (width = 1024px)
            (height = 768px)
            (backgroundColor = 0xff191711)
            (paddingLeft = 100px)
            (paddingTop = 100px)
        )
          
        # Блок в котором layout system располагает элементы по горизонтали друг за другом, если следующий блок не влазит, то блок переносится на ниже.
        # Ширина блока 80px, суммарная ширина всех вложенных блоков 20px + 30px + 40px = 90px, поэтому третий блок будет расположен ниже остальных.
        # Параметр gap=10px поэтому, расстояние между блоками по вертикали и горизонтали будет 10px
        (htile
            (style
                (width = 80px)
                (gap = 10px)
                (backgroundColor = 0x44ffffff)
            )
            (block
                (style
                    (width = 20px)
                    (height = 20px)
                    (backgroundColor = 0xffff0000)
                )
            )
      
            (block
                (style
                    (width = 30px)
                    (height = 30px)
                    (backgroundColor = 0xff00ff00)
                )
            )
      
            (block
                (style
                    (width = 40px)
                    (height = 40px)
                    (backgroundColor = 0xff0000ff)
                )
            )
        )
    )

     

    В результате получим:

    unbound2_htile_gap.PNG

  • align - позиционирование всех вложенных блоков как единого блока. Может принимать следующие значения: 
    left  - выравнивание контента по левому краю
    right - выравнивание контента по правому краю
    top - выравнивание контента по верхнему краю 
    bottom - выравнивание контента по нижнему краю
    center - выравнивание контента по центру по горизонтали
    middle - выравнивание контента по центру по вертикали

    Пример выравнивания блока по левому краю:

    Скрытый текст
    
    (def element TestView() layout = true
        (style
            (width = 1024px)
            (height = 768px)
            (backgroundColor = 0xff191711)
            (align = "left")
        )
          
        (block
            (style
                (width = 20px)
                (height = 20px)
                (backgroundColor = 0xffff0000)
            )
        )
    )

     

    Можно использовать несколько значений одновременно разделенных "|". Например если требуется выровнять по центру и по вертикали и по горизонтали. Пример:

    (align = "center | middle")

     

Для позиционирования блоков при position="absolute" вышеперечисленные свойства не применяются, нужно использовать следющие:

  • left / right / top / bottom - отступ от левого / правого / верхнего / нижнего края контейнера, в котором находится блок

Пример использования:

Скрытый текст

(def element TestView() layout = true
    (style
        (width = 400px)
        (height = 200px)
        (backgroundColor = 0xff191711)
        (align = "center|middle")
    )
  
    (block
        (style
            (width = 20px)
            (height = 20px)
            (backgroundColor = 0xffff0000)
        )
    )
  
    # Удаляем из списка позиционирования layout system. Блок имеет координаты x:40px (параметр left текущего блока), y:50px (параметр top текущего блока)
    (block
        (style
            (position = "absolute")
            (width = 30px)
            (height = 30px)
            (left = 40px)
            (top = 50px)
            (backgroundColor = 0xff00ff00)
        )
    )
  
    (block
        (style
            (width = 40px)
            (height = 40px)
            (backgroundColor = 0xff0000ff)
        )
    )
)

 

 

В результате получим

unbound2_position_absolute.PNG

 

  • hcenter  / vcenter- отступ от центра по горизонтали / по вертикали
    Скрытый текст
    
    (def element TestView() layout = true
        (style
            (width = 400px)
            (height = 200px)
            (backgroundColor = 0xff191711)
        )
      
        (block
            (style
                (width = 20px)
                (height = 20px)
                (backgroundColor = 0xffff0000)
            )
        )
      
        # Удаляем из списка позиционирования layout system. Отступы от центра по вертикали и горизонтали равны 0, поэтому блок расположен точно по центру
        (block
            (style
                (position = "absolute")
                (width = 30px)
                (height = 30px)
                (hcenter = 0px)
                (vcenter = 0px)
                (backgroundColor = 0xff00ff00)
            )
        )
      
        (block
            (style
                (width = 40px)
                (height = 40px)
                (backgroundColor = 0xff0000ff)
            )
        )
    )

     

     

В результате получим

unbound2_position_absolute_center.png

 

Примечание:

Размер блока у которого параметр position="flow" равны размерам вложенных в него блоков.

Размер блока у которого параметр position="absolute" по умолчанию равны 0.

 

  • Плюс 2

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

Macro

Макрос - именованный параметризированный фрагмент верстки, который место вызова заменяет на содержимое макроса на этапе разбора. Позволяет переиспользовать фрагмент верстки несколько раз.

Пример использования:

Скрытый текст

# Определение макроса
(def macro trace(expr:expression)
    (block
        (style
            (backgroundColor = "0x50000000")
        )
        (tf
        (class $TextHUD16Bold)
            (style (textColor = "0xFFFF00FF"))
            (autoSize='left')
            (bind text "expr")
        )
    )
)

 

 

После того как макрос был определен, его можно вызывать в любом месте.

Пример:

# Вызов макроса
(macro trace expr="variable")

Этот механизм используется для автогенерации scope, который будет связан с python.

Пример:

Скрытый текст

# This file was generated using wgpygen from the templates/macro.unbound.jinja2 template.
# Please, don't edit this file manually.
(def macro ButtonModel()
    (scope
        (event onClicked)
  
        (var rawLabel:str = '')
        (var label:str = '')
        (var isEnabled:bool = true)
        (var icon:gfx = null)
        (var iconAfterText:bool = true)
    )
)

 

 

  • Плюс 1

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

Scope

Scope - это хранилище данных, находящихся в распоряжении элемента. Не наследуетcя от родительских элементов. В разметке используется строгая типизация - все используемые переменные и их типы, а также events должны быть объявлены до момента использования в вычисляемом выражении, либо переданы из внешнего scope при вызове элемента.

Может содержать

  • переменные (var)
  • константы (const)
  • объявление события
  • вызов bind
  • dispatch события
  • $Animation контроллер для анимации переменных в scope

 

Пример:

Скрытый текст

# Объявление элемента с аргументом level
(def element LevelView(textStyle:str = 'MainTextStyle') layout=true
    (scope
        # Объявление эвента
        (event __onParamChange)
  
  
        # Объявление переменных со значением по умолчанию и dispatch события '__onParamChange' на изменение значения.
        # Событие 'evChanged' - внутреннее события core unbound.
        (var radius:number = 13              
            (dispatch __onParamChange on='evChanged')
        )
        (var color:number = 0xfff2ad
            (dispatch __onParamChange on='evChanged')
        )
    )
  
  
    (style
        (bind width "radius * 2")
        (bind height "radius * 2")
        (align = "center|middle")
    )
    (.graphics
        (bindcall clear init=true (event "__onParamChange"))
        (bindcall lineStyle 1 "color" 0.3 init=true watch=false (event "__onParamChange"))
        (bindcall drawCircle "radius" "radius" "radius" init=true watch=false (event "__onParamChange"))
        (bindcall endFill init=true (event "__onParamChange"))
    )
    (scope
        # Объявление переменной со значением по умолчанию
        (var level:number = 0)
    )
    (tf
        (name = 'level')
        (class "textStyle")
        (bind text "level" init=false)
        (selectable = false)
    )
)

 

 

Scope можно описывать в разных частях элемента (пример: переменная level). В итоге при исполнении все части объединятся в один scope. Отображение содержимого scope:

(trace "$scope")

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

Примечание:

Переменные, переданные в элемент как аргументы определения, НЕ попадают в scope. В примере выше переменной textStyle нет в scope.

 

При создании экземпляра элемента можно изменять его значения переменных scope:

Создание экземляра элемента

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

Переменные scope при вызове элемента можно синхронизировать с переменными родительского scope

Создание экземляра элемента

(scope
    (var parentLevel:number = 15)
)
  
(element LevelView 'PromoTitleTextStyle'
    (scope
        (bind level "parentLevel")
    )
)

 

 

  • Плюс 2

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

toplevel def

(def) или Definition

Конструкция (def object Name)  позволяет объявить глобальный объект, доступный для вызова из всей области в рамках рабочих каталогов.

 

Внимание!

Имя объекта должно быть уникальным. Не важно в одном или разных файлах эти объявления сделаны. Иначе будет ошибка и только первый объект будет создан

(def element TestView())
  
(def element TestView())
  
  
ERROR: Duplicate element definition: 'TestView'

 

  • Плюс 1

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

toplevel exec

Top level функция exec позволяет выполнить любое выражение, опционально можно задавать событие, по которому будет выполнено выражение.

Синтаксис:

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

Примеры:

1. Выполняет проигрывание звука по клику:

(exec "playSound(R.sounds.gui.yes1)" on='click')
Скрытый текст

(element ButtonTest myElement)
  
  
(def element ButtonTest(name:str ='') layout=true
    (name = "name")
    (exec "playSound(R.sounds.gui.yes1)" on='click')   
    (block
        (.graphics
            (beginFill "0xFF0000" "1")
            (drawCircle 40 40 10)
            (endFill)
        )
    )
)

 

 

2. Выполняет проигрывание звука по событию скоупа:

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

Пример использования

Скрытый текст

(element ButtonTest myElement)
  
  
(def element ButtonTest(name:str ='') layout=true
    (name = "name")
    (scope
        (event evBtnLeftClickEvent)
    )
    (dispatch evBtnLeftClickEvent on='click' dir=1 (enabled="$event.buttonIdx == 0"))
    (exec "playSound(R.sounds.gui.yes1)" (event "evBtnLeftClickEvent"))  
    (block
        (.graphics
            (beginFill "0xFF0000" "1")
            (drawCircle 40 40 10)
            (endFill)
        )
    )
)

 

 

 

  • Плюс 1

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

Top-Level Trace

Выводит в лог сообщение. Имеет все возможности top level метода:

  • привязку к эвентам (как эвентам скоупа, так и эвентам, имена которых передаются через параметр *on*)
  • привязку к изменениям параметров (если в качестве параметра передано выражение)

Примеры использования:

(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)
# ниже пример трейса по условию, например если мы расположили его в каком то общем макросе и надо отсечь "левые" срабатывания
(trace  'Some message' init=false  on='eventName'
    (bind enabled "name == 'anyName'")
)

 

  • Плюс 2

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

UI Widgets

Symbol

Добавление на сцену MovieClip по его имени (linkage). Используется в объявлениях элемента с параметром layout=false. Т.е. создается display object без layout system'ы.

Пример использования:

(def element TestView() layout=false
    (symbol 'linkageName')
)

Sprite

Добавление на сцену экземпляра класса Sprite. Используется в объявлениях элемента с параметром layout=false.

Пример использования:

Скрытый текст

(def element TestView() layout=false
    (sprite
        (y = 140)
        (tf
            (text = 'hello unbound')
        )
    )
)

 

 

MC

Добавление на сцену экземпляра класса MovieClip по его имени (linkage). Используется в объявлениях элемента с параметром layout=true. (т.е. поддержка layout system и styles)

Пример использования:

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

TextField

Добавление на сцену экземпляра класса TextField. Поддерживается во всех элементов с layout=true|false. Для задания текста используется свойство text или htmlText. Если будет задан text и htmlText, применится только последнее действие.

Пример использования:

Скрытый текст

(tf
    (style
        (width = 400)
        (height = 100)
        (textColor = 0xff0000)
        (fontFamily = $TitleFont)
        (fontSize = 56)
        (textAlign = "right")
        (leading = 10)
        (letterSpacing = 10)
    )
    (multiline = true)
    (autoSize = 'left')
    (selectable = false)
    (text = 'Hello unbound!!!')
)

 

 

Для случая когда текст слишком большой и не влазит в текстовое поле, существует свойство elideMode. Если elideMode=true, то текст обрезается под размер всего блока и последние 3 символа заменяются на ".". При каждом обрезании текста генерируются event textElideStatus в аргументе передается статус: обрезан текст или нет.

Скрытый текст

(tf
    (class HeroTitleTextStyle)
    (style
        (width = 200)
        (elideMode = true)
    )
    (text = 'Any long text')
    (trace "$event.value" init=false on='textElideStatus')
)

 

 

Element

Block

Добавляет на сцену контейнер-экземпляр класса Sprite, Все вложенные блоки будут добавляться в этот контейнер и позиционироваться друг за другом взависимости от значения свойства стиля flow.

Для block существуют aliases:

  • block - вертикальный блок
  • hblock - горизонтальный блок
  • vtile - вертикальный tile блок
  • htile - горизонтальный tile блок
  • reverse - вертикальный блок с обратным порядком элементов в блоке
  • hreverse - горизонтальный блок с обратным порядком элементов в блоке

 

Пример:

Скрытый текст

(hblock
    (block
        (style
            (height = 100px)
            (width = 100px)
            (backgroundColor = "0xFF00FF00")
        )
    )
  
    (block
        (style
            (height = 100px)
            (width = 100px)
            (marginLeft = 10px)
            (backgroundColor = "0xFFFFFFFF")
        )
    )
)

 

 

Image

Добавляет на сцену экземпляр класса Bitmap.

  • передать путь до файла (для этого используется R-class - ресурсный менеджер)
  • передать текстуру из атласа - экземпляр класса BitmapData
  • url адрес до изображения в сети

 

Если блоку не заданы размеры в style, то после загрузки изображения размеры блока станут такими же как размеры изображения.

(image
    (style
        (width = 200)
        (height = 200)
    )
    (source= "R.atlases.battleAtlas.AllyTeamBaseEntry_green_0.data") #load BitmapData from the atlas
    # (source = 'https://pp.userapi.com/c831209/v831209703/69c96/F8zeMFRzkQc.jpg') #load image by URL
    # (source = "R.images.gui.maps.icons.bootcamp.rewards.bcExp") #load image by path
)

 

List

Компонент List создает в себе n-ое количество рендереров, где renderer_name - имя элемента из верстки, list_width и list_height - ширина и высота, которые задают область листа. Если контент будет больше, то тогда должны появиться scrollBar-ы, заданные ниже в horizontal_slider и vertical_slider. Если list_width и list_height заданы равными 0, то область отрисовки рендереров не должна ограничиваться.

Если horizontal_slider и vertical_slider не заданы, то при положительных list_width и list_height контент может усекаться до размеров листа и его можно скролировать с клавиатуры кнопками со стрелочками.

Если для List задана ViewModel, то будет создаваться количество рендереров, равное количеству данных во ViewModel.

 

Практический совет

Используйте компонент List только в случае если размер содержимого контейнера большего самого контейнера и необходимо иметь возможность прокручивать содержимое контейнера. В противном случае используйте Group или Repeat controller.

 

Пример:

Скрытый текст

(def element List(
    name:str,
    renderer_name:str = '',
    list_width:number = 100%,
    list_height:number = 100%,
    count_renderers:number = 0,
    container_flow:number = "Flow.VERTICAL",
    hscroll_bar:str = 'ScrollBarH',
    vscroll_bar:str = 'ScrollBarV',
    vscroll_policy:str = 'auto',
    hscroll_policy:str = 'auto'
) layout=true
    (scope
        (var listCountRenderers:number = "count_renderers")
        (var listRendererName:str = "renderer_name")
        (var containerFlow:number = "container_flow")
        (var listVscrollPolicy:str = "vscroll_policy")
        (var listHscrollPolicy:str = "hscroll_policy")
        (var containerWidth:number = -1)
        (var containerHeight:number = -1)
        (var containerGap:number = 0)
        (var containerVGap:number = 0)
        (var containerHGap:number = 0)
        (var containerMargin:number = 0)
        (var containerMarginLeft:number = 0)
        (var containerMarginRight:number = 0)
        (var containerMarginTop:number = 0)
        (var containerMarginBottom:number = 0)
        (var containerAlign:number = 0)
    )
    (style
        (width = "list_width")
        (height = "list_height")
    )
    (list
        (style
            (width = "list_width")
            (height = "list_height")
        )
        (bind renderer "listRendererName")
        (bind countRenderers "listCountRenderers")
        (container
            (style
                (bind flow "containerFlow")
                (bind width "containerWidth" init=false enabled="containerWidth >= 0")
                (bind height "containerHeight" init=false enabled="containerHeight >= 0")
                (bind gap "containerGap" init=false)
                (bind vgap "containerVGap" init=false)
                (bind hgap "containerHGap" init=false)
                (bind margin "containerMargin" init=false)
                (bind marginLeft "containerMarginLeft" init=false)
                (bind marginRight "containerMarginRight" init=false)
                (bind marginTop "containerMarginTop" init=false)
                (bind marginBottom "containerMarginBottom" init=false)
                (bind align "containerAlign" init=false)
            )
        )
        (horizontalSlider
            (element "hscroll_bar" "name + 'HorScrlBar'")
        )
        (verticalSlider
            (element "vscroll_bar" "name + 'VertScrlBar'")
        )
        (bind vscrollPolicy "listVscrollPolicy")
        (bind hscrollPolicy "listHscrollPolicy")
    )
)

 

 

  • count_renderers - количество создаваемых рендереров (может быть равно 0).

  • list_width и list_height - размеры листа

  • container_flow - направление листа, по умолчанию вертикальное
  • hscroll_bar и vscroll_bar - имена компонентов для скроллбаров

  • vscroll_policy и hscroll_policy задают политику пояления скроллбаров. 'on' - всегда показывать скроллбары, 'off' - никогда не показывать, 'auto' - показывать, если требуется. По умолчанию равно 'auto'

 

Пример использования из верстки:

Внимание!

Имя листа должно передаваться в виде неименованного аргумента!

(element List 'listTest' renderer_name='TestRenderer' count_renderers="count"
    (scope
        (containerWidth = 594)
        (containerGap = 1)
        (containerFlow = "Flow.TILE_HORIZONTAL")
        (bind listCountRenderers "$event.newVal" init=false (event "rCountChanged"))
    )
)

 

ViewHolder

Функциональность блока view_holder позволяет добавлять контент в элементы, в заранее определенные placeholders. Это необходимо, если контент отличается для контрола, но есть общие элементы, которые могут быть определены заранее. Контент может быть добавлен:

  • в верстке
  • из python

Количество блоков view_holder может быть больше одного.

Передача контента из верстки

Для начала необходилмо определить view_holder и idName (строка - уникальный id в рамках елемента, в котором определяется). Тут же можно задать стиль этого блока.

(view_holder 'content'
    (style
        (width = 100%)
        (height = 100%)
        (position = "absolute")
    )
)

Для добавления контента в этот placeholder нужно добавить блок view_holder_content с тем idName, с которым он был определен.

(view_holder_content 'idName'
    # content here
)

Контент будет помещен на месте placeholder.

 

Рассмотрим пример, в котором нужно разместить контент между фоном и обводкой. Для этого между блоками с backgкound и stroke размещаем view_holder c именем 'content':

Скрытый текст

(def element AbstractComponent() layout=true
    (block
        (name = 'background')
        (style
            (width = 100%)
            (height = 100%)
            (backgroundColor = 0x44ff0000)
        )
    )
  
  
    (view_holder 'content'
        (style
            (width = 100%)
            (height = 100%)
            (position = "absolute")
        )
    )
  
    (image
        (name = 'stroke')
        (style
            (position = "absolute")
            (width = 100%)
            (height = 100%)
            (scale9grid = "Rect(5,5,150,14)")
        )
        (source = "R.atlases.components.stroke.data")
    )
)

 

 

После этого создадим экземпляр этого элемента и добавим контетв в view_holder:

Скрытый текст

(def element TestView() layout = true
    (style
        (width = 1024px)
        (height = 768px)
        (backgroundColor = 0xff191711)
        (paddingLeft = 50px)
        (paddingTop = 50px)
    )
  
  
    (element AbstractComponent
        (name = 'abstractComponent')
        (style
            (width = 200)
            (height = 200)
        )
  
        (view_holder_content 'content'
            (name = 'contentContainter')
            (block
                (name = 'tfContainer')
                (style
                    (width = 100%)
                    (height = 100%)
                    (align = "center|middle")
                )
                (tf
                    (name = 'textField')
                    (class $MissionStatusAvailableTextStyle)
                    (text = 'Content')
                )
            )
        )
    )
)

 

 

На месте view_holder_content будет создан Sprite и в него добавлены все вложенные блоки. Ниже представлен display list приведенного примера.

unbound2_view_holder_display_list.PNG

 

Передача контента из python

Для передачи контента из python, view_holder имеет свойство content.

Объявляем view_holder в верстке:

(view_holder
    (style
        (position = "absolute")
        (left = 20)
        (top = 0)
    )
    (bind content "entranceWidget")
)

 

Объявляем переменную в ViewModel в yaml, для передачи контента из модели:

properties:
  - name: entranceWidget
    type: view

Во view в python в переменную entraceWidget нужно передать требуемую view:

with self.viewModel.transaction() as model:
    view = EntrancePointWidget()
    model.setEntranceWidget(view)

Внимание! Не стоит злоупотреблять данной возможностью, передача view из python операция тяжелая.

Input

Компонент для ввода текстовых и цифровых данных с клавиатуры.

Имеет 2 реализации: InputSimple и InputNumeric.

Имеет ряд переменных скоупа для настройки:

  • isEnabled (true/false)- состояние доступности компонента;
  • alignText  ('left'/'right'/'center') - привязка текста к сторонам тектового поля (значения аналогичны полу из AS3);
  • enteredText - текущее значение введенного текста;
  • displayAsPassword  (true/false) - отображать ли текст как '*';
  • maxChars (number) - максимально разрешенное число символов;
  • editable (true/false) - разрешено ли редактирование;
  • restrict (regexp) - разрешенные для ввода символы;
  • minimum (number) - минимальное значение;
  • maximum (number) - максимальное значение.

 

Может рассылать несколько своих событий:

  • evTextChanged (args={'text':str}) - событие на изменение текста;
  • evInputComplete (args={'text':str}) - событие на нажатие клавиши Enter после ввода текста.

unbound2_image2018-5-25_15-15-44.png

 

Значения параметров по умолчанию указаны в примере ниже:

Скрытый текст

(element InputSimple
    (scope
        # defaul values
        (isEnabled = true)
        (alignText = 'left')
        (enteredText = '')
        (displayAsPassword = false)
        (maxChars = 20)
        (editable = true)
        (restrict = '0-9 . \-')
    )
    # evTextChanged
    # evInputComplete
)
 
(element InputNumeric
    (scope
        # defaul values
        (isEnabled = true)
        (alignText = 'left')
        (enteredText = '')
        (minumum = -100000000)
        (maximum = 100000000)
        (displayAsPassword = false)
        (maxChars = 20)
        (editable = true)
        (restrict = '0-9 . \-')
    )
    # evTextChanged
    # evInputComplete
)

 

 

Slider

Компонент, предоставляющий собой обычный Slider.

Имеет 2 реализации: SliderNormalH (горизонтальный) и  SliderNormalV (вертикальный).

Имеет ряд переменных скоупа для настройки:

  • value (number) - текущее значение слайдера в единицах (не процент);
  • minimum (number) - минимальное значение;
  • maximum (number) - максимальное значение.
  • singleStep  (number) - величина, на которую переместится ползунок и значение слайдер при перемещении ползунка мышью или клавиатурой;
  • tracking (true/false) - следует ли изменять реальное значение (value) слайдера при перемещении ползунка мышью, до отпускания кнопки мыши;
  • enabled (true/false) - доступен ли слайдер.

 

Может рассылать несколько своих событий:

  • sliderPositionChanged (args={'newValue':number}) - изменилась позиция ползунка слайдера (если включен флаг tracking, то отсылается одновременно с valChanged).

  • valChanged (args={'newValue':number}) - изменилось значение слайдера.

  • rangeChanged (args={'min':number, max:number })  - изменились границы величины слайдера.

unbound2_image2018-5-25_14-55-20.png

 

Значения параметров по умолчанию указаны в примере ниже:

Скрытый текст

(element SliderNormalH 'name'
    (scope
        # defaul values
        (value = 0)
        (singleStep = 1)
        (minimum = 0)
        (maximum = 0)
        (enabled = false)
        (tracking = false)
    )
    # valChanged
    # rangeChanged
    # sliderPositionChanged
)

 

 

Progress

Компонент прогрессбара.

Может принимать любой вид в зависимости от мувиклипа, который был передан.

В данный момент реализовано 2 горизонтальных прогрессбара и один радиальный.

ProgressBarSmall - горизонтальный размером в 60px

ProgressBarNormal - горизонтальный размером в 163px

unbound2_image2018-5-25_14-55-32.png

 

ProgressBarRound - радиальный

unbound2_image2018-5-25_14-55-46.png

 

Пример:

Скрытый текст

# Для уже готовых типов
(element ProgressBarSmall  
    (scope
        # defaul values
        (value = 0.0)
    )
)
  
# Для использования кастомного прогресса с мувиклипом
(progress 'FWProgressSmallMC'
    (value = 0)
)

 

 

DebugBlock

Компонент debug block представляет собой специальный элемент который позволяет отлаживать свойвства стиля выбранного элемента, можно как просматривать так и редактировать.

Пример использования:

(debug_block
    (bindcall startDrag on='mouseDown')
    (bindcall stopDrag on='mouseUp')
)

 

Group

Компонент Group создает в себе n-ое количество рендереров, где renderer_name - имя элемента из верстки, list_width и list_height - ширина и высота которые задают область группы. Если list_width и list_height заданы равными 0, то область отрисовки рендереров не ограничивается. 

- `name` - имя элемента, отвечает за биндинг с соотвествующей viewModel
- `binder` - необходим для механизма биндинга, по этому ключу биндер понимает какой элемент надо искать.

Если для Group задана viewModel, то на данный момент, будет создаваться количество рендереров равное количеству данных во viewModel.

Скрытый текст

(def element Group(
    name:str,
    binder:str = 'group',
    renderer_name:str = '',
    list_width:number = 100%,
    list_height:number = 100%,
    count_renderers:number = 0,
    container_flow:number = "Flow.VERTICAL"
) layout=true
    (scope
        (var listRendererName:str = "renderer_name")
        (var listAllowDeselect:bool = false)
        (var containerFlow:number = "container_flow")
        (var containerWidth:number = -1)
        (var containerHeight:number = -1)
        (var containerGap:number = 0)
        (var containerVGap:number = 0)
        (var containerHGap:number = 0)
        (var containerMargin:number = 0)
        (var containerMarginLeft:number = 0)
        (var containerMarginRight:number = 0)
        (var containerMarginTop:number = 0)
        (var containerMarginBottom:number = 0)
        (var containerAlign:number = 0)
        (var scopeData:array = [])
    )
    (style
        (width = "list_width")
        (height = "list_height")
    )
    (group
        (style
            (width = "list_width")
            (height = "list_height")
        )
        (bind renderer "listRendererName")
        (bind data "scopeData" init=false)
        (container
            (style
                (bind flow "containerFlow")
                (bind width "containerWidth" init=false enabled="containerWidth >= 0")
                (bind height "containerHeight" init=false enabled="containerHeight >= 0")
                (bind gap "containerGap" init=false)
                (bind vgap "containerVGap" init=false)
                (bind hgap "containerHGap" init=false)
                (bind margin "containerMargin" init=false)
                (bind marginLeft "containerMarginLeft" init=false)
                (bind marginRight "containerMarginRight" init=false)
                (bind marginTop "containerMarginTop" init=false)
                (bind marginBottom "containerMarginBottom" init=false)
                (bind align "containerAlign" init=false)
            )
        )
    )
)

 

 

Для рендереров в скоупе можно задать (event onSelectChange), который будет срабатывать при клике на текущем элементе(с $event==true) и на элементе, который был выбран перед этим ($event==false). При установленном listAllowDeselect = false, если элемент уже выбран, на нем не будет срабатывать onSelectChange, если listAllowDeselect = true, то при каждом клике будет диспатчится данное событие, чередуя значения в $event (true|false).

  • list_width и list_height - размеры листа

  • container_flow - направление листа, по умолчанию вертикальное

 

Пример использования из верстки:

(element Group name='listTest2' 'group' renderer_name='TestRenderer' count_renderers="group_count"
    (scope
        (bind containerWidth "594px")
        (bind containerGap "1")
        (bind containerFlow "Flow.TILE_HORIZONTAL")
    )
)

ScrollArea

Описание

Компонент scrollArea представляет собой контейнер блок, который агрегирует отображение некого контента внутри ограниченной области, заданной через блок style внутри себя (scrollArea). Если размер компонента превышает размер scrollArea, то мы увидим лишь часть контента и можем перемещать оставшуюся.

Syntax inside scrollArea
  • (content ...) - устанавливает контент, обязательный;
  • (vscrollPolicy = 'on' | 'off' | 'auto') or (hscrollPolicy = 'on' | 'off' | 'auto') - устанавливает правила отображения скролл баров или слайдеров. Если не выставлено, то аналогично (vscrollPolicy = 'auto');
  • (horizontalSlider ...) or (verticalSlider ...) - устанавливает слайдер или скролл бар существующий элемент для использования внутри scrollArea.
Interface for user input
  • ← → ↑ ↓ keys на клавиатуре, используются для перемещения контента в соответствующем направлении.
  • Home / End keys, используются для перемещения контента к началу / к концу.
  • PageUp/PageDown keys, используются для перемещения контента в соответствующем направлении на одну страницу (размером с видимую область).
  • mouse scroll wheel, используются для перемещения контента в вертикальном направлении.
  • mouse scroll wheel + shift key, используются для перемещения контента в горизонтальном направлении.

 

Примечание!

(horizontalSlider ...) или (verticalSlider ...) блоки должны быть реализованны на базе классов ObjectMainType::SCROLL_BAR или ObjectMainType::SLIDER. Если их не задать, то создается абстрактный слайдер, у которого нет графического представления, но он все равно позволяет перемещать контент по hot keys. На текущий момент мы используем element ScrollBarH / ScrollBarV в качестве готовых скролл баров.

Скрытый текст

(scrollArea 'scrollArea'
    (style (width = 100%) (height = 100%))
    (content
        (element UIKitContent 'contentBlock')
    )
    (horizontalSlider
        (element ScrollBarH 'sliderH')
    )
    (verticalSlider
        (element ScrollBarV 'sliderV')
    )
    (vscrollPolicy = 'on')
    (hscrollPolicy = 'off')
)

 

 

ScrollBar

Компонент скроллбар используется внутри SrollArea, но его можно использовать как отдельный компонент.

Имеет 2 реализации: ScrollBarH и ScrollBarV.

Имеет ряд переменных скоупа для настройки:

  • value (number) - текущее значение;
  • minimum (number) - минимальное значение;
  • maximum (number) - максимальное значение.
  • singleStep (number) - шаг, на который изменится значение скролла при перетягивании мыши;
  • pageStep (number)- шаг, на который изменится значение скролла при нажатии на pageUp/Down;
  • tracking (true/false) - следует ли изменять реальное значение (value) скроллбара при перемещении ползунка мышью, до отпускания кнопки мыши;
  • isEnabled (true/false) - доступен ли слайдер.

 

Может рассылать несколько своих событий:

  • sliderPositionChanged (args={'newValue':number}) - изменилась позиция ползунка слайдера (если включен флаг tracking, то отсылается одновременно с valChanged).
  • valChanged (args={'newValue':number}) - изменилось значение слайдера.
Скрытый текст

# Горизонтальный скроллбар
(element ScrollBarH 'name'
    # defaul values
    (scope
        (value = 0)
        (minimum = 0)
        (maximum = 100)
        (singleStep = 1)
        (pageStep = 1)
        (tracking = false)
        (isEnabled = true)
  
        # sliderPositionChanged
        # valChanged
    )
)
  
# Вертикальый скроллбар
(element ScrollBarV 'name')

 

 

Button

Существует уже ряд готовых кнопок в ui kit по аналогии с реализацией на scaleform:

  • ButtonPrimary
  • ButtonPrimaryBig
  • ButtonSecondary
  • ButtonOrangeBig
  • ButtonPrimaryWithContent
  • ButtonSecondaryWithContent
  • CloseBtn

 

Все кнопки обязателько содержат два макроса:
(macro ButtonBasic) и (macro ComponentStateBase "statesDict"), где statesDict это описание состояний кнопки, например для BTN_PRIMARY statesDict выглядит следующим образом:

Скрытый текст

(def constant BTN_PRIMARY {
        up : {font: $ButtonTextStyle, image: {source: 'bitmap:button_normal_bg', scale9: "Rect(15, 7, 135, 5)"} },
        hover : {font: $ButtonTextStyle, image: {source: 'bitmap:button_normal_bg_hover', scale9: "Rect(15, 7, 135, 5)"} },
        down : {font: $ButtonTextStyle, image: {source: 'bitmap:button_normal_bg_press', scale9: "Rect(15, 7, 135, 5)"} },
        disabled : {font: $ButtonTextDisabledStyle, image: {source: 'bitmap:button_normal_bg_disabled', scale9: "Rect(15, 7, 135, 5)"} },
        disabledOverlay : {style: 'BtnNormalDisabledOverlayStyle'},
        focusOverlay : {image: {source: 'bitmap:button_normal_focus', scale9: "Rect(15, 7, 135, 5)"}},
        upSelected : {font: $ButtonTextStyle, image: {source: 'bitmap:button_normal_bg_press', scale9: "Rect(15, 7, 135, 5)"} },
        hoverSelected : {font: $ButtonTextStyle, image: {source: 'bitmap:button_normal_bg_press', scale9: "Rect(15, 7, 135, 5)"} },
        downSelected : {font: $ButtonTextStyle, image: {source: 'bitmap:button_normal_bg_press', scale9: "Rect(15, 7, 135, 5)"} }
    }
)

 

 

ButtonBasic - позволяет задавать базовые параметры для кнопки.
ComponentStateBase - отвечает за стилизацию кнопки и добавление ей интерактивности: обработка событий мыши, установка фокуса

Используя эти два макроса можно получить доступ к следующим свойствам:

Скрытый текст

(var rawLabel:str = '')
(var label:str = '')
(var isEnabled:bool = true)
(var icon:gfx = null)
(var iconAfterText:bool = true)
(var selectable:bool = false)
(var selected:bool = false)
(var allowDeselect:bool = false) - используется для toggle
(var isFocused:bool = false)
(var backgroundAlpha:number = 1)

 

 

Из верстки также доступны следующие события:

Скрытый текст

(event evBtnUpEvent)
(event evBtnDownEvent)
(event evBtnOverEvent)
(event evBtnOutEvent)
(event evBtnDisbledEvent)
(event evBtnEnabledEvent)
(event evBtnLeftClickEvent)
(event evBtnRightClickEvent)
(event evBtnFocusChange)
(event evBtnSelectedChange)
(event evStageMouseUp)
(event evStateChanged)

 

 

Пример использования:

Скрытый текст

(element ButtonPrimary 'BtnRight'
    (style
        (marginLeft = 10px)
    )
    (scope
        (label = 'Next')
        (dispatch onForwardBtnClicked args="{}" on='evBtnLeftClickEvent')
  
        # Sound test with as3 click event - pass raw path to sound
        (exec "playSound('gui/coins')" on='evBtnLeftClickEvent')
    )
)

 

 

SlotButton

Кнопка-слот, в которой может находиться любой контент.

Для того, чтобы сделать слот со своим содержимым, нужно в элемент вставить макрос (macro SlotButtonBasic) и добавить контент в нужные слои (view_holder).

Есть три view_holder:

  • background - слой фона, который анимируется при смене состояний кнопки (находится на самом нижнем слое);
  • content - слой с основным содержимым кнопки (поверх него рисуется слой с анимированным затенением при смене состояний кнопки);
  • overlay - самый верхний слой, на случай, если нужно иметь какую-то графику, которая должна перекрывать всю кнопку или выходить за ее пределы.

 

Обычно достаточно вставить только слой content.

Скрытый текст

(def element CustomSlotButton(name:str = '') layout = true
    (macro SlotButtonBasic)
  
    (view_holder_content 'background'
        # Any content for background
    )
    (view_holder_content 'content'
        # Any content
    )
    (view_holder_content 'overlay'
        # Any content for overlay
    )
)

 

 

Video

Блок video добавляет на сцену экземпляр класса flash.media.Video. Для инициализации требуется передать оригинальный размер видеофайла.

Список свойств:

  • source - путь к файлу.
  • volume - уровень громкости от 0 до 100.
  • seek - приблизительное время (в секундах), к которому надо перейти в видеофайле.
  • autoPlay - автоматическое проигрывание видео после установки source.

 

Список событий:

  • metaDataChanged - событие изменение metaData файла (в аргумент события приходит dict со всеми параметрами видео файла: duration. width и т.д.)
  • playbackStarted - событие старта воспроизведение видео
  • playbackStopped - событие остановки воспроизведение видео
  • playbackPaused - событие постановки видео на паузу
  • seekStarted - событие старта поиска кадра
  • seekCompleted - событие окончания поиска кадра
Скрытый текст

(video original_widht=1920 original_height=1080
    (name = 'player')
    (style
        (width = 320px)
        (height = 180px)
    )
    (source = "R.videos.Logo_All")
    (volume = 0.5)
    (seek = 100)
)

 

 

 

 

  • Плюс 1

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

Styles and CSS

Общее описание

Блоки поддерживают настройку параметров layout'а через style. Каждый блок обладает своим набором параметров стиля.

Настройка стиля у блока tf:

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

Настройка стиля у блока block:

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

Настройка стиля у блока mc:

Скрытый текст

(mc 'Window_BG'
    (style
        (width=100)
        (height=50)
        (filters
            (dropShadow
                (distance = 1)
                (angle = 90)
                (color = 0xffffff)
                (alpha = 1.0)
                (blurX = 12)
                (blurY = 12)
                (strength = 2)
                (quality = 2)
                (inner = false)
                (knockout = false)
                (hideObject  = false)
            )
        )
    )
)

 

 

Стили можно описывать в отдельном определении. И передавать как параметр в блок в свойство class.

(def element TestView() layout = true
    (block
        (class BlockStyle)
    )
)
  
(def css BlockStyle()
    (backgroundColor = 0xffff0000)
    (width = 100px)
    (height = 100px)
)

Значение для свойства class может быть вычислено в выражении, таким образом можно стилизовать блоки в зависимости от условий.

Скрытый текст

(def element TestView() layout = true
    (scope
        (event onClick)
        (var switcher:bool = false)
        (bind switcher "!switcher" init=false watch=false (event "onClick"))
    )
      
    (block
        (bind class "switcher ? 'BlockStyle_1' : 'BlockStyle_2'")
    )
  
    (element ButtonPrimary
        (scope
            (label = 'change style')
        )
        (dispatch onClick on='click')
    )
)
  
(def css BlockStyle_1()
    (backgroundColor = 0xffff0000)
    (width = 100px)
    (height = 100px)
)
  
(def css BlockStyle_2()
    (backgroundColor = 0xff00ff00)
    (width = 120px)
    (height = 130px)
    (alpha = 0.5)
)

 

 

Если к блоку будет применено несколько стилей с одинаковыми свойствами, то последующие будут перезаписывать значения предыдущих. Важен порядок применения.

(block
    (class BlockStyle_1)
    (class BlockStyle_2)
)

Примечание:

Но если изменить свойство стиля непосредственно в style и передать css как параметр с тем же свойством. То порядок расположения применения стилей не важен. Блок style выполнится последним.

Скрытый текст

(def element TestView() layout = true
    (block
        (style
            (backgroundColor = 0xffff0000)
            (width = 100px)
            (height = 100px)
        )
        (class BlockStyle_2)
    )
)
  
(def css BlockStyle_2()
    (backgroundColor = 0xff00ff00)
    (width = 120px)
    (height = 130px)
    (alpha = 0.5)
)

 

 

Таблица стилей

Виды блоков:

  • базовые блоки: tf, mc, image, text_input.
  • контейнер-блоки (наследуются от базового блока): block (и все алиасы hblock, vtile, gtile, reverse, hreverse), list, view_holder, slider, scroll_bar, progress. scrollArea.

 

свойство аналог css кто поддерживает свойство принимаемые значения пример возможных значений
width width все блоки number, %, px 10px; 10%
minWidth min-width все блоки number, %, px 100px; 50%
maxWidth max-width все блоки number, %, px 100px; 50%
height height все блоки number, %, px 10px; 10%
minHeight min-height все блоки number, %, px 100px; 50%
maxHeight max-height все блоки number, %, px 100px; 50%
position position все блоки absolute, flow absolute
left left все блоки number, %, px 10px; 10%
right right все блоки number, %, px 10px; 10%
top top все блоки number, %, px 10px; 10%
bottom bottom все блоки number, %, px 10px; 10%
center смещение от центра все блоки number, %, px -170
hcenter смещение от центра по горизонтали все блоки number, %, px 10px; 10%
vcenter смещение от центра по вертикали все блоки number, %, px 10px; 10%
marginLeft margin-left все блоки number, %, px 10px
marginRight margin-right все блоки number, %, px 10px
marginTop margin-top все блоки number, %, px 10px
marginBottom margin-bottom все блоки number, %, px 10px
margin margin все блоки number, %, px 10px
paddingLeft padding-left контейнер-блоки number, %, px 10px
paddingRight padding-right контейнер-блоки number, %, px 10px
paddingTop padding-top контейнер-блоки number, %, px 10px
paddingBottom padding-bottom контейнер-блоки number, %, px 10px
padding padding контейнер-блоки number, %, px 10px
backgroundColor background-color контейнер-блоки 0xARGB 0x1000ff00
backgroundImage background-image контейнер-блоки str, 'url: {url}', 'bitmap: {linkage}', 'symbol: {linkage}' backgroundImage = 'url:..\icons\ico.png'
backgroundSize

background-size

background-repeat

контейнер-блоки fill; crop; cover; repeat; autosize backgroundSize = "crop"
flow flex-direction контейнер-блоки Flow.HORISONTAL, Flow.VERTICAL, Flow.TILE_HORIZONTAL, Flow.TILE_VERTICAL flow = "Flow.HORISONTAL"
align

justify-content

align-items

контейнер-блоки left, right, bottom, top, center, middle align = "middle|right"
alpha opacity все блоки number от 0 до 1 1; 0; 0.4
fontSize font-size tf number 36
leading междустрочный интервал 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() все блоки number

изменяет scale блока по горизонтали

1.25

ubScaleY transform: scaleY() все блоки number

изменяет scale блока по вертикали

1.25

scale9grid масштабирование, при котором контент разбивается на 9 частей и каждая из них масштабируется по-своему image Rect(x, y, width, height) - параметры выставляются от оригинального размера картинки Rect(50,50,50,50)
filters filter все блоки dropShadow, glow, blur
(filters
    (dropShadow
        (angle = 0)
        (blurX = 10)
        (blurY = 10)
        (strength = 1.5)
        (distance = 0)
        (color = 0xff0000)
    )
)

 

blendMode background-blend-mode все блоки, кроме image и tf

str

строковые значения Flash API

blendMode = 'add'
gap grid-gap контейнер-блоки number, px

В общем случае

(style
    (gap = 100px)
)

Для вертикального лэйаута:

(style
    (vgap = 50px)
)

Что будет соответствовать

(style
    (gap = 50px)
)

Для горизонтального лэйаута:

(style
    (hgap = 50px)
)

Что будет соответствовать

(style
    (gap = 50px)
)

Для тайл лэйаута:

(style
    (vgap = 50px)
    (hgap = 50px)
)

Что будет соответствовать

(style
    (gap = 50px)

)

zindex z-index все блоки

number

ZIndex.FOREGROUND - назначить максимальный zindex (поместить наверх)

ZIndex.BACKGROUND - назначить zindex=0 (поместить вниз)

zindex = 10

zindex = "ZIndex.BACKGROUND"

rotation поворот блока если его позиция absolute все блоки с позицией absolute number (значения угла поворота в градусах)
(style
    (rotation = 30)
)
pivotX

нулевая точка по X

используется для поворота, скейла, абсолютной позиции

все блоки с позицией absolute number, %, px
(style
    (pivotX = 50%)
)
или 
(style
    (pivotX = 100px)
)
pivotY

нулевая точка по Y

используется для поворота, скейла, абсолютной позиции

все блоки с позицией absolute number, %, px
(style
    (pivotY = 10%)
)
или 
(style
    (pivotY = 20px)
)
scaleX

масштаб по оси X

может быть отрицательным, применяется к блоку и его чайлдам

все блоки double

(style

    (scaleX = 1.2)
)
scaleY

масштаб по оси Y

может быть отрицательным, применяется к блоку и его чайлдам

все блоки double

(style

    (scaleY = -1.0)
)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • Плюс 1

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Разработчик
33 публикации
572 боя

CSS Tips and Tricks

Использование объекта стилей (аналог css-классов)

Создание объекта стилей:

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

Вызов:

(block
    (class SomeStyleObject)
)

Пример реализации псевдокласса hover

Скрытый текст

(def element SomeElement() layout=true
    (scope
        # Объявляем ивенты:
        (event evBtnOverEvent)
        (event evBtnOutEvent)
        ...
    )
    ...
    # Привязываем ивенты:
    (dispatch evBtnOverEvent args="{}" on=rollOver)
    (dispatch evBtnOutEvent args="{}" on=rollOut)
    ...
    (block
        (style
            # Привязываем изменение стилей к ивентам:
            (bind alpha 1 (event "evBtnOverEvent"))
            (bind alpha 0.7 (event "evBtnOutEvent"))
        )
    )
)

 

 

Срабарывание ховера при наведении на конкретную область, а не на весь блок

Если нужно задать определенныую область в качестве hitArea, то добавьте block с name='hoverArea' и передайте имя блока в свойство hitArea элемента parentElement с помощью объекта $target.

Скрытый текст

(def element parentElement() layout=true
    (style
        (width = 100px)
        (height = 100px)
        ...
    )
  
  
    (block
        (name = 'hoverArea')
        (style
            (width = 50px)
            (height = 50px)
            ...
        )
    )
    (hitArea = "$target.hoverArea")
    # Ховер на родительском блоке отработает только при наведении на 'hoverArea'
)

 

 

Изменение стилей в зависимости от ширины/высоты экрана (аналог медаизапросов)

Скрытый текст

(def element SomeElement() layout=true
    (scope
        # Записываем значение высоты экрана в переменную
        (var viewSizeHeight:number = "viewSize.height")
        (bind viewSizeHeight "viewSize.height" (event "viewResized"))
    )
    (style
        ...
        # Делаем проверку и задаём нужное значение у свойства
        (bind bottom 0 (bind enabled "viewSizeHeight < 800"))
        (bind bottom 27px (bind enabled "viewSizeHeight > 800"))
    )
)

 

 

 

  • Плюс 1

Рассказать о публикации


Ссылка на публикацию
Поделиться на других сайтах
Гость
Эта тема закрыта для публикации новых ответов.

×