C#ATIA

↑タイトル詐欺 主にFusion360API 偶にCATIA V5 VBA(絶賛ネタ切れ中)

俺コマンドを作る4

こちらの続きなのですが、
俺コマンドを作る3 - C#ATIA

内容的には、あちらのAddinSkeletonを使わずに書いていたこちらの続きです。
俺コマンドを作る1 - C#ATIA


作りかかっているアドインの処理部分は、大体上手く行っているのですが
制御的な部分で詰まりました。
やりたいことはこんな感じです。
f:id:kandennti:20201222181644p:plain
コマンドを起動するとチェックボックス(本当はGroupCommandInput)が表示されます。
これをチェックを外し、OK押すと・・・例の如く何もしません。

再度コマンドを起動した時には、前回操作したチェックが外れた状態で
ダイアログが出てきて欲しいんです。
f:id:kandennti:20201222182138p:plain

この仕組みが分からなかったんです。
遠回しな表現だと、こちらのトピに近いです。
解決済み: 次の操作も同じ円を描くことができますか? - Autodesk Community
ちょっとこれはボリュームが大きすぎて対処出来そうにないのが本音です。
(コマンドをフックすれば出来そうだけど、出来るのかな?)

恐らく他人には伝わらないと思うのですが書いておきます。自分の為に。
アドインはメモリに駐在しているような感じだけど、コマンド自体は駐在していないっぽく、
CommandDefinitionを保持している状態のToolbarPanelが駐在している。と思う。
コマンドはボタンが押されたタイミングでコマンド自体は作られている気がします。

チェックがOnかOffを保持していたいのですが、どうやらGlobalな変数に入れておいても
ダメっぽかったです。
 Globalな変数で大丈夫です・・・。

実現出来るものかどうかも分からぬまま、何かサンプルが見当たらないか探したところ
有りました。
f:id:kandennti:20201222183121p:plain
アドインの方のギア作るやつです。

これ、コードのボリュームが大きく、吐き気がしてくるのですが
仕方が無いため読みました。で、分かりました。

ひょっとしたら幾つか方法が有りそうなのですが、このギアのアドインの場合は
こんな感じでした。
CAD部分の王様、Designオブジェクトにattributes(属性)プロパティが有ります。
help.autodesk.com
ここは、アドイン開発者が自由に属性を設定出来るうえ、ファイルの保存時にも属性が
保存されます。
ここに上記のチェックの状態を保存しておけば、複数コマンドを実行しても
前回の状態を保つことが出来る事が分かりました。

御興味もなかろうと思いますが、こんな処理です。

#FusionAPI_python addin
#Author-kantoku
#Description-俺コマンド(アドイン) 状態を保存するサンプル

import adsk.core, adsk.fusion, traceback

_app = adsk.core.Application.cast(None)
_ui  = adsk.core.UserInterface.cast(None)
_handlers = []

# 俺コマンド情報
_cmdInfo = {
    'id' : 'cmdOre',
    'name' : '俺コマンド',
    'tooltip' : '偉そうにしているが何も出来ない'
    }

# グループコマンドインプット情報
_grpInfo = {
    'id' : 'dlgGrp',
    'name' : '変更して、良し!',
    'value' : True
    }
_grp = adsk.core.GroupCommandInput.cast(None)

# 俺コマンドを追加するパネルのID
_panelId = 'SolidScriptsAddinsPanel'


def run(context):
    ui = None
    try:
        # 色々と使う、ApplicationとuserInterfaceを取得
        global _app, _ui
        _app = adsk.core.Application.get()
        _ui = _app.userInterface

        # -- 俺コマンドを作成するためにcommandDefinitionを作るよ --

        # 今利用出来る全てのコマンドを取得
        cmdDefs :adsk.core.CommandDefinitions = _ui.commandDefinitions

        # 既に同一のIDの俺コマンドが無いか? 確認してみる
        global _cmdInfo
        cmdDef :adsk.core.CommandDefinition = cmdDefs.itemById(_cmdInfo['id'])
        if cmdDef:
            # 見つけたら非情にも消し去る(行儀悪いから良い子はしない)
            cmdDef.deleteMe()

        # commandDefinitionを作る
        # http://help.autodesk.com/view/fusion360/ENU/?guid=GUID-04eb6198-72cd-4430-a6a4-8d68a1105b8e
        cmdDef = cmdDefs.addButtonDefinition(
            _cmdInfo['id'],
            _cmdInfo['name'],
            _cmdInfo['tooltip'])

        # 俺コマンドはイベントを使って産み出す
        # もうおまじないレベル
        # http://help.autodesk.com/view/fusion360/ENU/?guid=GUID-895ee146-8697-4ba0-98e7-4f72b74edb4f
        global _handlers
        onCommandCreated = CommandCreatedHandler()
        cmdDef.commandCreated.add(onCommandCreated)
        _handlers.append(onCommandCreated)


        # -- 俺コマンドを呼び出しやすくする為にパネルに登録するから --

        # 目的のパネル取得
        global _panelId
        targetpanel :adsk.core.ToolbarPanel = _ui.allToolbarPanels.itemById(_panelId)

        # パネル内のコントロール取得
        # あれはコントロールって呼ぶんだな
        controls :adsk.core.ToolbarControls = targetpanel.controls

        # 俺コマンドをパネルに登録
        # https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-1ed0cfb5-2ad4-4285-9eec-484ef19f2729
        cmdControl :adsk.core.ToolbarPanel = controls.addCommand(cmdDef)

        # 俺コマンドを使える状態にするぞ
        # あくまで登録しているだけで、コントロールが押されるまで待機
        cmdControl.isVisible = True
        cmdControl.isPromoted = True
        cmdControl.isPromotedByDefault = True                

    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

