2ヶ月ぶりくらいの更新です。子供が夏休みの間、毎朝・毎晩お弁当作りなどの家事炊事に追われておりました。
さて、ここしばらくちょこちょことツイートしてますが、久しぶりにゼロからスクリプト開発しています。数年前に作った検索置換を連続で行うスクリプトを、設計から見直してゼロからまた組んでいる感じです。今日はSUIでつまづいたのでメモとして残しておきます。
先にポエム(ここに至るまでの経緯)、後に解決方法を書いたので、お急ぎの方は「原因と対策」まで飛ばしてください。
この記事での作業環境です。
- InDesign 2020(15.1.3)
- Visual Studio Code(1.60.0)
- ExtendScript Debugger for VSCode(1.1.2)
SUIでSUIImageをボタン代わりに使う経緯
しばらく前にSUIの仕様が大きく変わって(CC2015くらいだったかな)、SUIのIconButtonに角丸の囲みが付くようになりました。これが良いか悪いかはさておき、IconButtonとして使った場合に見た目が非常にダサい。なのでボタンを画像(SUIImage
)として用意して、インタラクションを独自に実装したほうが見栄えはいいのです。
具体的には、SUIImageを利用して画像を表示、イベントリスナーにclickイベントを登録し、画像がクリックされたら画像を差し替えます。これで「ボタンとして押した」風の動作を実装しようとしています。
SUIに画像を表示する
まず画像を2つ用意します。一方が押す前、もう一方が押した後の状態を示します。
押す前の状態の画像をSUIダイアログに貼っつけます。コードは下記。
//@targetengine suiimagetest var mySUIImage = { active: ScriptUI.newImage(File("ファイルパス")), deactive: ScriptUI.newImage(File("ファイルパス")), }; var w = new Window("palette", "SUIImage test"); var btn = w.add('image', undefined, mySUIImage.deactive); w.show();
クリックしたら画像を差し替える
ここに「クリックしたら画像を差し替える」処理を付け足します。
//@targetengine suiimagetest var mySUIImage = { active: ScriptUI.newImage(File("ファイルパス")), deactive: ScriptUI.newImage(File("ファイルパス")), }; var w = new Window("palette", "SUIImage test"); var btn = w.add('image', undefined, mySUIImage.deactive); // ここから追記 btn.isActive = false; btn.addEventListener('click', function() { if (!this.isActive) { this.image = mySUIImage.active; this.isActive = true; } else { this.image = mySUIImage.deactive; this.isActive = false; } }); // 追記ここまで w.show();
InDesignで呼び出してみるとこんな感じ。
おーできてるできてる。
で、この方法だとまだ外部ファイル(画像のpngファイル)がスクリプトと別に必要になるので、これを文字列にして埋め込みます*1。
同じ処理をファイルパスではなくFile.decode()
で行う
//@targetengine suiimagetest // ここを書き換えた var mySUIImage = { active: ScriptUI.newImage(File.decode("%C2%89PNG%0D………")), deactive: ScriptUI.newImage(File.decode("%C2%89PNG%0D………")), }; var w = new Window("palette", "SUIImage test"); var btn = w.add('image', undefined, mySUIImage.deactive); btn.isActive = false; btn.addEventListener('click', function() { if (!this.isActive) { this.image = mySUIImage.active; this.isActive = true; } else { this.image = mySUIImage.deactive; this.isActive = false; } }); w.show();
よーしこれでできたっと!! 動かないじゃーーーん!
原因と対策
原因?
ブレークポイントでスクリプトを止めて、デバッグビューから変数を確認してみます。
本来であれば画像のアイコンあたりにimage
というプロパティが存在するはずなのです*2。
おそらくこれが原因でimage
がうまく差し替わってない?
(ここにたどり着くまでに1時間近く溶かしています)
対策
ということで、じゃぁ事前にimage
プロパティを生やせばいいんでしょ、と。
btn.addEventListener('click', function() { this.image = this.image; // ←ここ! if (!this.isActive) { this.image = mySUIImage.active; this.isActive = true; } else { this.image = mySUIImage.deactive; this.isActive = false; } });
と、これだけではだめでした。ちゃんとこれはScriptUIImage
ですよ、というインスタンス化(ScriptUI.newImage()
メソッド)が改めて必要だった。
(ここにたどり着くまでにさらに1時間弱溶かしています)
解決
これで実装できました。
//@targetengine suiimagetest var mySUIImage = { active: ScriptUI.newImage(File.decode("%C2%89PNG%0D………")), deactive: ScriptUI.newImage(File.decode("%C2%89PNG%0D………")), }; var w = new Window("palette", "SUIImage test"); var btn = w.add('image', undefined, mySUIImage.deactive); btn.isActive = false; btn.addEventListener('click', function() { this.image = ScriptUI.newImage(this.image); // ←おまじない if (!this.isActive) { this.image = mySUIImage.active; this.isActive = true; } else { this.image = mySUIImage.deactive; this.isActive = false; } }); w.show();
余談
ScriptUI.newImage()
メソッドには省略可能な引数が3つあり(JavaScript Toolguide「ScriptUI classの項」を参照)、順に標準時(normal)、利用不可時(disable、省略可)、押下時(pressed、省略可)、ホバー時(rollover、省略可)です。
これらはSUIコントロールのIconButton
に画像を指定する際に有効です。
ただ、今回僕が途中で悩んだように、PNGファイルをテキストとして埋め込む方法ではうまくいきませんでした(今回のように何か抜け道はあるとは思いますが未検証)。
//@targetengine suiimagetest var img = { active: File("ファイルパス"), deactive: File("ファイルパス"), }; var w = new Window("palette", "SUIImage test"); var btn = w.add('iconbutton', undefined, ScriptUI.newImage(img.deactive, undefined, img.active, img.active)); w.show();