見出し画像

【DaVinci Resolve API】GUI関連メモ

まえがき

DaVinciResolveAPIでは各種ウィジェットを組み合わせてGUIを作成できます。
が、これもまた日本語情報がありません。
そもそも英語情報にしたって公式がどこに情報を載せているかもよくわかりません。プロジェクトやタイムラインを操作するドキュメントはヘルプページから探せますが、GUIは本当にどこ?

一応、ヘルプから開発者向け情報のフォルダへ飛ぶことはできるけれど……

とはいえ全く情報がないわけではありません。
有志による非公式情報は存在しており、GUIに関しては「We Suck Less」というフォーラムが参考になります。

https://www.steakunderwater.com/wesuckless/viewtopic.php?t=1411&start=210

2022/12/25追記
UIを含めたDavinciResolveスクリプティング情報はResolveDevDocというサイトの方がしっかりまとめられているのでそちらの方が良いかもしれません。(英語で記述されていますが翻訳機能を使えば大体なんとかなります)
一部項目は情報が抜けていますが、少なくともこのページよりは探しやすいでしょう。
https://resolvedevdoc.readthedocs.io/en/latest/index.html

今回の記事は特にAndrewHazeldenという方の投稿をメインに一部DeepL翻訳しつつ、実際に試してわかったことなどを追記したメモです。
あくまでメモですから正直なところ、全然見やすくはありません
メモを書いてた頃はウィジェットをコントロールと呼んでますし……。

本当ならちゃんと文章を整理・修正してから載せるべきなのでしょうが、私もそこまで時間をかけたくないのが本音です。
ただでさえスクリプト開発に労力を割いているために動画投稿できていないのに、これ以上の時間を費やすのは難しいわけで。

まあそれでも、まとまってないにしても一つくらいは日本語情報があった方が調べやすいかなあと思い、今回の記事投稿に至りました。
その点をご承知の上で読んでいただければ幸いです。

ちなみに頑張ればこのくらいのGUIを組めたりはします。
なお、GUI周りには画像関連のウィジェットがないようなのですが、TextEditウィジェットでHTML表記すればイケます。
画像をレイヤー表示する方法はこちらで解説してます。

例:開発中のGUI

メモ本文


----------------------
There are two main objects needed to manage a window, the UIManager that handles layout, and the UIDispatcher that manages interaction events, accessed as follows:
ウィンドウを管理するために必要な主なオブジェクトは、レイアウトを処理するUIManagerと、インタラクションイベントを管理するUIDispatcherの2つで、以下のようにアクセスすることができます。
 
    ui = fusion.UIManager()
    dispatcher = bmd.UIDispatcher(ui)
 
Windows are created with the the UIDispatcher, passing a dictionary of attributes like ID and Text, with GUI elements in nested layouts all created with the UIManager.
WindowsはUIDispatcherで作成し、IDやTextなどの属性の辞書を渡し、GUI要素はUIManagerでネストしたレイアウトですべて作成します。
 
UIDispatcher Functions
--------------------
UIDispatcher objectはイベント処理管理のための重要な関数をいくつか持っています。
最も重要なのは以下の通り。
 
    AddWindow(props, children): Accepts a dictionary of properties and a list of children, 返却値:Window object
    AddDialog(props, children): Accepts a dictionary of properties and a list of children, 返却値:Dialog object
    int RunLoop():              クリックしたときの処理など、各種イベントハンドラ設定などを完了し、準備した後に呼び出す関数です。
    ExitLoop(int):              イベント処理を終了し、RunLoop()から指定された終了コードを返します。
 

一般的な使用方法。
ウィンドウの作成、イベントハンドラの設定、
ExitLoop()実行時のクローズハンドラの導入後、
ウィンドウのShow()を実行し、 RunLoop()入力を受け付ける待機状態になります。
 
    ui = fusion.UIManager
    dispatcher = bmd.UIDispatcher(ui)
 
    win = dispatcher.AddWindow({ 'ID': 'myWindow' }, [ ui.Label({ 'Text': 'Hello World!' }) ])
 
    def OnClose(ev):
        dispatcher.ExitLoop()
 
    win.On.myWindow.Close = OnClose
 
    win.Show()
    dispatcher.RunLoop()
 
 
AddWindow() will also accept a single child without needing a list, or a single dictionary containing both proprties and child elements, for ease of use.
AddWindow() は、使いやすさを考慮して、リストを必要としない単一の子、またはプロパティと子要素の両方を含む単一のディクショナリも受け入れます。
 
As well as constructing new child elements and layouts, the UIManager also offers a few useful functions:
UIManagerは、新しい子要素やレイアウトを構築するだけでなく、いくつかの便利な機能を提供しています。

    FindWindow(ID):                     IDが一致する要素を返す
    FindWindows(ID):                    IDが一致する要素のリストを返す
    QueueEvent(element, event, info):   指定要素(ウィジェット)が持つイベントをイベントキューの最後へ追加します。
                                        あくまでイベントの順番待ちに加えるだけで、このメソッドの実行直後にイベント処理が始まるわけではないことに注意してください。
                                        infoはイベントハンドラが受け取る属性辞書で、{}のように空のまま渡すとデフォルト属性のみですが
                                        {arg1=true}のように何か追加するとデフォルト以外の属性をイベントハンドラへ渡すことができます。
                                        追加属性の有無によって、そのイベントが意図的に呼び出されたかどうか判断することも可能かもしれません。
 