# 俺コマンド作成
class CommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            global _app, _ui, _handlers
            cmd = adsk.core.Command.cast(args.command)
            des :adsk.fusion.Design = _app.activeDocument

            # イベント
            onExecute = ExecuteHandler()
            cmd.execute.add(onExecute)
            _handlers.append(onExecute)

            # GroupCommandInputを追加
            global _grpInfo, _grp
            inputs = cmd.commandInputs
            _grp = inputs.addGroupCommandInput(_grpInfo['id'], _grpInfo['name'])
            _grp.isEnabledCheckBoxDisplayed = True

            # チェックの有無をコマンドを前回使用した状態にしたい。
            # その為、Designのattributes(属性)に残しておいたり、読み込むのがお手本みたい。
            # で、探し出す。個人的に、
            # 属性グループ名:コマンドID ,属性パラメータ名:コマンドインプットID
            # と、しておくのが分かりやすいんじゃないかと思っている。
            # https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-5726553F-6473-4045-A5DC-DC6F712CC751
            attr :adsk.core.Attribute = des.attributes.itemByName(
                cmd.parentCommandDefinition.id,
                _grp.id)

            if attr:
                # 属性発見
                _grp.isEnabledCheckBoxChecked = bool(int(attr.value))
            else:
                # 属性見つからん
                _grp.isEnabledCheckBoxChecked = _grpInfo['value']

        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


# 俺コマンド実行 と言っても何もしない・・・けど
# Designのattributes(属性)にダイアログ情報は残したい。
class ExecuteHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        global _ui
        try:
            global _app
            des :adsk.fusion.Design = _app.activeDocument
            cmd = adsk.core.Command.cast(args.command)

            # 属性のvalueは文字のみなのね
            # bool -> in -> str で保存 面倒
            global _grp
            des.attributes.add(
                cmd.parentCommandDefinition.id,
                _grp.id,
                str(int(_grp.isEnabledCheckBoxChecked))
                )
        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))


# 俺コマンド削除
def stop(context):
    try:
        # 全てのパネルを取得
        panels :adsk.core.ToolbarPanels = _ui.allToolbarPanels

        # 俺コマンドの入ったパネル取得
        global _panelId
        panel :adsk.core.ToolbarPanel = panels.itemById(_panelId)

        # 行儀良く、俺コマンドを削除
        global _cmdInfo
        if panel:
            panel.controls.itemById(_cmdInfo['id']).deleteMe()

        # 行儀良く、俺コマンドcmdDefを削除
        cmdDefs :adsk.core.CommandDefinitions = _ui.commandDefinitions
        cmdDef :adsk.core.CommandDefinition = cmdDefs.itemById(_cmdInfo['id'])
        if cmdDef:
            cmdDef.deleteMe()
        
        # 個人的にゴミを残したくないのでDesignのattributes(属性)も削除
        global _app
        des :adsk.fusion.Design = _app.activeDocument
        attrs = des.attributes.itemsByGroup(_cmdInfo['id'])
        [attr.deleteMe() for attr in attrs]

    except:
        print('Failed:\n{}'.format(traceback.format_exc()))

アドインを起動するとここに入ります。
f:id:kandennti:20201222181905p:plain
このコマンドをチェックを入れたり外したりすると、次回も状態を保って起動します。

参考にしたギアのアドインは、属性を保存しっぱなしですが、
俺コマンドは自然に易しいため、アドイン停止時に属性を削除します。

前回のものはパネルの登録等が異常なほど丁寧な処理をしていましたが、
簡素化しています。他にもイロイロと現実的な状態かな?

間違いなく説明不足なのですが、必要な人もいないだろうと思ってます。
(必要だったらコメントください。1カ月ぐらいは覚えているハズ)