カスタムレイヤーを作成する場合、カスタムコントロールプリセットをレイヤーに含めることもできます。これは、レイヤーにプッシュボタンがあり、ライブ時のレイヤーの動作を制御する場合に便利です。
データ構造
以下のデータ構造は、コンポジション内の `tvOut_ControlRepresentations` 構造体出力キーの下に存在する必要があるサンプル出力です:
{
"tvOut_ControlRepresentations": [
{
"title": "Compact Cut's",
"buttons": [
{
"actions": [
{
"layerId": "03627C25-CC8A-474F-A738-C4DEB3353FA4",
"variantId": "F6F52194-06DE-462E-983A-8D505C533A69",
"type": "signal",
"signalKey": "tvGroup_Control__Cut_1_TypeSignal",
"signalName": "Cut 1"
}
],
"liveState": {
"layerId": "03627C25-CC8A-474F-A738-C4DEB3353FA4",
"variantId": "F6F52194-06DE-462E-983A-8D505C533A69",
"dynamicSourceId": "tvIn_VideoSourceAImage"
},
"sourcePreview": {
"layerId": "03627C25-CC8A-474F-A738-C4DEB3353FA4",
"variantId": "F6F52194-06DE-462E-983A-8D505C533A69",
"dynamicSourceId": "tvIn_VideoSourceAImage"
},
"color": "#BBBBBB",
"width": 1,
"height": 1,
"x": 0,
"y": 0,
"icon": "facetime-video",
"dynamicText": {
"template": "{{inputputValues.tvIn_VideoSourceAName}}",
"layerId": "03627C25-CC8A-474F-A738-C4DEB3353FA4",
"variantId": "F6F52194-06DE-462E-983A-8D505C533A69"
}
}
]
}
]
}
プリセットには "タイトル "と "ボタン "の配列がありますが、1つのボタンでもかまいません。
キー `layerId` と `variantId` には、コンポジション入力キー `tvIn_LayerIdentifier` と `tvIn_RuntimeIdentifier` の文字列データを動的に入力する必要がある。
リモコンプリセットの使用 エーピーアイ クオーツコンポーザーで
mimoLiveのビルドインレイヤーは ルア スクリプトを使用して、このデータ構造を動的に生成します。Quartz Composer はデータ構造の生成をサポートしていないからです。そのため ルア スクリプトには複雑な関数 addButton() があります。通常、この関数を使うだけで、変更する必要はありません。そのため、独自のレイヤーのために新しいリモコンのデフォルト設定を構築するのは非常に簡単です。
例えば、これは ルア スクリプトを使用して、ストップウォッチ層のリモートコントロールを生成します。コードの15行目から29行目までを変更するだけで、このコードを採用できることに注意してください。
inLayerIdentifier = QC_STRING
inVariantIdentifier = QC_STRING
outControlRepresentations = QC_STRUCT
main = function()
controlRepresentations = {}
-- first representation
controlRepresenation = {}
-- {
controlRepresenation["Title"] = "Stop Watch"
buttons = {}
-- {
-- addButton(buttonsTable, buttonTitle, subTitle, positionX, positionY, width, height, color, icon, actionTarget, liveStateSource, previewSource)
-- first row
addButton(buttons, "{{outputValues.tvOut_TimeString}}", "", 0, 0, 2, 1, "#333333", "", "", "", "")
addButton(buttons, "Live", "{\{name\}}", 2, 0, 1, 1, "#333333", "", "toggleLive", "layerVariant", "")
-- second row
addButton(buttons, "Start", "", 0, 1, 1, 1, "#33cc33", "play", "tvGroup_Control__Start_TypeSignal", "", "")
addButton(buttons, "Stop", "", 1, 1, 1, 1, "#cc3333", "pause", "tvGroup_Control__Stop_TypeSignal", "", "")
addButton(buttons, "Reset", "", 2, 1, 1, 1, "#cccc33", "stop", "tvGroup_Control__Reset_TypeSignal", "", "")
-- }
controlRepresenation["buttons"] = buttons
-- }
table.insert(controlRepresentations , controlRepresenation)
outControlRepresentations = controlRepresentations
end
function addButton(buttonsTable, buttonTitle, buttonSubTitle, positionX, positionY, width, height, color, icon, actionTarget, liveStateSource, previewSource)
local button = {}
-- {
if #buttonTitle > 0 then
if string.find(buttonTitle, "{{") then
-- dynamic titel
local dynamicText = {}
-- {
dynamicText["layerId"] = inLayerIdentifier
dynamicText["variantId"] = inVariantIdentifier
dynamicText["template"] = buttonTitle
-- }
button["dynamicText"] = dynamicText
else
-- static title
button["text"] = buttonTitle
end -- if dynamic
end -- if buttonTitle
if #buttonSubTitle > 0 then
if string.find(buttonSubTitle, "{{") then
-- dynamic titel
local dynamicSubText = {}
-- {
dynamicSubText["layerId"] = inLayerIdentifier
dynamicSubText["variantId"] = inVariantIdentifier
dynamicSubText["template"] = buttonSubTitle
-- }
button["dynamicSubText"] = dynamicSubText
else
-- static title
button["subtext"] = buttonSubTitle
end -- if dynamic
end -- if buttonSubTitle
button["x"] = positionX
button["y"] = positionY
button["width"] = width
button["height"] = height
if #color > 0 then
button["color"] = color
end -- if
if #actionTarget > 0 then
local actions = {}
-- {
local action = {}
-- {
action["layerId"] = inLayerIdentifier
action["variantId"] = inVariantIdentifier
if string.ends(actionTarget, "_TypeSignal") then
action["type"] = "signal"
action["signalKey"] = actionTarget
action["signalName"] = buttonTitle
elseif actionTarget == "toggleLive" then
action["type"] = "toggleLive"
else
action["type"] = "toggleSwitch"
action["toggleSwitchKey"] = actionTarget
action["toggleSwitchName"] = buttonTitle
end -- if
-- }
table.insert(actions , action)
-- }
button["actions"] = actions
end -- if actionTarget
if #liveStateSource > 0 then
local liveState = {}
-- {
liveState["layerId"] = inLayerIdentifier
liveState["variantId"] = inVariantIdentifier
if string.starts(liveStateSource,"tvIn_VideoSource") then
-- get the live state from a dynamic video source
liveState["dynamicSourceId"] = liveStateSource
elseif liveStateSource == "layerVariant" then
-- nor more information needed
else
liveState["propertyPath"] = liveStateSource end -- if
-- }
button["liveState"] = liveState
end -- if liveState Source
if #previewSource > 0 then
local sourcePreview = {}
-- {
sourcePreview["layerId"] = inLayerIdentifier
sourcePreview["variantId"] = inVariantIdentifier
sourcePreview["dynamicSourceId"] = previewSource
-- }
button["sourcePreview"] = sourcePreview
end -- if
if #icon > 0 then
-- See bottom of documentation page for list of avaiable icon names
button["icon"] = icon
end -- if
-- }
table.insert(buttonsTable, button)
end -- func
function string.starts(String,Start)
return string.sub(String,1,string.len(Start))==Start
end
function string.ends(String,End)
return End=='' or string.sub(String,-string.len(End))==End
end
1TP7トンポジショニング
複数のボタンを使う場合、ボタンのレイアウトは手動で制御しなければなりません。つまり、ボタンは "x "と "y "属性を使ってグリッド上に配置されます。"x "と "y "属性は、"width "と "height "属性と同様に、グリッド・セルの倍数で与えられます。位置は、ボタン・グループがドラッグされた左上のグリッド・セルからの相対位置です。
1TP7トンアクション
Buttonsは複数のアクションを持つことも、単一のアクションを持つことも、まったく持たないこともできます。
"textInput "および "numericInput "アクションは、リモコンでの一貫したユーザーエクスペリエンスが保証されないため、単独であるべきであることに注意してください。
行動目標
アクションターゲットはmimoLiveドキュメント内の要素です。それらは階層的に扱われる:
ドキュメントID」は常に実行時に描画されるので、プリセットに存在する必要はない。
- もし "layerId "も "variantId "も与えられなければ、アクションはドキュメント自身に対して引き起こされます。
- もし "layerId "が与えられると、アクションは指定されたレイヤーでトリガーされます。
- もし "layerId" と "variantId" が与えられると、アクションは指定された variant で起動されます。この場合だけ、"toggleSwitchKey" や "signalKey" を追加で指定することができます (以下のアクションの種類を参照)。
アクションの種類
アクションタイプ | 説明 | 追加属性 | 有効なターゲット |
---|---|---|---|
トグルライブ | ライブ状態の切り替え | なし | ドキュメント(ショーの開始/停止)、レイヤー、バリアント |
セットライブ | ライブ状態を "ライブ "に設定する | なし | ドキュメント(表示開始)、レイヤー、バリアント |
セットオフ | ライブ状態を "オフ "にする | なし | ドキュメント(Stop Show)、レイヤー、バリアント |
シグナル | 信号をトリガーする | signalKey, signalName(推奨) | バリアント |
トグルスイッチ | ブール値の入力値をトグルする | toggleSwitchKey, toggleSwitchName (推奨) | バリアント |
テキスト入力 | テキスト入力フィールドを開き、送信時に inputKey の値を更新します。 | inputKey, inputName(推奨) | レイヤー、バリアント、ソース |
数値入力 | inputKey の数値を制御するスライダー。 | inputKey, inputDescription (最小値と最大値の両方を持つオブジェクト), inputName (推奨) | レイヤー、バリアント、ソース |
「textInput "と "numericInput "アクションタイプは、mimoLive 5.2から利用可能です。
1TP7トンライブ状態
liveState "オブジェクトを使って、ボタンのタリーライトの状態を設定することができます。
ライブ・ステート・ソース
ボタンアクションターゲットと同様に、ライブ状態は複数のソースから得ることができる:
- ドキュメントID」は常に実行時に描画されるので、プリセットに存在する必要はない。
- もし "layerId "も "variantId "も与えられなければ、ドキュメントのライブ状態(ショーが始まっているかどうか)が使われる。
- layerId "が与えられると、そのレイヤーのライブ状態が使われる。
- もし "layerId" と "variantId" が与えられたら、 variant のライブ状態が使われます。
- この場合のみ、バリアントの入力値か出力値のブール値プロパティが使われなければならないことを示すために、追加の「propertyPath」を指定することができる。
- もう一つの可能性は(propertyPath と相互に排他的です!)、ライブ状態のルックアップを、選択されたソース(ビデオスイッチャーなど)の動的な変更を尊重するソース(ID によってフェッチされる)にリダイレクトする「dynamicSourceId」プロパティを指定することです。dynamicSourceId」の値はバリアントの入力値で検索されます。
例えば、"inputValues.some_Boolean_Property "や "outputValues.other_Property "などです。
- sourceId "が指定された場合、ソースのライブ状態が使用される。
1TP7トンテキスト
アクションボタンは一次行と二次行のテキストを表示することができ、どちらも静的または動的な性質があります。
主要テキスト
このテキストは、ボタンがユーザーに対して何を行うかを示す主要なインジケータになります。ボタンのプリセットにtextプロパティが含まれている場合、それはそのまま表示される静的なテキストです。
あるいは、簡単なテンプレート構文を使って mimoLive レイヤーやバリアントプロパティを含めることができる dynamicText を与えることもできます。テンプレート文字列では、中かっこで囲まれたプロパティパスと通常の文字を組み合わせることができます:
"template": "{\{propertyPath\}}"
プロパティのパスは、"layerId"、"variantId"、"sourceId"、"filterId" を使用して解決されるオブジェクトからの相対パスで評価されます。ターゲットの解決は以下のルールに従います:
- ドキュメントID」は常に実行時に描画されるので、プリセットに存在する必要はない。
- layerId "も "variantId "も与えられない場合、プロパティパスはドキュメントからの相対パスで評価されます。
- もし、"layerId" (そして、オプションで "variantId")が与えられると、プロパティパスは、レイヤー/バリアントからの相対評価となります。
- variantの親レイヤーは "aslayer.name "のように "layer "で始まるパスでアクセスできます。
入力値と出力値の最初のパスセグメントは、APIドキュメントにあるようなケバブケース("input-values.tvIn...")ではなく、キャメルケース("inputValues.tvIn...")でなければならない。
- 静的テキストは常に動的テキストより優先される。なぜなら、これによってユーザーは動的テキストを、状況に応じてより有用なカスタムテキストで上書きすることができるからだ。
二次テキスト
親レイヤーの名前など、ボタンに関するより多くの情報をユーザーに与えるために、"subtext "または "dynamicSubText "プロパティを使用して二次テキストを与えることができます。
テンプレート構文とオブジェクト解決は、本文とまったく同じルールに従う。
Buttonテキストとアイコンのサイズ
ボタン上のテキストとアイコンは、コンテキストによってサイズが異なる場合があります。オプション "fontScale "で、現在のスクリーンサイズから計算されたデフォルトサイズに対する相対的な縮尺を指定できます。"1 "がデフォルトサイズになります。1未満(例えば0.8)はフォントサイズを縮小し、1以上(例えば1.5)は拡大します。
1TP7トンプレビュー
アクションボタンは、コントロールするソースのプレビュー画像や、ドキュメント内で利用可能なその他のソースを表示することができます。
ソースが静的(mimoLiveにドラッグされた画像のみ)かどうかに応じて、静的な ピーエヌジー アルファ・チャンネルをサポートするソースの表現が一度ロードされる。それ以外のソースに対しては ジェイペグ ソースの表現は定期的に更新される。ダイナミック・ソースの目標更新速度は毎秒5フレームですが、プレビュー・フレームを繰り返しロードするためにネットワーク接続速度が不十分であることが判明した場合、この速度は低減されます。
現在、アクションボタンにドキュメントのプログラム出力を表示することはサポートされていません。ソースのリストには表示されませんが、レイヤーのデフォルト画像はプレビュー可能です。
ソースプレビューを指定するには、オブジェクト解決メカニズムが使用される:
- ドキュメントID」は常に実行時に描画されるので、プリセットに存在する必要はない。
- sourceId "が指定された場合、そのIDを持つソースがプレビューに使用される。
- layerId"、"variantId"、"dynamicSourceId" のすべてが与えられると、ソースの ID は、"dynamicSourceId" のキーの下にある指定されたレイヤーの variant で検索されます。これは、ビデオスイッチャーのソース A-G のようなソースを、ドキュメント内で変更されたときでも参照するために使うことができます。
1TP7トンカラー
color "属性を使用することで、ボタンは、"color "属性で表現可能な任意のカラーコードで着色することができます。 HTML (例:"#f80"、"#ff0088"、"orange"、"rgb(255, 66, 88)")。
1TP7トンアイコン
1TP14トンは、その機能を示すアイコンを表示することができます。利用可能なすべてのアイコンのリストを見るには、mimoLiveが実行中で、かつリモートコントロールが有効になっているときにhttp://localhost:8989/icons/demo.html。
アイコンのプレーンな名前を使用してください。例えば「backward」や「arrow-down」などです。