Visão geral
O modelo de execução de um NCLua é orientado a eventos. Como será visto adiante, um script Lua para TV Digital nada mais é que um tratador de eventos.
Isso quer dizer que existem eventos associados aos usos do controle remoto, transmissões pelo canal de interatividade, sincronismos em documentos NCL, etc, e é através deles que toda dinâmica de um NCLua se faz.
Durante a inicialização do NCLua, antes de se tornar orientado a eventos, o script deve registrar pelo menos uma função de tratamento de eventos. A partir de então, qualquer ação tomada pela aplicação é somente em resposta a um evento recebido por essa função tratadora. A função event.register efetua o registro de tratadores.
--- example.lua ---
... -- código de inicialização
function handler (evt)
... -- código do tratador
end
event.register(handler) -- registro do tratador
Durante sua execução, um NCLua também pode enviar eventos para se comunicar com o ambiente. Assim é possível que o NCLua envie dados pelo canal de interatividade, sinalize que sua execução terminou, etc. A função event.post efetua o envio de eventos.
Um NCLua também pode usufruir desse mecanismo de eventos internamente, através
de eventos da classe user.
Tais eventos, portanto, são postados e recebidos pelo próprio NCLua.
Classes de Eventos
Um evento é descrito por uma tabela Lua simples, onde o campo class é
obrigatório e identifica a classe do evento.
Por exemplo, um evento para indicar que a tecla '0' foi pressionada é
descrito pela seguinte tabela:
{ class='key', type='press', key='0' }
As seguintes classes de eventos são definidas:
Classe 'ncl':
Um NCLua se comunica com o documento no qual está inserido através desta classe de eventos.
Em um documento NCL, relacionamentos entre nós de mídia são descritos através de elos que relacionam condições e ações. Um NCLua interage com o documento apenas através de elos em que seu objeto de mídia está associado. Portanto, não é possível que um NCLua interfira diretamente no comportamento de outras mídias presentes no documento.
Em elos que acionam o NCLua, a condição satisfeita faz com que o NCLua receba um evento descrevendo a ação a ser tomada.
Por exemplo, no elo abaixo:
<link xconnector="onBeginStart">
<bind role="onBegin" component="videoId"/>
<bind role="start" component="luaId"/>
</link>
Quando videoId iniciar, o NCLua receberá o evento:
{ class='ncl', type='presentation', action='start' }
Esse evento será recebido pela função registrada durante a inicialização do script.
Em elos cuja condição depende de um NCLua, a ação será disparada quando o NCLua sinalizar o evento que case com a condição esperada.
Por exemplo, no elo abaixo:
<link xconnector="onBeginStart">
<bind role="onEnd" component="luaId"/>
<bind role="start" component="imageId"/>
</link>
Assim que o NCLua postar o evento:
event.post { class='ncl', type='presentation', action='stop' }
O elo irá exibir a imagem que participa do elo.
Há dois tipos de eventos da classe ncl suportados pelos NCLua: apresentação e
atribuição.
Eventos de seleção são tratados pela classe de eventos 'key'.
O tipo é identificado no campo type do evento e pode assumir, portanto,
apenas os valores 'presentation' ou 'attribution'.
Tipo 'presentation':
Eventos de apresentação controlam a exibição do nó NCLua.
Eventos de apresentação podem estar associados a áreas (âncoras de
apresentação)
específicas ou ao nó como um todo.
Áreas são identificadas pelo campo area e equivalem ao nó inteiro
quando ausentes (i.e. iguais a nil).
O campo action indica a ação a ser tomada ou sinalizada pelo NCLua,
dependendo se este está recebendo ou gerando o evento.
Em suma, um evento de apresentação possui a seguinte estrutura:
class:'ncl'type:'presentation'area:[string]Nome da âncora (label) associada ao evento.action:[string]Pode assumir os seguintes valores:'start','stop','abort','pause'e'resume'.
Tipo 'attribution':
Eventos de atribuição controlam as propriedades do nó NCLua.
O campo property do evento contém o nome da propriedade sendo afetada.
Os eventos de atribuição são bastante similares aos de apresentação, uma vez
que são regidos pelo mesmo modelo de máquina de estados.
Assim, o campo action pode assumir os mesmos valores encontrados nos eventos
de apresentação.
O campo value é preenchido com o valor a ser atribuido e é sempre uma
string, uma vez que vem de um atributo XML.
A ação de start em um evento de atribuição corresponde ao role="set" em um
elo NCL.
As propriedades dos NCLua não possuem nenhuma relação direta com as variáveis declaradas no script. Um NCLua que pretende alterar o valor de uma propriedade deve postar um evento para tal fim. As propriedades dos nós são controladas pelo próprio documento NCL.
Por exemplo:
event.post {
class = 'ncl',
type = 'attribution',
property = 'myProp',
action = 'start',
value = '10',
}
Em suma, um evento de atribuição possui a seguinte estrutura:
class:'ncl'type:'attribution'property:[string]Nome da propriedade (name) associada ao evento.action:[string]Pode assumir os seguintes valores:'start','stop','abort','pause'e'resume'.value:[string]Novo valor a ser atribuído à propriedade.
Classe 'key':
Esta classe de eventos é utilizada para representar o uso do controle remoto pelo usuário. Para esta classe não faz sentido que o NCLua gere eventos, uma vez que o controle remoto é um dispositivo unicamente de entrada.
Exemplo:
{ class='key', type='press', key='0' }
Eventos da classe key possuem a seguinte estrutura:
class:'key'type:[string]Pode assumir'press'ou'release'.key:[string]Valor da tecla em questão.
Classe 'user':
Aplicações podem extender sua funcionalidade criando seus próprios eventos através desta classe.
Nenhum campo da tabela representando o evento está definido (além,
claro, do campo class).
Como eventos desta classe são para uso interno, não faz sentido a postagem de
seus eventos com o destino igual a 'out'.
Exemplo:
{ class='user', data='mydata' }
Classe 'tcp':
O uso do canal de interatividade é realizado por meio desta classe de eventos.
De modo a enviar e receber dados, uma conexão deve ser pré estabelecida, postando um evento como a seguir.
event.post {
class = 'tcp',
type = 'connect',
host = <addr>,
port = <number>,
[timeout = <number>,]
}
O resultado da conexão é retornado em um tratador de eventos pré registrado. O evento retornado possui a seguinte estrutura:
evt = {
class = 'tcp',
type = 'connect',
host = <addr>,
port = <number>,
connection = identifier,
error = <err_msg>,
}
Os campos error e connection são mutuamente exclusivos.
Quando houver um problema na conexão, uma mensagem de erro é retornada no campo
error.
Quando a conexão sucede, um identificador único para a conexão é retornado no
campo connection.
Um NCLua envia dados através do canal de retorno postando eventos na seguinte forma:
event.post {
class = 'tcp',
type = 'data',
connection = <identifier>,
value = <string>,
[timeout = number,]
}
De maneira similar, um NCLua recebe dados do canal de retorno em eventos da seguinte forma:
evt = {
class = 'tcp',
type = 'data',
value = <string>,
connection = <identifier>,
error = <err_msg>,
}
Novamente, os campos error e connection são mutuamente exclusivos.
Quando houver um problema na conexão, uma mensagem de erro é retornada no campo
error.
Quando a conexão sucede, um identificador único para a conexão é retornado no
campo connection.
Para fechar uma conexão, o seguinte evento deve ser postado:
event.post {
class = 'tcp',
type = 'disconnect',
connection = <identifier>,
}
Funções
event.register ([pos,] f)
Registra a função passada como um tratador de eventos, isto é, sempre que ocorrer um evento, `f` será chamada. |
event.unregister (f)
Desregistra a função passada como um tratador de eventos, isto é, novos eventos não serão mais passados a `f`. |
event.post ([dst,] evt)
Posta o evento passado. |
event.timer (time, f)
Cria um timer que expira após `time` (em milisegundos) e então chama a função `f`. |
event.uptime ()
Retorna o número de milisegundos decorridos desde o início da aplicação. |
Recebe:
pos: [number] Posição de inserção da função de tratamento.f: [function] Função de tratamento.
A assinatura de f deve ser:
function f (evt)
-- returns boolean
end
Onde evt é o evento que, ao ocorrer, ativa a função.
A função pode retornar true, para sinalizar que o evento foi tratado e,
portanto, não deve ser enviado a outros tratadores.
É recomendado que a função (definida pela aplicação) retorne rapidamente, já que enquanto ela estiver executando, nenhum outro evento é processado.
O formatador NCL garante que as funções recebem os eventos na ordem em que
foram registradas. Enquanto os tratadores não retornam o valor true, o
formatador notifica o próximo tratador registrado.
O parâmetro pos é opcional e, caso não seja passado, a função registrada será
a última a receber eventos.
Desregistra a função passada como um tratador de eventos, isto é, novos
eventos não serão mais passados a f.
Recebe:
f: [function] Função de tratamento.
Posta o evento passado.
Recebe:
dst: [string] Destinatário do evento. Pode assumir os valores'in'(envio para a própria aplicação) e'out'(envio para o formatador NCL). Caso seja omitido, assume o valor'out'.evt: [table] Evento a ser postado.
Retorna:
sent: [boolean] Se o evento foi enviado com sucesso.err_msg: [string] Mensagem em caso de erro.
Cria um timer que expira após time (em milisegundos) e então chama a
função f.
Recebe:
time: [number] Tempo em milisegundos.f: [function] Função de retomada.
Retorna:
unreg: [function] Função que, quando chamada, cancela o timer.
A assinatura de f é simples, sem parâmetros:
function f () end
O valor de 0 milisegundos é válido. Neste caso, f é chamada assim que
possível (nunca imediatamente, dentro de um tratador de eventos).
Assim como tratadores de eventos, a função f deve retornar rapidamente,
pois enquanto ela é executada nenhum evento é tratado.
Retorna o número de milisegundos decorridos desde o início da aplicação.