UIManager Elements
------------------
The element's ID is used to find, manage, and dispatch events for that element. GUI elements also support a set of common attributes including Enabled, Hidden, Visible, Font, WindowTitle, BackgroundColor, Geometry, ToolTip, StatusTip, StyleSheet, WindowOpacity, MinimumSize, MaximumSize, and FixedSize. Some other common GUI elements and their main attributes include:
要素のIDは、その要素のイベントの検索、管理、ディスパッチに使用されます。GUI要素はEnabled、Hidden、Visible、Font、WindowTitle、BackgroundColor、Geometry、ToolTip、StatusTip、StyleSheet、WindowOpacity、MinimumSize、MaximumSize、FixedSizeなどの共通の属性もサポートします。その他の一般的なGUI要素とその主な属性には次のようなものがあります。 
    大体のウィジェットに共通する要素:
                Enabled          : (boolean)ウィジェットの有効化。無効化すると操作を受け付けなくなる。
                Hidden
                Visible          : (boolean)ウィジェットの可視状態。falseにすると非表示になる。
                Font
                WindowTitle      : (string)ウィンドウのフレームに表示するタイトル。Window専用?
                DoAlpha          : (boolean)背景色のAlpha値(透明度)を有効にするかどうか
                BackgroundColor  : 背景色。色の名前を指定するほか、{'R':1.0, 'G':1.0, 'B':1.0, 'A':1.0} というように設定したテーブルまたは辞書型などで指定。
                Geometry         : 現在のウィジェットの位置とサイズ。
                                   [X座標, Y座標, 幅, 高さ]を格納したテーブルまたはリスト形式で設定・取得可能。
                ToolTip
                StatusTip
                StyleSheet       : (string)ウィジェットのスタイルを指定。指定できる要素はQtのStyleSheetを調べた方が良いと思われる。
                                   スタイルは子ウィジェットにも適用される。
                WindowOpacity    : (double) ウィンドウの不透明度。1.0で完全な不透明。
                                   Qtでは1.0未満にした場合にウィンドウの更新やサイズ変更が遅くなるらしい。
                MinimumSize      : ウィジェットの最小サイズ。ウィンドウサイズを変更したとき、ウィジェットはこれより小さくはならない。[幅, 高さ]を格納したテーブルまたはリスト。
                MaximumSize      : ウィジェットの最大サイズ。ウィンドウサイズを変更したとき、ウィジェットはこれより大きくはならない。[幅, 高さ]を格納したテーブルまたはリスト。
                FixedSize        : ウィジェットのサイズを固定する。[幅, 高さ]を格納したテーブルまたはリスト。
             

    Label:      Text, Alignment, FrameStyle, WordWrap, Indent, Margin
    Button:     Text,      :(string)ボタンに表示する文字列
                Down, 
                Checkable, :(boolean) ボタンをトグルボタンにするか。
                Checked,   :(boolean) Checkableが有効な場合、ボタンのチェック状態を返却、設定可能。
                Icon,      :(Icon)ボタン表示文字列の横に表示するアイコン画像
                IconSize,  :({int, int})アイコンの表示サイズ
                Flat       :(boolean) ボタンの境界線が消える。Chackableを有効にしてチェック状態の時は表示される。
    CheckBox:   Text, Down, Checkable, Checked, Tristate, CheckState
    ComboBox:   ItemText,         :(list)
                Editable,         :(boolean)直接編集可能?
                CurrentIndex,     :(int)選択中の値
                CurrentText,     :(string)選択中のテキスト
                Count            :(int)設定数。
    SpinBox:    Value, Minimum, Maximum, SingleStep, Prefix, Suffix, Alignment, ReadOnly, Wrapping
                Prefix:接頭辞。数値の前に表示する文字列を指定する。
                Suffix:接尾辞。数値の後ろに表示する文字列を指定する。
                    例えばPrefix="入力", Suffix="行"とすると「入力5行」というように表示される。
                Alignment:文字列配置。中央上寄りといった風に、上下左右の配置を設定できる。
                    Alignment = { AlignHCenter = true, AlignTop = true }
                        
    Slider:     Value, Minimum, Maximum, SingleStep, PageStep, Orientation, Tracking, SliderPosition
    LineEdit:   Text:入力したテキスト
                PlaceholderText:Textが1文字も入力されていない時に表示される文字列
                Font
                MaxLength
                ReadOnly:編集不可にする。この状態でもEditingFinishedイベントは発生する。
                Modified:文字列の変更があったかどうかをboolean値で管理。
                ClearButtonEnabled:入力したテキストを削除するボタンを表示。ReadOnlyプロパティが有効だと押せない。
    TextEdit:   Text,                 :表示テキスト。
                                      これに文字列を代入しても内容は変更されないので、テキストを変更したいならPlainTextを利用する。
                PlainText,            :素のテキスト?
                                      テキストをスクリプトから設定するときはこの要素を変更する。
                PlaceholderText, 
                HTML,     :TextEdit ボックス内で HTML コードをレンダリングするために使用する。
                Font, 
                Alignment, 
                ReadOnly, :読取専用かどうか。
                TextColor, 
                TextBackgroundColor, 
                TabStopWidth, :(int)Tab文字が半角スペース何文字分かの設定(0だとデフォルトになる模様。よって最低値は1)
                Lexer,    :構文解析器。スクリプトエディタとして使いたい場合に指定。 
                            "lua", "python", "html", "json", "xml", "markdown", "cpp", "glsl", etc...
               (参考URL: https://forum.blackmagicdesign.com/viewtopic.php?t=153672&p=817925)
                LexerColors
    ColorPicker: Text, Color, Tracking, DoAlpha
    Font:       Family, StyleName, PointSize, PixelSize, Bold, Italic, Underline, Overline, StrikeOut, Kerning, Weight, Stretch, MonoSpaced
    Icon:       File              :アイコンとして表示する画像ファイルパス
    TabBar:     CurrentIndex,     :選択中のタブのインデックス。
                                    0から始まるが、Luaの配列はデフォルトだと1から始まるため、対応データテーブルを管理する際は注意すること。
                                    例えば、タブに対応した長さ4のテーブル[0]~[3]があるとする。
                                    この時、テーブル[0]をtable.remove(テーブル, 0)で削除しようとすると、エラーはでないが削除もされない。
                                    結果として「タブの0番は消えるが、対応テーブル0番は消えない」ので「対応するインデックスがズレる」という事態が発生する。
                                    0番タブを追加だけして操作不可能にする(Hide()メソッドで隠すとか?)ことで合わせることも可能かもしれないが、
                                    「見えないけど有る」データは後々バグの原因になりかねないので、タブのインデックスを使う場合は大人しく+1した方が安全かと思われる。
                                    UI上で操作する以外にも、このプロパティに値を直接代入して変更した場合もCurrentChangedイベントが発生する。
                TabsClosable,    :(boolean)trueならタブにクローザーアイコンを表示する
                                    CloseReqestedイベントも有効にして使う。
                Expanding, 
                AutoHide, 
                Movable,         :(boolean)有効にするとマウスドラッグで位置を変えられる。
                                  インデックスは位置に依存するため、CurrentIndexで別のウィジェットを切り替える処理がある場合は事故の要因になり得る。
                                  これを有効にするならTabで何か切り替える場合はTextで照合するか、別の管理用変数で参照する方が良いかも。
                DrawBase, 
                UsesScrollButtons, 
                DocumentMode, 
                ChangeCurrentOnDrag
    Tree:       ColumnCount,             :列の数
                SortingEnabled,         :列のヘッダをクリックするとソートできるようになる。(最後にクリックされた列のみソートが昇順・降順かどうか表示される)
                                          ただし、2022/4/11時点ではこれを有効化した場合、
                                          Tree:AddTopLevelItem(item)などでTreeItemを追加した際に一番左列で自動的にソートされてしまう。
                                          また、Tree:SortItems(int, order)やTree:SortByColumn(int, order)でのソートは降順ソートしかできないため、
                                          これらソート関数で昇順に戻すこともできない。
                                        
                ItemsExpandable,         :アイテムの子要素を展開できるようにするかどうか。デフォルトはtrue。
                                          falseに設定すると、ダブルクリックしたり、アイテム左側の「>」をクリックしても子要素を展開できなくなる。
                                          スクリプトからTreeItem.Expandにtrue, falseを代入した場合は開閉できる。
                                          あくまでマウスでの展開操作をロックする設定と見た方が良いかも。
                ExpandsOnDoubleClick,     :アイテムをダブルクリックしたときに子要素を展開できるようにするかどうか。デフォルトはtrue。
                                          falseに設定するとダブルクリックでの展開ができなくなる。
                                          ダブルクリックしたときに開閉したくない、
                                          あるいはダブルクリックしたアイテムは常に展開状態にしたい場合は無効化しておき、
                                          代わりにTree:ItemDoubleClickedイベントを有効化して、
                                          そのイベント内で該当のTreeItem.Expandedを操作すると良いかも。
                AutoExpandDelay, 
                HeaderHidden,             :ヘッダを隠す。
                IconSize,                 :({int, int})アイコンの表示サイズ
                RootIsDecorated,          :ルートが装飾されるか? よくわからず。
                Animated,                 :ツリーアイテム展開・折り畳み時にアニメーションするか。
                AllColumnsShowFocus, 
                WordWrap, 
                TreePosition, 
                SelectionBehavior,         :選択時の挙動?
                SelectionMode,             :選択モードを文字列で指定可能。"SingleSelection", "MultiSelection"があることを確認済み。
                                          "SingleSelection":同時に1つのアイテムのみ選択可能。デフォルト。
                                          "MultiSelection" :同時に複数のアイテムを選択可能。このモードだとTabKeyNavigationは無効化される模様。
                UniformRowHeights, 
                Indentation,
                VerticalScrollMode, 
                HorizontalScrollMode, 
                AutoScroll, 
                AutoScrollMargin, 
                TabKeyNavigation,         :選択中のTreeItemをTabキーで次へ、Shift+Tabキーで前へ移動する。
                                          選択中のアイテムがない場合、一番上のアイテムが選択される。
                                          一番上を選択中にShift+Tabキー、または一番下を選択中にTabキーを押すと、インデックス的には押した分だけ前or次に移動してる?
                                          SelectionModeが"MultiSelection"の場合は無効化される模様。
                AlternatingRowColors    : 奇数行と偶数行の背景色が違う色に変わります。
                FrameStyle,             :Treeの一番外枠のスタイルと思われるが良くわからず。デフォルト値は53?
                LineWidth,             -- 線の幅?
                MidLineWidth, 
                FrameRect, 
                FrameShape, 
                FrameShadow
    TreeItem:   Selected,             :(boolean)選択状態を表す。
                                      選択状態の識別以外にも、true, falseを代入することで選択状態を操作することも可能。
                Hidden,             :(boolean)表示状態を表す。
                                      falseを代入して非表示にすると、子要素もまとめて非表示になる。
                Expanded,             :(boolean)アイテムを展開して子要素を表示しているかを表す。
                                      true, falseを代入することで展開状態を操作することも可能。この場合はTree.ItemsExpandableを無効化していても問題なく操作可能。
                Disabled,             :(boolean)操作不可状態。trueにするとクリックによる選択状態の切り替えができない模様。
                FirstColumnSpanned, 
                Flags,                : Tree:FindFlagsで検索するためのフラグ?
                ChildIndicatorPolicy
   
Some elements also have property arrays, indexed by item or column (zero-based), e.g. newItem.Text[2] = 'Third column text'
 また、いくつかの要素は、項目または列(ゼロベース)でインデックスされたプロパティ配列を持ち、例えば、newItem.Text[2] = '3列目のテキスト'
 
    Combo:      ItemText[]
    TabBar:     TabText[], 
                TabToolTip[], 
                TabWhatsThis[], 
                TabTextColor[]
    Tree:       ColumnWidth[]
    Treeitem:   Text[], 
                StatusTip[], 
                ToolTip[], 
                WhatsThis[], 
                SizeHint[], 
                TextAlignment[], 
                CheckState[], 
                BackgroundColor[], 
                TextColor[], 
                Icon[], 
                Font[]
   
Some elements like Label and Button will automatically recognise and render basic HTML in their Text attributes, and TextEdit is capable of displaying and returning HTML too. Element attributes can be specified when creating the element, or can be read or changed later:
LabelやButtonのようないくつかの要素は、自動的に基本的なHTMLを認識し、そのText属性にレンダリングします。TextEditはHTMLも表示し、返すことができます。要素の属性は、要素作成時に指定することも、後から読み込んだり変更したりすることもできます。
 
    win.Find('myButton').Text = "Processing..."
 
Most elements have functions that can be called from them as well:
 ほとんどの要素は、そこから呼び出すことのできる関数も持っています。
 
    Show()             :ウィジェットを表示
    Hide()             :ウィジェットを非表示
    Raise()            :ウィジェットを同じグループ内の一番上に移動?
    Lower()            :ウィジェットを同じグループ内の一番下に移動?
    StackUnder(element):ウィジェットを指定したウィジェットの下に移動? 指定ウィジェットは同じ親を持つ兄弟ウィジェットである必要あり?
    Close()            :ウィジェットを閉じます。
    GetID()            :(string) "UITextEdit" という風にウィジェットの種類を返します。
    Find(ID)            Returns child element with matching ID
                        IDが一致する子要素を返します。
    GetChildren()       Returns list
                        子要素のリストを返します。
    AddChild(element)   子要素を追加します。
                        ただし、それだけでは正常に表示されません。
                        AddChild()で子要素を追加後にwin:RecalcLayout()を実行する必要があります。
    RemoveChild(element) 子要素を削除します。
    SetParent(element)  親要素を設定します
    Move(point)
    Resize(size)
    Size()              横、縦サイズの配列を返します。横サイズ:Size()[1]、縦サイズ:Size()[2]
    Pos()               Returns position
    HasFocus()          Returns boolean        Focusを持っているかどうかを返します。ウィンドウについてはSetFocusで設定しないとtrueになることはない?
    SetFocus(reason)    Accepts string "MouseFocusReason", "TabFocusReason", "ActiveWindowFocusReason", "OtherFocusreason", etc
    FocusWidget()       Returns element        Focusを持っているウィジェットを返します。
    IsActiveWindow()    Returns boolean        ウィンドウがアクティブかどうかを返します。
    SetTabOrder(element)    指定ウィジェットがフォーカスを持っている状態でTabキーを押した際、次にフォーカスが移るウィジェットを設定する?
    Update()
    Repaint()
    SetPaletteColor(r,g,b)
    QueueEvent(name, info)  指定したイベントをイベントキューの最後へ追加します。
                            あくまでイベントの順番待ちに加えるだけで、このメソッドの実行直後にイベント処理が始まるわけではないことに注意してください。
                            infoはイベントハンドラが受け取る属性辞書で、{}のように空のまま渡すとデフォルト属性のみですが
                            {arg1=true}のように何か追加するとデフォルト以外の属性をイベントハンドラへ渡すことができます。
                            追加属性の有無によって、そのイベントが意図的に呼び出されたかどうか判断することも可能かもしれません。
 
    GetItems()          すべての子要素の辞書を返します。
 
Some elements have extra functions of their own:
 
    Label:              SetSelection(int, int), bool HasSelection(), string SelectedText(), int SelectionStart()
    Button:             Click(),    :クリックします。ボタンを押した時の処理を動かしたいときに。
                        Toggle(),    :
                        AnimateClicked():
    CheckBox:           Click(), Toggle(), AnimateClicked()
    ComboBox:           AddItem(string),     :コンボボックスに選択肢を追加します
                        InsertItem(string), 
                        AddItems(list), 
                        InsertItems(int, list), 
                        InsertSeparator(int), 
                        RemoveItem(int), 
                        Clear(),            :設定された値を全て消して初期化します
                        SetEditText(string), 
                        ClearEditText(), 
                        Count(),             :設定された値の数を返します
                        ShowPopup(), 
                        HidePopup()
    SpinBox:            SetRange(int, int), StepBy(int), StepUp(), StepDown(), SelectAll(), Clear()
    Slider:             SetRange(int, int), TriggerAction(string)
    LineEdit:           SetSelection(int, int), :指定位置の文字列を選択?
                        bool HasSelectedText(), :テキストを選択中か?
                        string SelectedText(),     :選択中テキストを返却?
                        int SelectionStart(),     :選択範囲の開始位置を返却?
                        SelectAll(),             :全体を選択?
                        Clear(), 
                        Cut(), 
                        Copy(), 
                        Paste(),
                        Undo(), Redo(), Deselect(), Insert(string), Backspace(), Del(), Home(bool), End(bool), int CursorPositionAt(point)
    TextEdit:           InsertPlainText(string), 
                        InsertHTML(string), 
                        Append(string), 
                        SelectAll(), 
                        Clear(), 
                        Cut(), 
                        Copy(), 
                        Paste(), 
                        Undo(), 
                        Redo(),
                        ScrollToAnchor(string), 
                        ZoomIn(int), 
                        ZoomOut(int), 
                        EnsureCursorVisible(), 
                        MoveCursor(moveOperation, moveMode), 
                        bool CanPaste(),    -- 貼り付け操作ができるか?
                        string AnchorAt(point), 
                        bool Find(string, findFlags)
    TabBar:             int AddTab(string),     :指定テキストを表示したタブを追加。カレントインデックスも移動する。
                        int InsertTab(string),     :指定位置に指定テキストを表示したタブを挿入(第1引数が挿入位置?)カレントインデックスも移動する?
                        int Count(),             :タブの数を返します
                        RemoveTab(int),         :指定位置のタブを消します
                        MoveTab(int, int)        :第1引数のタブを第2引数の位置に移動?
    Tree:               item NewItem()            :新しいTreeItemを作成して返します。なお、作ったアイテムはAddTopLevelItemなどで追加しないと反映されないので注意。
                        AddTopLevelItem(item),     :Treeの一番上にアイテムを追加します。
                        InsertTopLevelItem(int, item), 
                        SetHeaderLabel(string), 
                        int CurrentColumn(),     :現在の列を返します。ItemClickedイベントで呼び出して使うのがメイン?
                        int SortColumn(),        :ソートされた列番号?
                        int TopLevelItemCount(), 
                        item CurrentItem(),     :現在のアイテムを返します。ItemClickedイベントで呼び出して使うのがメイン?
                        item TopLevelItem(int), :指定位置のアイテムを返します。0で一番上のアイテムを取得できます。
                        item TakeTopLevelItem(int), 
                        item InvisibleRootItem(),
                        item HeaderItem(), 
                        int IndexOfTopLevelItem(item), 
                        item ItemAbove(item),     ;指定したアイテムの一つ上のアイテムを返します。ItemBelow
                                                  存在しない(指定アイテムが一番上)の場合、nilを返します。
                        item ItemBelow(item),     :指定したアイテムの一つ下のアイテムを返します。
                                                  存在しない(指定アイテムが一番下)の場合、nilを返します。
                        item ItemAt(point),
                        Clear(),                 :ヘッダー以外のTreeItemを消去
                        rect VisualItemRect(item), 
                        SetHeaderLabels(list), 
                        SetHeaderItem(item),     :列のヘッダーを設定する。item:ヘッダ名を格納したTreeItem変数。
                        InsertTopLevelItems(list), 
                        AddTopLevelItems(list),    :TreeItemを格納した配列を引数に渡すと、Treeの一番上に複数のアイテムを一括で追加します。                        
                        list SelectedItems(),     :選択中アイテムリスト。
                                                    インデックスは1から始まるため、Pythonでは注意が必要。
                        list FindItems(string, flags), : 文字列がTreeitem.Flagsに含まれるものを検索する?
                        SortItems(int, order),      :指定列ごとにソート? orderは"Ascending", "Descending"の2種類?
                                                      子要素も同様のorderでソートされる点には注意。
                                                    :両方ともソートはできるが、AscendingでもDescendingでも降順ソートになってしまう。(2022/4/11時点)
                        ScrollToItem(item), 
                        ResetIndentation(),
                        SortByColumn(int, order),     :指定列ごとにソート? orderは"Ascending", "Descending"の2種類?
                                                    :両方ともソートはできるが、AscendingでもDescendingでも降順ソートになってしまう。(2022/4/11時点)
                        int FrameWidth()
    TreeItem:           AddChild(item),             :子アイテムを追加します。
                                                      追加したアイテムは親アイテムをダブルクリックするか、親アイテムの左に表示される「>」をクリックすると表示できます。
                                                      なお、子アイテムに4列分設定したとしても、3列しか設定していないTreeでは3列目までしか表示できません。
                        InsertChild(item), 
                        RemoveChild(item), 
                        SortChildren(int, order),     :子要素を指定列ごとにソートします。orderは"Ascending", "Descending"の2種類。
                                                      Tree:SortItems()やTree:SortByColumn()と違ってちゃんと昇順・降順の両方でソートできる。
                        InsertChildren(int, list), 
                        AddChildren(list),
                        int IndexOfChild(item), 
                        item Clone(), 
                        tree TreeWidget(), 
                        item Parent(), 
                        item Child(int), 
                        item TakeChild(int),
                        int ChildCount(), 
                        int ColumnCount()
    Window:             Show(), Hide(), RecalcLayout()
    Dialog:             Exec(), IsRunning(), Done(), RecalcLayout()
 
Elements can be accessed by the window's FindWindow(id) function, or by assigning them to a variable for later usage, which is more efficient. The GetItems() function will return a dictionary of all child elements for ease of access.
要素へのアクセスはウィンドウのFindWindow(id)関数で行うか、変数に代入して後で使用するのが効率的です。GetItems()関数は、アクセスを容易にするために、すべての子要素の辞書を返します。 

UIManager Layout
----------------
Additionally, elements can be nested to define layout, using the HGroup and VGroup elements. As with Window and other elements, tou can pass a single dictionary or list with all properties and children, or separate them into a dict of properties and list of children, for convenience:
また、HGroup、VGroup要素を用いて、要素を入れ子にしてレイアウトを定義することができます。Windowや他の要素と同様に、touはすべてのプロパティと子を1つの辞書またはリストに渡すか、利便性のためにプロパティの辞書と子のリストに分離することができます。 

    winLayout = ui.VGroup([
        ui.Label({ 'Text': "A 2x2 grid of buttons", 'Weight': 1 }),
       
        ui.HGroup({ 'Weight': 5 }, [
            ui.Button({ 'ID': "myButton1",  'Text': "Go" }),
            ui.Button({ 'ID': "myButton2",  'Text': "Stop" }),
            ]),
        ui.VGap(2),
        ui.HGroup({ 'Weight': 5 }, [
            ui.Button({ 'ID': "myButtonA",  'Text': "Begin" }),
            ui.Button({ 'ID': "myButtonB",  'Text': "End" }),
            ]),
        ]),
    win = dispatcher.AddWindow({ 'ID': "myWindow" }, winLayout)
 
HGap and VGap elements can included for finer spacing control. Note also the Weight attribute, which can be applied to most elements to control how they adjust their relative sizes. A Weight of 0 will use the element's minimum size.
HGapとVGap要素を含めることで、より細かいスペーシングの制御が可能です。Weight属性にも注意してください。この属性は、ほとんどの要素に適用でき、相対的な大きさを調整する方法を制御することができます。重みを0にすると、その要素の最小サイズを使用します。
 
 
Event Handlers
--------------
Window objects will call user-defined event handler functions in response to various interaction events. Event handlers are managed using a window member called 'On'. This has sub-members for each GUI element with an ID, and those have members for each available event. To set up an event handler, define a function for it, then assign the function to the window's On.ID.Event member as follows:
ウィンドウ オブジェクトは、さまざまなインタラクション イベントに応答して、ユーザー定義のイベント ハンドラ関数を呼び出します。イベントハンドラは 'On' というウィンドウメンバを使って管理されます。これはIDを持つ各GUI要素のためのサブメンバーを持っており、それらは利用可能な各イベントのためのメンバーを持っています。イベントハンドラを設定するには、イベントハンドラ用の関数を定義し、その関数をウィンドウのOn.ID.Eventメンバに次のように代入します。
 
    def OnClose(ev):
        dispatcher.ExitLoop()
 
    win.On.myWindow.Close = OnClose
 
Alternatively, if your object's ID is stored in a string variable called 'buttonID', you could use:
あるいは、オブジェクトのIDが'buttonID'という文字列変数に格納されている場合、これを使うこともできます。

    win.On[buttonID].Clicked = OnButtonClicked
 
Many objects have specific events that can be handled:
多くのオブジェクトは、処理可能な特定のイベントを持っています。

    特定イベントハンドラで処理中に別のイベント発生条件を満たした場合、割り込み処理は発生せず、順番に処理される模様?
        例:
            1.TabBarのCloseRequestedイベントの処理中にCurrentIndexに値を代入(CurrentChangedイベントの発生条件を満たす)
            2.CloseRequestedイベント終了後にCurrentChangedイベントが発生する。
                (CloseRequestedの処理の途中でCurrentChangedイベントハンドラの処理が実行されることはない)
    

    evの値の調べ方はfor文でキーと値を取り出す。
    for k,v in pairs(ev) do
        print("[" .. k .. "]:" .. tostring(v))
    end
    
    引数evの持つ値(前UI共通?):
        who:(string)イベント発生したウィジェットID
        what:(string)イベントの種類
        when:(double)検知日時
        window:(string)ウィジェットが配置されたウィンドウID
        modifiers(table):(address)変更したかどうか? アドレスの変化を見ても規則性がわからず。
        sender:(テーブル?)ウィジェットの種類?
 
    Button:             Clicked, Toggled, Pressed, Released
                        evの持つ固有値:
                            On:(boolean)カーソルがウィジェット上に乗っているかどうか?
    CheckBox:           Clicked, :クリックしたとき
                                    evの持つ固有値:
                                        On:変更後のチェック状態(bool型)
                        Toggled, 
                        Pressed, 
                        Released
    ComboBox:           CurrentIndexChanged,: インデックスが変わった時。デフォルトで有効。
                        CurrentTextChanged, 
                        TextEdited,          :テキストを直接編集時?
                        EditTextChanged, :
                        EditingFinished, :編集が終わる(他のウィジェットへフォーカスが移った時)?
                        ReturnPressed,         :エンターキーを押した時?
                        Activated
    SpinBox:            ValueChanged(ev.Value), :値を変更したとき?
                        EditingFinished            :直接編集して、その編集が終わった(他のウィジェットへフォーカスが移った)時?
    Slider:             ValueChanged, SliderMoved, ActionTriggered, SliderPressed, SliderReleased, RangeChanged
    LineEdit:           TextChanged, :テキスト変更時。他の関数などによって変更されたときも検知する点がTextEditedと異なる。
                        TextEdited, :テキストを直接編集時(キー入力やコピペしたとき)。TextChangedの前に発生。
                        EditingFinished:編集が終わる(他のウィジェットへフォーカスが移った時)?
                        ReturnPressed, :エンターキーを押した時。Ctrl+Enterなどの処理を分岐したいときに便利かも。
                                         EditingFinishedの後に実行される。
                        SelectionChanged:選択範囲を変更した時
                        CursorPositionChanged:カーソル位置変更時。テキスト入力や削除、コピペ時などにも反応する。おそらくフォーカスが外れている時は発生しない。
                        evの持つ固有値:
                            new:(int)カーソルの変更後の位置(文字数)。範囲選択でも変更される。
                            old:(int)カーソルの変更前の位置(文字数)。
    TextEdit:           TextChanged,     -- テキスト変更時
                        SelectionChanged,     -- テキストの選択を変更時?
                        CursorPositionChanged    -- カーソルポジション変更時?
    ColorPicker:        ColorChanged
    TabBar:             CurrentChanged,     :カレントタブ変更時。最初のタブを追加した時、カレントタブを消した時にも移動するので発生する。
                        evの持つ固有値:
                            Index:(int)切り替え後のタブのインデックス
                        CloseRequested,     :タブのクローズボタンを押した時。
                                              基本的にこのイベントハンドラにRemoveTab()を仕込んで実行する。
                                              なお、カレントインデックスをRemoveTab()で消した場合はCurrentChangedイベントが実行される。
                        TabMoved,             :タブを移動させた時。(消去や挿入時のも含む?)
                        TabBarClicked,        :タブをクリック時
                        TabBarDoubleClicked    :タブをダブルクリック時
    Tree:               CurrentItemChanged, 
                        ItemClicked,         :TreeItemクリック時。デフォルトで有効。
                        evの持つ固有値:
                            item:(TreeItem)クリックしたTreeItem
                            column:(int)クリックした列。左から数えて0から開始。
                        ItemPressed, 
                        ItemActivated, 
                        ItemDoubleClicked,    :TreeItemダブルクリック時 。1回目のクリック時にItemClickedイベントを先に検知する。
                        evの持つ固有値:
                            item:(TreeItem)ダブルクリックしたTreeItem
                            column:(int)クリックした列。左から数えて0から開始。
                        ItemChanged, 
                        ItemEntered,
                        ItemExpanded, 
                        ItemCollapsed,     -- アイテムを折りたたんだとき
                        CurrentItemChanged, 
                        ItemSelectionChanged    : 選択アイテムが変わった時。
                                                  例えば、選択済みアイテムをクリックしてもこのイベントは発生しない。
                                                  ItemClickedなどと違って引数evにItem属性が含まれていないため、選択中アイテムはTree:SelectedItems()で取得すると良い。
                                                  ItemClickedより先に処理される。
    Window:             Close,     -- ウィンドウ右上のクローズボタンを押した時(そのままでは画面は消えないので、イベント内でdispacher:ExitLoop()を実行させる必要がある)
                        Show,     -- ウィンドウを表示したとき
                        Hide, 
                        Resize, 
                        MousePress, 
                        MouseRelease, 
                        MouseDoubleClick, 
                        MouseMove, 
                        Wheel, 
                        KeyPress,     -- ウィンドウがアクティブな状態でキーを押した時
                        KeyRelease,     -- ウィンドウがアクティブな状態でキーを離した時
                        FocusIn,     -- Enterイベントなどでwindows:SetFocus("ActiveWindowFocusReason")を実行しておき、
                                    -- ウィンドウにフォーカスが移っている状態でウィンドウがアクティブになるとイベントを検知する模様?
                                    -- Showイベントでフォーカスを設定しておくことも可能だが、その場合はウィンドウ内のボタンなどのウィジェットを操作後は
                                    -- ウィンドウのFocusInを検知できないため、Enterイベントで実施するのが適切か?
                        FocusOut,     -- Enterイベントなどでwindows:SetFocus("ActiveWindowFocusReason")を実行しておき、
                                    -- ウィンドウにフォーカスが移っている状態でウィンドウが非アクティブになるとイベントを検知する模様?
                                    -- Showイベントでフォーカスを設定しておくことも可能だが、その場合はウィンドウ内のボタンなどのウィジェットを操作後は
                                    -- ウィンドウのFocusOutを検知できないため、Enterイベントで実施するのが適切か?
                        ContextMenu, -- 右クリックを押した時(ただし、エディタ系のように右クリック時に標準でメニュー(コピー・貼り付けなど)が出る場合はイベントは発生しない)
                        Enter,      -- ウィンドウ内にマウスカーソルが入った時
                        Leave        -- ウィンドウ外へマウスカーソルが出た時
 
Event handler functions are called with a dictionary of related attributes such as who, what, when, sender, and modifiers. Common events and some additional attributes they receive include:
イベントハンドラ関数は、who, what, when, sender, modifiers などの関連属性の辞書とともに呼び出される。一般的なイベントと、それらが受け取るいくつかの追加属性は以下の通りです。
 
    MousePress:         Pos, GlobalPos, Button, Buttons
    MouseRelease:       Pos, GlobalPos, Button, Buttons
    MouseDoubleClick:   Pos, GlobalPos, Button, Buttons
    MouseMove:          Pos, GlobalPos, Button, Buttons
    Wheel:              Pos, GlobalPos, Buttons, Delta, PixelDelta, AngleDelta, Orientiation, Phase
    KeyPress:           キーを押した瞬間を検知。
                        なお、このイベントはShift、Ctrl、Alt、Windowsキーなどの「押し続けても何も入力されないキー」しか検知できない。 
                        Key       :キーコード
                        Text     :押したキーの文字
                        IsAutoRepeat, 
                        Count
    KeyRelease:         キーを離した瞬間を検知。
                        なお、このイベントはアルファベット、Tab、Deleteキーなどの「押し続けると何かが連続で入力されつづけるキー」を検知できる。
                        連続入力されるキーは、押し続けている間はKeyReleaseイベントが発生し続ける。
                        押しても何も入力されないキーについては離したタイミングでのみ発生する。
                        Key       :キーコード
                        Text      :押したキーの文字
                        IsAutoRepeat : キーの押し始め、離したタイミングか、押し続けている状態かを表す
                                   true  : キーの押し始め、離したタイミング
                                   false : 押し続けている状態
                        Count
    ContextMenu:        Pos, GlobalPos
    Move:               Pos, OldPos
    FocusIn:            Reason
    FocusOut:           Reason
 
Event handlers can be enabled or disabled for a given element by turning them on or off in the Events attribute:
イベントハンドラは、Event属性でON/OFFすることで、指定した要素に対して有効/無効にすることができます。
 
    ui.Slider({ 'ID': 'mySlider', 'Events': { 'SliderMoved': true } })
   
Some common events like Clicked or Close are enabled by default.
 
 
Basic Resolve API
-----------------
Please refer to the [Basic Resolve API] section in '../Developer/Scripting/README.txt' file for the list of the functions that Resolve offers for scripted control. For plugin scripts, the 'resolve' and 'project' variables are automatically set up for you, and may be used to access any part of Resolve's API.
 
Further Information
-------------------
This document provides a basic introduction only, and does not list all available UIManager elements and attributes. As UIManager is based on Qt, you can refer to the Qt documentation at https://doc.qt.io/qt-5/qwidget.html for more information on element types and their attributes. There are also many third-party examples and discussions available on user forums for DaVinci Resolve and Fusion Studio.




□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
参考ページhttps://www.steakunderwater.com/wesuckless/viewtopic.php?t=1411&start=165


TabBarは、UI のページを切り替えるために使用されるタブのセットを提供し、
最も一般的には ui:Stack のようなものと一緒に使用します。

ここでは、ui:TabBarで利用可能なものの大まかな概要を説明します。

Properties:
    CurrentIndex - アクティブなタブのインデックス番号 [integer RW]
    UsesScrollButtons - タブのスクロールを可能にするボタンを表示する [boolean RW]
    TabsClosable - タブにクローザーアイコンを表示する [boolean RW]
                    クローザーアイコンクリック時の処理は
                    Events={CloseRequested=true}で有効にした上で、イベントハンドラの記述が必要です。
    Expanding - タブを展開して空きスペースを活用する [boolean RW]
    Movable - タブをドラッグして、位置入れ替えを可能にする [boolean RW]
              Index番号は変わらないため、タブの見出しごとに処理を変える場合は
              Index番号ではなくてTabTextの内容ごとに条件分岐が必要。
    DocumentMode - ドキュメント選択のための視覚的なスタイル [boolean RW]
    DrawBase - タブバーの基準線を引く [boolean RW]

    TabText[index] - 指定インデックスのタブラベル [string RW]
    TabToolTip[index] - 指定インデックスのツールチップ [string RW]
    TabTxtColor[index] - 指定インデックスのラベルカラー [color RW]

Methods:
    AddTab(label) - テキストラベルを設定しつつタブを追加します。新しいタブのインデックス番号を返却します。
                    Index番号は0から開始します。
    InsertTab(index, label) - テキストラベルを設定しつつタブを指定位置へ挿入します。新しいタブのインデックス番号を返却します。
    Count() - TabBar内のタブの数を返却します。
    RemoveTab(index) - 指定インデックスのタブを削除します。
    MoveTab(fromindex, toindex) - fromindexタブをtoindexの位置へ移動します

Events:
    イベントは基本的に一つを除いて無効化されています。
    イベントハンドラを設定するとき、該当イベントを有効化しておく必要があります。
    CurrentChanged - Current tab changed to ev.Index.  Enabled by default.
                     カレントタブが変更されたときのイベントです。デフォルトで有効です。
    CloseRequested - ev.IndexのタブでCloserがクリックされました。
    TabMoved - タブがev.Fromからev.Toへドラッグされました。
    TabBarClicked - ev.Indexでタブがクリックされました。
    TabBarDoubleClicked - ev.Indexでタブがダブル・クリックされました。

以下、TabBar使用例。
■■■■■■■■■■■■■■■■■■■■■■■■
ui = fu.UIManager
disp = bmd.UIDispatcher(ui)
 
win = disp:AddWindow(
{
    ID = "MyWin",
    WindowTitle = "Tab test",
    Geometry = { 100,100,400,300 },
 
    ui:VGroup
    {
        ui:TabBar { Weight = 0.0, ID = "MyTabs", },
        ui:VGap(0, 10),
        ui:Stack
        {
            Weight = 1.0,
            ID = "MyStack",
 
            ui:Button { Text = "Button One", ID = "Button1" },
            ui:Slider { ID = "Slider1", Minimum = 0, Maximum = 100 },
            ui:HGroup
            {
                ui:Button { Text = "A", ID = "ButtonA" },
                ui:Button { Text = "B", ID = "ButtonB" },
                ui:Button { Text = "C", ID = "ButtonC" },
            },
        },
        ui:VGap(0, 10),
    },
})
 
itm = win:GetItems()
 
itm.MyStack.CurrentIndex = 0
 
itm.MyTabs:AddTab("One")
itm.MyTabs:AddTab("Two")
itm.MyTabs:AddTab("Three")
 
function win.On.MyTabs.CurrentChanged(ev)
    itm.MyStack.CurrentIndex = ev.Index
end
 
function win.On.Slider1.ValueChanged(ev)
    local v = 1 - ev.Value/100
 
    itm.MyTabs.TabTextColor[0] = { R=1, G=v, B=v, A=1 }
    itm.MyTabs.TabTextColor[1] = { R=v, G=1, B=v, A=1 }
    itm.MyTabs.TabTextColor[2] = { R=v, G=v, B=1, A=1 }
end
 
function win.On.Button1.Clicked(ev)
    itm.MyTabs.TabText[0] = "One"
    itm.MyTabs.TabText[1] = "Two"
    itm.MyTabs.TabText[2] = "Three"
end
 
function win.On.ButtonA.Clicked(ev)
    itm.MyTabs.TabText[0] = "A"
end
 
function win.On.ButtonB.Clicked(ev)
    itm.MyTabs.TabText[1] = "B"
end
 
function win.On.ButtonC.Clicked(ev)
    itm.MyTabs.TabText[2] = "C"
end
 
function win.On.MyWin.Close(ev)
    disp:ExitLoop()
end
 
win:Show()
disp:RunLoop()
win:Hide()

■■■■■■■■■■■■■■■■■■■■■■■■
参考ページ:https://www.steakunderwater.com/wesuckless/viewtopic.php?t=1411

Fusionでは、新しいウィンドウはこのように表示されます。
ui-manager-new-window.png
利用可能なGUI要素

新しいウィンドウが作成されたので、以下のGUI要素をウィンドウのui:VGroup{}タグ内に配置し、ビューに追加することができます。

tag:
ui:VGroup{}
ui:HGroup{}
ui:Stack{}
ui:VGap{}
ui:HGap{}
ui:Button{}
ui:CheckBox{}
ui:ColorPicker{}
ui:ComboBox{}
ui:DoubleSpinBox{}
ui:Label{}
ui:LineEdit{}
ui:Slider{}
ui:SpinBox{}
ui:TabBar{}
ui:TextEdit{}
ui:Tree{}

IDタグとは?

UI マネージャでは、GUI レイアウトのすべてのウィジェットの { } 中括弧の中に ID タグ文字列が配置されることを理解することが重要です。
IDタグは、引用符で囲まれた1文字から、スペースを含まない長い文字列まであり、
Luaがコードから特定のGUIエレメントにアクセスする際に使用する名前を定義するのに使用されます。


新しいGUI要素の使い方を教えてください。

ui:VGroup{} / ui:HGroup{}

ui:VGroup{}とui:HGroup{}があります。
GUI要素は、ウィンドウ内に縦長と横長のレイアウトを作成するために使用します。
これらのグループオブジェクトを互いに入れ子にして複数積み重ねることで、
画面上にUI要素を行と列に配置した複雑なGUIを作成したり、グリッド形式のレイアウトを作成することも可能です。

例:
ui:VGroup{。
  -- ここにGUI要素を追加する
}

ui:VGap{} / ui:HGap{}

ui:VGap{}とui:HGap{}は GUI要素は、各GUIウィジェットの間にスペースを設け、ウィンドウ内の移動を容易にしたり、
ui:VGroup{} や ui:HGroup{} レイアウト内の要素をより論理的にグループ化するために使用されます。
gapウィジェットには、ピクセルまたは相対的な測定値を使用してウィジェット間のスペースを定義するオプションがあります。

この例では、ui:VGroup{}またはui:HGroup{}レイアウトのui:HGap要素の両側に置かれたウィジェットの間に、
5ピクセル幅の水平方向のギャップを追加しています。

例:
-- Add a control here
ui:HGap(5),
-- Add a control here

この例では、ui:VGroup{} または ui:HGroup{} レイアウトの ui:HGap エレメントの両側に配置されたウィジェットの間に、
柔軟な大きさの水平を作成します。

例:
-- Add a control here
ui:HGap(0, 1.0),
-- Add a control here


ui:Button{}を使用します。

ui:Button{}ウィジェットはシンプルな長方形の形のクリッカブルボタンを作成します。

新しいボタンにテキストラベルを割り当てるには、次のような属性を追加します。
Text = 'The Button Label'. 
もしお使いのオペレーティングシステムのデフォルトフォントが絵文字や拡張ユニコード文字の表示をサポートしていれば、
それらをボタンのテキストラベル文字列に追加することもできます。
ui-manager-button.png.

例:
local ui = fu.UIManager
local disp = bmd.UIDispatcher(ui)
local width,height = 400,200
 
win = disp:AddWindow({
  ID = 'MyWin',
  WindowTitle = 'My First Window',
  Geometry = { 100, 100, width, height },
  Spacing = 10,
 
  ui:VGroup{
    ID = 'root',
   
    -- Add your GUI elements here:
    ui:HGroup{
      Margin = 50,
      ui:Button{ID = 'B', Text = 'The Button Label'},
    }
  },
})
 
-- The window was closed
function win.On.MyWin.Close(ev)
    disp:ExitLoop()
end
 
-- Add your GUI element based event functions here:
itm = win:GetItems()
 
function win.On.B.Clicked(ev)
  print('Button Clicked')
    disp:ExitLoop()
end
 
win:Show()
disp:RunLoop()
win:Hide()



ui:CheckBox{}を使用します。

ui:CheckBox{}ウィジェットはウィンドウレイアウトにチェックボックスを追加し、true/falseのブール値を設定します。
新しいチェックボックスにラベルを割り当てるには、次のような属性を追加します。
Text = 'The Checkbox Label'.

例:
local ui = fu.UIManager
local disp = bmd.UIDispatcher(ui)
local width,height = 400,200
 
win = disp:AddWindow({
  ID = 'MyWin',
  WindowTitle = 'My First Window',
  Geometry = { 100, 100, width, height },
  Spacing = 10,
 
  ui:VGroup{
    ID = 'root',
    Margin = 50,
   
    -- Add your GUI elements here:
    ui:CheckBox{ID = 'MyCheckbox', Text = 'The Checkbox Label'},
  },
})
 
-- The window was closed
function win.On.MyWin.Close(ev)
    disp:ExitLoop()
end
 
-- Add your GUI element based event functions here:
itm = win:GetItems()
 
function win.On.MyCheckbox.Clicked(ev)
  print('[Checkbox] ' .. tostring(itm.MyCheckbox.Checked))
end
 
win:Show()
disp:RunLoop()
win:Hide()




ui:カラーピッカー{}

ui:ColorPicker{}ウィジェットは、赤/緑/青のカラースライダーと、カスタムカラー値を作成するための
プレビューカラースウォッチを提供します。
ui-manager-colorpicker.png
を使用して、カラーピッカーのデフォルトカラーを入力することができます。

例:
ui:ColorPicker{ ID = "Color", Color = { R = 0.753, G = 0.753, B = 0.753, A = 1}},

カラーピッカーのRGBフロート値を読み取るには
例:
red = itm.Color.Color.R
green = itm.Color.Color.G
blue = itm.Color.Color.B

例:
local ui = fu.UIManager
local disp = bmd.UIDispatcher(ui)
local width,height = 400,200
 
win = disp:AddWindow({
  ID = 'MyWin',
  WindowTitle = 'My First Window',
  Geometry = {100, 100, width, height},
  Spacing = 10,
 
  ui:VGroup{
    ID = 'root',
   
    -- Add your GUI elements here:
    ui:ColorPicker{ID = 'Color'},
  },
})
 
-- The window was closed
function win.On.MyWin.Close(ev)
    disp:ExitLoop()
end
 
-- Add your GUI element based event functions here:
itm = win:GetItems()
 
win:Show()
disp:RunLoop()
win:Hide()




ui:ComboBox{}(コンボボックス)

ui:ComboBox{}ウィジェットはComboControl / Options Menuスタイルのメニューを表示し、
エントリーの一覧から個々のメニューを選択することが出来ます。

現在のコンボボックスの選択項目の文字列は ".CurrentText" を使って次のように読み取ることができます。
print(itm.MyCombo.CurrentText)

このように".CurrentIndex "を使って、現在のコンボボックスの選択範囲のインデックス値を読み取ることができます。
print(itm.MyCombo.CurrentIndex)

ui-manager-combobox.png
メニュー項目のリストは、AddWindow()関数の外側で、AddItem()コマンドを使用して、次のように定義する必要があります。
例:
local ui = fu.UIManager
local disp = bmd.UIDispatcher(ui)
local width,height = 400,100
 
win = disp:AddWindow({
  ID = 'MyWin',
  WindowTitle = 'My First Window',
  Geometry = {100, 100, width, height},
  Spacing = 10,
 
  ui:VGroup{
    ID = 'root',
   
    -- Add your GUI elements here:
    ui:ComboBox{ID = 'MyCombo', Text = 'Combo Menu'},
  },
})
 
-- The window was closed
function win.On.MyWin.Close(ev)
    disp:ExitLoop()
end
 
-- Add your GUI element based event functions here:
itm = win:GetItems()
 
-- Add the items to the ComboBox menu
itm.MyCombo:AddItem('Apple')
itm.MyCombo:AddItem('Banana')
itm.MyCombo:AddItem('Cherry')
itm.MyCombo:AddItem('Orange')
itm.MyCombo:AddItem('Mango')
itm.MyCombo:AddItem('Kiwi')
 
-- This function is run when a user picks a different setting in the ComboBox control
function win.On.MyCombo.CurrentIndexChanged(ev)
  if itm.MyCombo.CurrentIndex == 0 then
    -- Apple
    print('[' .. itm.MyCombo.CurrentText .. '] Lets make an apple crisp dessert.')
  elseif itm.MyCombo.CurrentIndex == 1 then
    -- Banana
    print('[' .. itm.MyCombo.CurrentText .. '] Lets make a banana split with ice cream.')
  elseif itm.MyCombo.CurrentIndex == 2 then
    -- Cherry
    print('[' .. itm.MyCombo.CurrentText .. '] Lets make some cherry tarts.')
  elseif itm.MyCombo.CurrentIndex == 3 then
    -- Orange
    print('[' .. itm.MyCombo.CurrentText .. '] Lets peel an orange and have sliced orange boats.')
  elseif itm.MyCombo.CurrentIndex == 4 then
    -- Mango
    print('[' .. itm.MyCombo.CurrentText .. '] Lets eat cubed mango chunks with yoghurt.')
  elseif itm.MyCombo.CurrentIndex == 5 then
    -- Kiwi
    print('[' .. itm.MyCombo.CurrentText .. '] Lets have a fresh Kiwi snack.')
  end
end
 
win:Show()
disp:RunLoop()
win:Hide()




ui:DoubleSpinBox{}を使用します。

ui:DoubleSpinBox{}ウィジェットは、数値の入力を可能にします。
このGUI要素は数値を直接入力するか、上下の矢印ボタンを押すか、
数値フィールドをクリックしてマウスのスクロールホイールを回すことにより増加させることができます。

ui:DoubleSpinBoxウィジェットは、通常ui:VGroup{}またはui:HGroup{}要素内に配置し、
GUI上のサイズをウィジェットすることができます。

例:
local ui = fu.UIManager
local disp = bmd.UIDispatcher(ui)
local width,height = 400,75
 
win = disp:AddWindow({
  ID = 'MyWin',
  WindowTitle = 'My First Window',
  Geometry = {100, 100, width, height},
  Spacing = 10,
 
  ui:VGroup{
    ID = 'root',
 
    -- Add your GUI elements here:
    ui:DoubleSpinBox{ID='MySpinner'},
  },
})
 
-- The window was closed
function win.On.MyWin.Close(ev)
    disp:ExitLoop()
end
 
-- Add your GUI element based event functions here:
itm = win:GetItems()
 
function win.On.MySpinner.ValueChanged(ev)
  print('[DoubleSpinBox Value] '.. itm.MySpinner.Value)
end
 
win:Show()
disp:RunLoop()
win:Hide()




ui:Label{}を使用します。

ui:Label{}ウィジェットを使うと、ウィンドウにユーザー編集不可のテキストブロックを追加することができます。

ui:VGroup{}やui:HGroup{}レイアウトの中で複数のLabel要素を使用すると、
より複雑なウィンドウレイアウトを視覚的に分割して、より論理的なグループに分けることができます。
これにより、ユーザーは一連のウィジェットが何に使われるかを理解しやすくなります。

例:
local ui = fu.UIManager
local disp = bmd.UIDispatcher(ui)
local width,height = 400,200
 
win = disp:AddWindow({
  ID = 'MyWin',
  WindowTitle = 'My First Window',
  Geometry = {100, 100, width, height},
  Spacing = 10,
 
  ui:VGroup{
    ID = 'root',
 
    -- Add your GUI elements here:
    ui:Label{ID = 'L', Text = 'This is a Label', Alignment = { AlignHCenter = true, AlignTop = true },},
  },
})
 
-- The window was closed
function win.On.MyWin.Close(ev)
    disp:ExitLoop()
end
 
-- Add your GUI element based event functions here:
itm = win:GetItems()
 
win:Show()
disp:RunLoop()
win:Hide()



ui:Slider{}

ui:Slider{}ウィジェットは、水平スライダーウィジェットを提供します。
例:
local ui = fu.UIManager
local disp = bmd.UIDispatcher(ui)
local width,height = 400,100
 
win = disp:AddWindow({
  ID = 'MyWin',
  WindowTitle = 'My First Window',
  Geometry = {100, 100, width, height},
  Spacing = 10,
 
  ui:HGroup{
    ID = 'root',
   
    -- Add your GUI elements here:
    ui:Slider{ID = 'MySlider'},
   
    ui:Label{ID = 'MyLabel', Text = 'Value: ',},
  },
})
 
-- The window was closed
function win.On.MyWin.Close(ev)
  disp:ExitLoop()
end
 
-- Add your GUI element based event functions here:
itm = win:GetItems()
 
itm.MySlider.Value = 25
itm.MySlider.Minimum = 0
itm.MySlider.Maximum = 100
 
function win.On.MySlider.ValueChanged(ev)
  itm.MyLabel.Text = 'Slider Value: ' .. tostring(ev.Value)
end
 
win:Show()
disp:RunLoop()
win:Hide()



ui:LineEdit{}を使用します。

ui:LineEdit{}ウィジェットは、一行ベースの編集可能なテキストフィールドウィジェットを追加します。
"PlaceholderText" 属性は、フィールドが空のときに表示されるラベルテキストを定義することができます。
これは、ウィジェットが何に使用されるかを示すのに便利です。

例:
local ui = fu.UIManager
local disp = bmd.UIDispatcher(ui)
local width,height = 400,200
 
win = disp:AddWindow({
  ID = 'MyWin',
  WindowTitle = 'My First Window',
  Geometry = { 100, 100, width, height },
  Spacing = 10,
 
  ui:VGroup{
    ID = 'root',
    Margin = 50,
   
    -- Add your GUI elements here:
    ui:LineEdit{ID='MyLineTxt', Text = 'Hello Fusioneers!', PlaceholderText = 'Please Enter a few words.',},
   
    ui:Button{ID = 'PrintButton', Text = 'Print Text'},
  },
})
 
-- The window was closed
function win.On.MyWin.Close(ev)
    disp:ExitLoop()
end
 
-- Add your GUI element based event functions here:
itm = win:GetItems()
 
function win.On.PrintButton.Clicked(ev)
  print(itm.MyLineTxt.Text)
end
 
function win.On.MyLineTxt.TextChanged(ev)
    print(itm.MyLineTxt.Text)
end
 
win:Show()
disp:RunLoop()
win:Hide()




ui:TextEdit{}を使用します。

ui:TextEdit{}ウィジェットは、編集可能なテキストフィールドウィジェットを追加します。
テキストフィールドはプレーンテキストまたは HTML を使ってレンダリングすることが可能です。
ui:TextEditフィールドは、以下のように "ReadOnly "タグを追加することにより、読み取り専用にすることができます。

ui:TextEdit{ID='Txt', Text = 'Hello', ReadOnly = true,}

ui:TextEditフィールドの内容を変更するには、次のどちらかを使用します。
例1:
-- Plain unformatted text:
itm.MyTxt.PlainText = 'Hello Fusioneers'2:
-- HTML encoded text:
itm.MyTxt.HTML = [[<h1>HTML Formatted Text</h1><p>This this HTML rendered in a ui:TextEdit field!</p>]]

"PlaceholderText "属性は、フィールドが空のときに表示されるラベルテキストを定義することができます。
これは、ウィジェットが何に使われるかを示すのに便利です。

例:
local ui = fu.UIManager
local disp = bmd.UIDispatcher(ui)
local width,height = 600,800
 
win = disp:AddWindow({
  ID = 'MyWin',
  WindowTitle = 'My First Window',
  Geometry = { 100, 100, width, height },
  Spacing = 10,
 
  ui:VGroup{
    ID = 'root',
    Margin = 50,
   
    -- Add your GUI elements here:
    ui:TextEdit{ID='MyTxt', Text = 'Hello', PlaceholderText = 'Please Enter a few words.',}
  },
})
 
-- The window was closed
function win.On.MyWin.Close(ev)
    disp:ExitLoop()
end
 
-- Add your GUI element based event functions here:
itm = win:GetItems()
 
function win.On.MyTxt.TextChanged(ev)
    print(itm.MyTxt.PlainText)
end
 
win:Show()
disp:RunLoop()
win:Hide()




ui:Tree{}を使用します。

ui:Tree{}ウィジェットはスプレッドシートのようなグリッドレイアウトを作成します。
これはレポート中の要素を行と列でリストアップするのに便利です。
ui:Treeの項目は、以下のタグを使用してクリックやソートが可能なようにすることができます。
ui:Tree{ID = 'Tree', SortingEnabled=true, Events = {  ItemDoubleClicked=true, ItemClicked=true }, },

行のシングルクリックは、"function win.On.Tree.ItemClicked(ev)" で検出することができます。
行のダブルクリックは、"function win.On.Tree.ItemDoubleClicked(ev)" を使って検出することができます。
シングルクリック、ダブルクリックのイベント内では、"ev.item.Text[1]"でクリックされた行名テキストを読み取ることができます。
また、[]括弧内のインデックス値は、表示したい特定の列見出しテキストです。
クリックされた特定のツリー・ビュー・セルの内容は、
「ev.column」を使用して個々のセルにアクセスして編集することができます。

-- A Tree view cell was clicked on
function win.On.Tree.ItemClicked(ev)
  -- You can use the ev.column value to edit a specific ui:Tree cell label
  ev.item.Text[ev.column] = '*CLICK*'
end

ツリービューに折りたたみ式の三角形のセクションを追加して、小見出しを付けることができます。
これは、より高度なトピックなので、今後のチュートリアルで説明します。
各見出しの幅は、".ColumnWidth "設定を使用して調整します。
-- Resize the Columns
itm.Tree.ColumnWidth[0] = 150
itm.Tree.ColumnWidth[1] = 300
itm.Tree.ColumnWidth[2] = 50

ツリービューを動的に再構築する場合、"itm.Tree:Clear() "コマンドで既存のアイテムを消去することができます。
例:
local ui = fu.UIManager
local disp = bmd.UIDispatcher(ui)
local width,height = 430,700
 
win = disp:AddWindow({
  ID = 'MyWin',
  WindowTitle = 'Tree',
  Geometry = { 100, 100, width, height },
  Spacing = 0,
 
  ui:VGroup{
    ID = 'root',
    ui:Tree{ID = 'Tree', SortingEnabled=true, Events = {ItemDoubleClicked=true, ItemClicked=true}, },  
  },
})
 
-- The window was closed
function win.On.MyWin.Close(ev)
    disp:ExitLoop()
end
 
-- Add your GUI element based event functions here:
itm = win:GetItems()
 
-- Add a header row.
hdr = itm.Tree:NewItem()
hdr.Text[0] = ''
hdr.Text[1] = 'Column A'
hdr.Text[2] = 'Column B'
hdr.Text[3] = 'Column C'
hdr.Text[4] = 'Column D'
hdr.Text[5] = 'Column E'
itm.Tree:SetHeaderItem(hdr)
 
-- Number of columns in the Tree list
itm.Tree.ColumnCount = 5
 
-- Resize the Columns
itm.Tree.ColumnWidth[0] = 100
itm.Tree.ColumnWidth[1] = 75
itm.Tree.ColumnWidth[2] = 75
itm.Tree.ColumnWidth[3] = 75
itm.Tree.ColumnWidth[4] = 75
itm.Tree.ColumnWidth[5] = 75
 
-- Add an new row entries to the list
for row = 1, 50 do
  itRow = itm.Tree:NewItem();
  -- String.format is used to create a leading zero padded row number like 'Row A01' or 'Row B01'.
  itRow.Text[0] = string.format('Row %02d', row);
  itRow.Text[1] = string.format('A %02d', row);
  itRow.Text[2] = string.format('B %02d', row);
  itRow.Text[3] = string.format('C %02d', row);
  itRow.Text[4] = string.format('D %02d', row);  
  itRow.Text[5] = string.format('E %02d', row);
  itm.Tree:AddTopLevelItem(itRow)
end
 
-- A Tree view row was clicked on
function win.On.Tree.ItemClicked(ev)
  print('[Single Clicked] ' .. tostring(ev.item.Text[0]))
 
  -- You can use the ev.column value to edit a specific ui:Tree cell label
  ev.item.Text[ev.column] = '*CLICK*'
end
 
-- A Tree view row was double clicked on
function win.On.Tree.ItemDoubleClicked(ev)
  print('[Double Clicked] ' .. tostring(ev.item.Text[0]))
end
 
win:Show()
disp:RunLoop()
win:Hide()



■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

前回の記事で紹介したUIマネージャーのGUIインターフェース・ウィジェットをさらに詳しく説明する前に、Luaを使用してHTMLコード・エディター・ウィンドウを作成し、HTMLプレビューをライブ表示するサンプル・プロジェクトを紹介したいと思います。このサンプルは、ui:TextEditフィールドがプレーンテキスト(.PlainText属性)またはHTMLコンテンツ(.HTML属性)を受け取り、レンダリングすることができるという優れた機能に基づいて作成されています。

このスタイル付きHTMLテキスト機能は、コンポジット・パッケージには不要に思えるかもしれませんが、スクリプトのGUIにリッチテキスト形式のドキュメントをインライン表示したり、Fusionのスクリプトシステムを使ってHTML形式のレポートやログを生成し、アーティストが一目で分かるようにシンプルなUIマネージャビューに表示することが可能になり、世界が大きく広がります。

HTMLコードエディタ.lua

概要
このスクリプトは、Fusion 8.2.1 と Fusion 9 で動作する Fusion Lua ベースのサンプルで、
ビュー上部の編集フィールドで HTML コードを編集し、ウィンドウ下部にライブプレビューを表示することができます。

ui:TextEditウィジェットのHTML入力は、レンダリングされたコンテンツに予め用意された
HTMLヘッダー/フッターとCSSコードブロックを自動的に追加しますので、
編集するコードは、既存のHTMLボディタグの中にあるかのように記述することが必要です。

このLuaスクリプトは、fu.UIManager GUIの例として、新しいウィンドウを作成し、
ui:TextEditフィールドを追加してユーザーからの入力を受け付け、
ライブレンダリングしたRich HTML出力を "read only "と表示されている2番目のui:TextEditフィールドに表示して、
リアルタイムで自動更新する方法を紹介することを主目的としています。

このライブ更新は、HTMLテキストエディターウィンドウのトップビューエリアでテキストを更新するたびにトリガーされる.TextChangedイベントを持つ関数win.On.CodeEntry.TextChanged(ev)コードを使用して実現されています。

itm.HTMLPreview.HTML = itm.CodeEntry.PlainText というコードは、上の「HTMLコードエディタ」ビューで入力したプレーンテキスト形式のコードをコピーし、下の「HTMLライブプレビュー」ウィンドウにリッチテキストHTML形式のコンテンツとして貼り付けています。UI Managerは、見つけたHTMLタグをスタイル付きHTMLテキストフォーマットコマンドに変換し、見出し、斜体、太字、下線付きリンク、箇条書きリストのような視覚的にスタイル付きのテキスト要素を提供します。

私の最初のテストでは、インターネットにリンクされたHTTPベースの画像URLは、
プレビューウィンドウに読み込まれないようです。
Base64でエンコードされた画像をインラインでウェブページに埋め込むことは可能ですが、
それは次の「HTML画像ソースの例」の記事で説明します。


HTML Image Source Example

Overview

The "HTML Image Source.lua" script is a Fusion Lua based example that works in Fusion 8.2.1 and Fusion 9 that uses the HTML loading capacity of the ui:textField to display an image.

This example is based upon a tip from the WSL User Dunn. The basic idea is that you are able to use the CodeBeautify webpage translator tool to convert a PNG, or JPEG image from a binary image format into a base64 encoded inline HTML "Image Source" element that can be placed as HTML code inside of a ui:textField control.

Screenshot
HTML-Image-Source-Screenshot.png
Download
HTML-Image-Source-Example.zip
Installation

Step 1. Copy the "HTML Image Source.lua" script and the "fusion-logo.png.base64" image to your Fusion user preferences "Scripts/Comp/" folder.

Step 2. Once the script is copied into the "Scripts/Comp/" folder you can then run it from inside Fusion's GUI by going to the Script menu and selecting the "HTML Image Source" item.

How to Generate a base64 Image Resource Using a Web Based Tool

Step 1. Go to this webpage https://codebeautify.org/image-to-base64-converter and process your photo or logo image from a JPEG/PNG/GIF image format into a "Source Image" based inline html code format.

Step 2. Save the "Source Image" output from the Code Beautify conversion tool into a new textfile that is placed in the same folder as your UI Manager based .lua script. It is a good idea to give this converted image a unique name like "my-image.base64" so you can remember later on this media was encoded in the base64 format.

Step 3. If you copied the files in the installation steps to a different folder then specified by default, you will need to update the "base64Imagename" variable in the "HTML Image Source.lua" script to use the Fusion relative "Pathmap" based location where you copied the "fusion-logo.png.base64" image.

Base64 Encoding an Image from the Command Prompt

You can also use the Mac/Linux/Cygwin on Windows "base64" terminal program to base64 encode an image into the required format. Then you need to add the html header tag `<img src='data:image/png;base64,` and a footer tag of `'/>` to the base64 encoded image. You can type "man base64" in a terminal window for more details on the conversion tool.

MacOS base64 Encoding Terminal Commands:
CODE: SELECT ALL

base64 --input="/Applications/Blackmagic Fusion 9/Fusion.app/Contents/MacOS/Library/Text Plus/Steel Hilight.bmp" --output="$HOME/Desktop/base64-encoded.tmp"
echo "<img src='data:image/png;base64," > "$HOME/Desktop/image.base64"
cat "$HOME/Desktop/base64-encoded.tmp" >> "$HOME/Desktop/image.base64" 
echo "'/>" >> "$HOME/Desktop/image.base64"
Linux base64 Encoding Terminal Commands
CODE: SELECT ALL

base64 "/opt/BlackmagicDesign/Fusion9/Library/Text Plus/Steel Hilight.bmp" > "$HOME/Desktop/base64-encoded.tmp"
echo "<img src='data:image/png;base64," > "$HOME/Desktop/image.base64"
cat "$HOME/Desktop/base64-encoded.tmp" >> "$HOME/Desktop/image.base64" 
echo "'/>" >> "$HOME/Desktop/image.base64"
Note: To help you understand what the above terminal code does a bit better, the > chevron symbol pushes the output string from running the terminal command into a file on disk. The double >> chevron command concatenates the output string from running the terminal command onto the end of an existing file that is on disk.

Note: For accuracy you should change the "<img src='data:image/png;base64," part of the terminal command to so the HTML header text matches the image format you are converting:

JPEG image:
CODE: SELECT ALL

<img src='data:image/jpg;base64,"
GIF image / GIF animation:
CODE: SELECT ALL

<img src='data:image/gif;base64,"
PNG image:
CODE: SELECT ALL

<img src='data:image/png;base64,"
BMP image:
CODE: SELECT ALL

<img src='data:image/bmp;base64,"


■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


ほとんどのUIウィジェットは、複数のイベントをサポートしていますが、効率化のため、
通常はデフォルトで1つしか有効になりません。追加のイベントは、イベントテーブルを指定して設定することができる。
イベントテーブルを指定する場合、デフォルトのイベントが必要であれば、それを含めなければならないことに注意してください。

イベントハンドラ関数のevパラメータには、すべてのイベントに対する一般的な情報と、
多くのイベントに対する現在の値や状態などの具体的な情報が含まれていることに注意してください。
ui:ComboBox{
        ID = "MyCombo",
        ...
        Events = { CurrentIndexChanged = true, Activated = true },
    }

function win.On.MyCombo.CurrentIndexChanged(ev)
    ...
end

function win.On.MyCombo.Activated(ev)
    ...
end



各種ウィジェットタイプでサポートされているイベント(*は、デフォルトで有効になっているイベントを示す)。
なお、どれか一つを有効化すると、デフォルトで有効なイベントは改めて有効宣言しないと無効になる模様?

Button:
    Clicked *
    Toggled
    Pressed
    Released
CheckBox:
    Clicked *
    Toggled
    Pressed
    Released
    StateChanged
    ColorPicker:
    ColorChanged *
ComboBox:
    EditTextChanged
    Activated
    ActivatedText
    Highlighted
    HighlightedText
    CurrentIndexChanged *
    CurrentIndexChangedText
    CurrentTextChanged
    TextChanged
    TextEdited
    CursorPositionChanged
    ReturnPressed
    EditingFinished
    SelectionChanged
DoubleSpinBox:
    EditingFinished
    ValueChanged *
LineEdit:
    TextChanged *
    TextEdited
    CursorPositionChanged
    ReturnPressed
    EditingFinished
    SelectionChanged
Slider:
    ValueChanged *
    SliderMoved
    ActionTriggered
    SliderPressed
    SliderReleased
    RangeChanged
SpinBox:
    EditingFinished
    ValueChanged *
TabBar:
    CurrentChanged *
    CloseRequested
    TabMoved
    TabBarClicked
    TabBarDoubleClicked
TextEdit:
    TextChanged *
    CursorPositionChanged
    SelectionChanged
Tree:
    ItemPressed
    ItemClicked *
    ItemDoubleClicked
    ItemActivated
    ItemEntered
    ItemChanged
    ItemExpanded
    ItemCollapsed
    CurrentItemChanged
    ItemSelectionChanged
Window:
    Close *

サポートしていただけるとその分の価値を提供できてるんだなって励みになります。