マクロ スクリプトの定義

 

   

ユーザ インタフェースの作成 - クイック ナビゲーション

マクロ スクリプトは、[ユーザ インタフェースをカスタマイズ](Customize User Interface)の ActionItem(ツールバー ボタン、メニューまたはクアッド メニューの項目、キーボード ショートカット)に関連付けられたスクリプトで、対応する ActionItem が呼び出されたときに実行されます。

マクロ スクリプトは macroScript 定義構文で定義する必要があります。その後ショートカット ツールバーまたは[タブ](Tab)をマウスの右ボタンでクリックして[カスタマイズ](Customize)を選択すると、ツールバー ボタンに関連付けることができます。コマンド ショートカット(ホットキー)またはマクロ スクリプトのいずれかを選択できる、[ユーザ インタフェースをカスタマイズ](Customize User Interface)ダイアログ ボックスが表示されます。マクロ スクリプトは、基本的には名前とカテゴリを持ち、オプションとしてツールチップとアイコンを持つ MAXScript コードです。

マクロ スクリプトはユーザ インタフェース項目を自動的には作成しません。マクロ スクリプトでダイアログ ボックスを表示する場合は、「ロールアウト フロータ ウィンドウ」に記述されているようにロールアウト フロータ ウィンドウおよびロールアウトを作成する必要があります。また、「ロールアウト ユーザ インタフェース コントロール」に記述されているようにロールアウト内にユーザ インタフェース項目を作成し、インストールする必要があります。

MacroScript は次の構文を使用して定義します。

macroScript <name> 
[category:<string>] 
[buttonText:<string>] 
[toolTip:<string>] 
[icon:#(<string>, <index>)] 
[silentErrors:<boolean>] 
[autoUndoEnabled:boolean>] 
(<macro_script_body>)

例:

macroScript Free_Camera category:"Cameras" tooltip:"Free Camera"
Icon:#("Cameras",2)
(
  StartObjectCreation FreeCamera
)
macroScript Target_Camera category:"Cameras"
tooltip:"Targeted Camera" Icon:#("Cameras",1)
(
  StartObjectCreation TargetCamera
)

3ds Max 2011 以降、MacroScript 定義の名前プロパティを定義する文字列は、定義がディルデで囲まれているローカライズされたリソース文字列で置き換えることができます。 リソース文字列の置換 for

MAXScript が macroScript 構文を評価し終えると、[ユーザ インタフェースをカスタマイズ](Customize User-Interface)ダイアログ ボックスの該当するカテゴリにマクロ スクリプト定義が表示されます。次の図は、上記の 2 つのマクロ スクリプトを含む[ユーザ インタフェースをカスタマイズ](Customize User Interface)ダイアログ ボックスです。

ツールチップを指定した場合、そのツールチップが[ユーザ インタフェースをカスタマイズ](Customize User Interface)ダイアログ ボックスに表示される名前になります。ツールチップを指定しない場合は、<name> が表示される名前になります。他の類似構文(スクリプト ユーティリティ、関数、右クリック メニュー)とは異なり、 macroScript はこの名前を使った変数を作成しません。マクロ スクリプトは、次に説明するようにポインタとしてファイルに保存されます。

注:

英数字以外の文字を使用して、すべての引数文字列を定義できます。これには、エスケープ シーケンスを使用した二重引用符(¥") のサポートも含まれます。

category: 引数では、マクロ スクリプト名がリストされる[ユーザ インタフェースをカスタマイズ](Customize User-Interface)ダイアログ ボックス内のカテゴリを指定します。カテゴリを使用するのは、マクロ スクリプトのグループを編成してマクロ スクリプト名がクラッシュしにくくするためです。カテゴリが指定されていない場合、既定値のカテゴリ「unknown」が使われます。

internalCategory 引数は、.cui.mnu、および .kbd ファイルでの演算を識別します。

toolTip: 引数では、ボタンのツールチップを指定します。ツールチップが指定されていない場合、そのボタンには <name> が表示されます。

buttonText: 引数では、ボタン内に表示するテキストを指定します。また、 icon: 引数ではボタン内に表示するアイコンを指定します。[ユーザ インタフェースをカスタマイズ](Customize User Interface)ダイアログ ボックスで、 buttonText または icon のどちらをボタンに表示するかを選択できます。 buttonText: 引数が指定されていない場合、マクロ スクリプト名が buttonText として使用されます。

icon: 引数には、アイコンのビットマップ ファイル、およびアイコン ビットマップ ファイルのアイコン イメージを指定します。アイコンのビットマップ ファイルは、現在の 3ds Max ユーザ インタフェース ディレクトリに格納されている必要があります。アイコン ビットマップ ファイルの名前には、基本名(「MyToolbar」など)の後に、個別のアイコン サイズおよびアイコン ビットマップ ファイル タイプを指定するサフィックス(「_24i.bmp」など)が続きます。 icon: 引数の文字列は、拡張子がない基本名だけです。この基本名は、[ユーザ インタフェースをカスタマイズ](Customize User-Interface)ダイアログ ボックスの[イメージ グループ](Image Group)ドロップダウン リストに表示される名前です。アイコン ビットマップ ファイルには、個別のアイコンをいくつでも含めることができ、アイコンは整列して保存されます。アイコン ビットマップ ファイルに複数のアイコンが含まれる場合、<index> は使用するアイコン ビットマップ ファイル内のアイコンを指定します。左端のアイコンには、1 の <index> が付いています。3ds Max 内部アイコン([ユーザ インタフェースをカスタマイズ](Customize User-Interface)ダイアログ ボックス内の[内部イメージ グループ](Image Group Internal))は、アイコン ファイルに格納されていません。したがって、3ds Max 内部アイコンは、 icon: 引数として空の文字列を使用して参照されます。

このため、 icon: 引数は、アイコンのビットマップ ファイルの基本名の文字列と、このファイル内のアイコン インデックスを含む 2 つの要素からなる配列か、あるいはアイコンのインデックスが 1 であることを前提とした基本名の文字列だけになります。

例:

macroScript Box category:"Objects" tooltip:"Box"
icon:#("standard", 1) -- use first icon in standard
(
  StartObjectCreation Box
)
macroScript Sphere category:"Objects" tooltip:"Sphere"
icon:#("", 2) -- use second icon in internal icons
(
  StartObjectCreation Sphere
)
macroScript Cone category:"Objects" tooltip:"Cone"
icon:"myicon" -- use first icon in myicon
(
  StartObjectCreation Cone
)

詳細は、「アイコン ビットマップ ファイルの作成」を参照してください。

silentErrors: パラメータにより、マクロ スクリプトの実行中に MAXScript のランタイム エラー メッセージを表示するかどうかを指定します。このパラメータを True に設定すると、エラー メッセージは表示されなくなります。これは、MAXScript エラー メッセージによってユーザが混乱するかもしれないマクロ スクリプトが配布された場合に使用すると便利です。既定値は False です。

autoUndoEnabled: パラメータは、マクロ スクリプトの本体を自動的に theHold begin/accept 呼び出しに内部的にラップするかどうかをコントロールします。

False に設定すると、マクロ スクリプトの本体の実行でマクロ スクリプト全体の undo レコードは生成されません。

True に設定するか、指定しなかった場合、実行時にマクロ スクリプトの本体全体で 1 つの undo レコードが作成されます。

既定値は true です。

3ds Max 2010 以降で使用可能です。

例:

MacroScript MacroScript_autoUndoEnabled_test1
category:"MacroScript_autoUndoEnabled_test"
buttontext:"test1"
autoUndoEnabled:false
(
  format "test1\n"
  format "expecting theHold.holding == false, got: %\n" (theHold.holding())
  format "expecting theHold.IsSuspended == false, got: %\n" (theHold.IsSuspended())
  format "expecting theHold.Restoring == false, got: %\n" (theHold.Restoring())
  format "expecting theHold.Redoing == false, got: %\n" (theHold.Redoing())
  format "expecting theHold.RestoreOrRedoing == false, got: %\n" (theHold.RestoreOrRedoing())
  format "expecting theHold.SuperLevel == 0, got: %\n" (theHold.SuperLevel())
)

<macro_script_body> は 2 つの形式のいずれかになります。

本体は単一の MAXScript 式か、一連のイベント ハンドラのいずれかになります。

<event_handler> は、3ds Max により生成したイベントを扱うマクロ スクリプトに対してローカルな特別関数定義です。

   

有効な <event_name> は次のとおりです。

on isChecked do <expr>   

<expr> が True を返し、マクロ スクリプト項目がメニューまたはクアッド メニューにある場合、マクロ スクリプト項目の横にチェック マークが表示されます。マクロ スクリプトがツールバーのボタンの場合、ボタンは「押された状態」で表示されます。 do はこのイベント ハンドラのオプションです。このイベント ハンドラが指定されていない場合、項目はオンにはなっていません。

   

on isIndeterminate do <expr>   

<expr> が True を返し、マクロ スクリプト項目がメニューまたはクアッド メニューにある場合、マクロ スクリプト項目の横に水平ダッシュ記号が表示されます。マクロ スクリプトがツールバーのボタンの場合、ハンドラの効果はありません。 isChecked が False を返した場合でも、このハンドラが on isChecked do ハンドラから独立し、不確定な記号を設定します。

3ds Max 2015 以降で使用可能です。

   

on isEnabled do <expr> 

<expr> が False を返し、マクロ スクリプト項目がメニューまたはクアッド メニューにある場合、マクロ スクリプト項目はメニューまたはクアッド メニューに表示されません。マクロ スクリプトがツールバーのボタンの場合、ボタンは使用不可能になっています。 do はこのイベント ハンドラのオプションです。このイベント ハンドラが指定されていない場合、項目は使用可能になります。

   

on isVisible do <expr> 

<expr> が False を返し、マクロ スクリプト項目がメニューまたはクアッド メニューにある場合、マクロ スクリプト項目はメニューまたはクアッド メニューに表示されません。マクロス クリプトがツールバーのボタンの場合、ハンドラの影響はありません。 do はこのイベント ハンドラのオプションです。このイベント ハンドラが指定されていない場合、項目が表示されます。

   

on execute do <expr> 

メニューまたはクアッド メニューの項目が選択されたとき、またはツールバーのボタンがクリックされたときに、評価される式です。このイベント ハンドラが指定されていない場合は、ランタイム エラーが発生します。

スクリプト:

macroScript Free_Camera
category:"Lights and Cameras"
internalcategory:"Lights and Cameras"
tooltip:"Free Camera"
buttontext:"Free Camera"
Icon:#("Cameras",2)
(
  on execute do StartObjectCreation FreeCamera
  on isChecked return (mcrUtils.IsCreating FreeCamera)
)

スクリプト:

macroScript SubObject_Vertex
buttonText:"Vertex"
category:"Modifier Stack"
internalCategory:"Modifier Stack"
tooltip:"Vertex Sub-object Mode"
icon:#("SubObjectIcons",1)
(
  on isChecked do (subObjectLevel == 1 and filters.canSwitchTo_Vertex())
  on isEnabled do Filters.canSwitchTo_Vertex()
  on isVisible do Filters.canSwitchTo_Vertex()
  on execute do
  (
    if subObjectLevel == undefined then max modify mode
    if subObjectLevel != 1 then subObjectLevel = 1 else subObjectLevel = 0
  )
)

   

on altExecute <type> do <expr> 

マクロ スクリプトが altExecute イベント ハンドラを実装している場合、マクロ スクリプトに対応するクアッド メニュー項目に、マウス アイコン(濃いクリック ボタン)が表示されます。このアイコンをクリックすると、 <type> #default に設定して、イベント ハンドラが実行されます。

たとえば、次のスクリプトにより、標準の[ワイヤ パラメータ](Wire Parameters)クアッド メニューに、別の実行機能が追加されます。アイコンをクリックすると、[ワイヤリング](Wiring)モードに変更する代わりに、[パラメータ ワイヤリング エディタ](Param Wiring Editor)が表示されます。

スクリプト:

macroScript paramWire
category:"Parameter Wire"
internalcategory:"Parameter Wire"
buttonText:"Wire Parameters"
tooltip:"Start Parameter Wiring"
Icon:#("MAXScript" ,1)
(
  on isEnabled return selection.count == 1
  on execute do(paramWire.start())
  on altExecute type do
  (
    paramWire.OpenEditor()
  )
)

   

on closeDialogs do <expr> 

closeDialogs は、 isChecked ハンドラが True を返す(ボタン/アイコン/アイテムがチェックされる)たびに、 on Execute ハンドラの代わりに呼び出されるハンドラです。未チェック状態に切り替え直すのに使用することもできます。ハンドラには開いたダイアログを閉じる任意のクリーンアップ コードを実装し、基本的にはマクロ スクリプトを実行前の状態に戻しておきます。

注: closeDialogs ハンドラは、 isChecked ハンドラが存在するかどうかに依存します。 isChecked ハンドラを定義せずに on closeDialogs ハンドラを定義すると、コンパイル時にエラーが発生します。

次に、ロールアウトのオンとオフを切り替えるマクロ スクリプトのテストを示します。

スクリプト:

macroScript testCloseDialogs category:"MXS Help"
(
rollout testCloseRollout "Test" --define a rollout
(
label lb_test "testing CloseDialogs handler..."
)
on isChecked do testCloseRollout.open --return true if rollout is open --if isChecked returns false (the rollout is not open in a dialog), --the on execute handler will be called and will create the dialog.

on execute do createDialog testCloseRollout

  --If isChecked returns true and the user pressed the button again, --instead of calling the on execute handler, the macroScript will call --the on closeDialogs handler and destroy the dialog.

on closeDialogs do destroyDialog testCloseRollout
)

  --If you drag the macroScript to a toolbar and click the button, --a dialog should appear and the button should be checked. --Click it again and the dialog will disappear. --Repeat as often as you want - the dialog will be toggled on and off! 

   

on droppable <window> node:point:do... 

   

on drop <window> node:point:do... 

これらオプションの MacroScript イベント ハンドラを使って、i-Drop 技術とともに使用できる、いわゆる DropScript を定義することができます。詳細は、「DropScrip イベント」を参照してください。

<macro_script_body> は、グローバル変数とローカル変数の両方、関数、および構造の定義を含めることができます。 <macro_script_body > は独自のローカル スコープでコンパイルされ、ローカルはマクロ スクリプトのスコープ内だけで可視です。マクロ スクリプト ローカルは、通常の(スタック ベースの)ローカルと多少異なるヒープ ベースのローカルです。

通常のローカルは現在のスコープ内で可視であり、そのスコープの実行が終了するまでの寿命があります。ヒープ ベースのローカルは、現在のスコープ内でのみ可視となっていますが、寿命はこのローカルが定義されているトップ レベルの式の寿命と同じです。マクロ スクリプトのローカルは、マクロ スクリプトが初めて実行されるときに作成され、 undefined 値あるいは指定された初期値に初期化されます。これらの値は、別個のメモリ スタックに保存されます。マクロ スクリプトの各関数(またはトップ レベル スクリプト)のエントリ時にメモリ スタック内の「フレーム」がマークされます。また、関数(またはトップ レベル スクリプト)の終了時に、フレーム内のすべての値がメモリから解放されます。

マクロ スクリプトの名前は変数として作成されないため、マクロ スクリプトのスコープ外にあるマクロ スクリプトのローカルにはアクセスできません。たとえば、マクロ スクリプト内でロールアウトを作成することができ、ロールアウトのイベント ハンドラはマクロ スクリプト内で定義されたローカルにアクセスできます。これは、ロールアウトはマクロ スクリプトのスコープ内で実行されているためです。ただし、マクロ スクリプトのローカルはマクロ スクリプトのスコープ内から実行されていないため、別のユーティリティやリスナーからはアクセスできません。詳細については、「変数のスコープ」を参照してください。

macroScript 定義を実行すると、戻り値は整数 マクロ スクリプト ID 値になります。MacroScript は、各マクロ スクリプトについての情報を内部の配列に保存します。返されるマクロ スクリプト ID 値は、そのマクロ スクリプトの配列インデックスです。各マクロ スクリプト用に保存される情報は、マクロ スクリプトが定義されているファイルおよび macroScript 定義の始まり位置を指定するファイルへのポインタから構成されています。MacroScript 定義は、スクリプトを含むツールバー ボタンを初めて押すとき、または macros.run() メソッドを使用してマクロ スクリプトを実行するときにのみ、コンパイルされます。

マクロ スクリプトを定義する 5 つの方法

ロードされているマクロ スクリプト定義を含むファイルを移動または削除した後で、マクロ スクリプトを実行しようとすると、エラー メッセージが表示されます。さらに、マクロ スクリプト定義を含むファイルを編集した場合、そのファイル内で定義されている他のマクロ スクリプトのファイル ポインタが更新されるよう、ファイル全体を保存して再評価してください。この操作を行わない場合、現在ロードされている定義はファイル内容と一致しないというエラー メッセージが発生します。

マクロ スクリプト定義を再評価する場合、そのマクロ スクリプトを使用するボタンに変更が反映されます。

MAXScript で評価された、またはツールバーにテキストをドロップすることによって作成された macroScript 定義には独立した定義 .mcr ファイルがあります。このファイルは、現在のユーザ インタフェース ディレクトリの下にある MacroScripts ディレクトリ(通常は UI¥MacroScripts )に作成されます。ファイルの名前は、<category_name>-<macro_name>.mcr となります。

例:

 
DragAndDrop-Macro12.mcr
 for macroScript Macro12 category:"DragAndDrop" 
NURBS-Map_Updater.mcr
 for macroScript Map_Updater category:"NURBS" 

[リスナー](Listener) で macroScript 定義を評価する場合、またはツールバーにテキストをドロップする場合、記録される定義ファイルは UI¥MacroScripts 内のこの補助ファイルです。この定義ファイルは、[ユーザ インタフェースをカスタマイズ](CUI customize)メニューまたはダイアログ ボックスの[マクロ スクリプトを編集](Edit MacroScript)をクリックすると表示されます。macroScript 定義が[リスナー](Listener)で評価される場合、補助ファイルが評価ごとに個別に作成されるのではなく、同一の定義が評価のたびに更新されます。

UI\MacroScripts ディレクトリに存在しない .ms ファイルまたは .mcr ファイルの macroScript 定義を評価する場合、UI¥MacroScripts の独立したファイルにそれぞれのコピーが格納されます。ただし、記録されている定義ファイルは元のソース ファイルなので、[マクロ スクリプトを編集](Edit MacroScript)をクリックすると、そのファイルが表示されます。

つまり、このような macroScript 定義を含むボタンが startup.cui ファイルのツールバーに追加される場合、3ds Max の次回起動時には UI¥MacroScripts の補助 .mcr ファイルが定義として使用されます。3ds Max を起動すると、UI¥MacroScripts の補助ファイルから macroScript 定義が取得されます。これらのマクロ スクリプトも MAXScript スタートアップ スクリプト ファイルに定義されている場合、これらは MAXScript の起動時に再定義され、記録されている定義ファイルがそのスクリプト ファイルを示すように更新されます。

マクロ スクリプトへのアクセス:

MAXScript では、スクリプト内からマクロ スクリプトにアクセスして実行できるいくつかのメソッドが提供されています。これらのマクロ スクリプト関数は、 macros という名前の付いた構造パッケージに入っています。使用できるメソッドの詳細については、「マクロ スクリプト」を参照してください。

次のマクロ スクリプト では、RAMPlayer に直接レンダリングできます。このマクロ スクリプトでは、マクロ スクリプトで使われるロールアウトとロールアウト フロータの使用方法を示します。

スクリプト:

-- MacroScript to Render to RamPlayer
-- Author: Alexander Bicalho
--****************************************************************
-- MODIFY THIS AT YOUR OWN RISK
-- This utility will allow you to render directly to the RamPlayer

MacroScript RAM_Render category:"Tools" tooltip:"Render to Ram"
(
--declare local variables and define some functions
local r_dialogue
local get_names existFile
function get_names name a = append a name
function existFile fname = (getfiles fname).count != 0
--create the rollout definition
rollout r_size"Render Parameters"
(
local p = 95
local p2 = p+78
group "Time Output"
(
radiobuttons r_time columns:1 align:#left labels:#("Single","Active Time Segment","Range:" )
spinner nth "Every Nth Frame:" pos:[215,24] fieldwidth:50 type:#integer range:[0,10000,1] enabled:false
spinner r_from fieldwidth:60 pos:[75,56] type:#integer range:[0,10000,1] enabled:false
spinner r_to "To:" fieldwidth:60 pos:[152,56] type:#integer range:[0,10000,100] enabled:false
)
group "Render Size"
(
spinner rw "Width " fieldwidth:60 pos:[15,p+08] type:#integer range:[0,10000,320]
spinner rh "Height " fieldwidth:60 pos:[12,p+32] type:#integer range:[0,10000,240]
spinner aspect "Aspect " fieldwidth:60 pos:[10,p+56] type:#float range:[0,20,1.0]
button s160 "160x120" pos:[125,p+06] width:75 height:19
button s256 "256x243" pos:[125,p+30] width:75 height:19
button s320 "320x240" pos:[205,p+06] width:75 height:19
button s512 "512x486" pos:[205,p+30] width:75 height:19
button s640 "640x480" pos:[285,p+06] width:75 height:19
button s720 "720x486" pos:[285,p+30] width:75 height:19
button conf_render "Configure" pos:[125,p+54] width:115 height:19
button wipe "Purge Files" pos:[245,p+54] width:115 height:19
button go "Render" pos:[125,p+78] width:235 height:19
)
label abt0 "Render to RAM" pos:[8,p2+31]
label abt1 "Version 0.2a" pos:[8,p2+46]
label abt2 "Alexander Esppeschit Bicalho" pos:[225,p2+31]
label abt3 "abicalho@brasilmail.com" pos:[249,p2+46]
--define the rollout event handlers
on wipe pressed do
(
local tempfilename_a = (getdir #image) + "\\ramplayertemp_a.avi"
local tempfilename_b = (getdir #image) + "\\ramplayertemp_b.avi"
if existfile tempfilename_a then deletefile tempfilename_a
if existfile tempfilename_b then deletefile tempfilename_b
)
on r_time changed state do
(
case state of
(
1: nth.enabled = r_from.enabled = r_to.enabled = false
2: (
nth.enabled = true
r_from.enabled = r_to.enabled = false
)
3: nth.enabled = r_from.enabled = r_to.enabled = true
)
)
on s160 pressed do (rw.value=160; rh.value=120; aspect.value=1.0)
on s320 pressed do (rw.value=320; rh.value=240; aspect.value=1.0)
on s256 pressed do (rw.value=256; rh.value=243; aspect.value=1.266)
on s512 pressed do (rw.value=512; rh.value=486; aspect.value=1.266)
on s640 pressed do (rw.value=640; rh.value=480; aspect.value=1.0)
on s720 pressed do (rw.value=720; rh.value=486; aspect.value=0.9)
on conf_render pressed do (max render scene)
on go pressed do
(
local tempfilename_a = (getdir #image) + "\\ramplayertemp_a.avi"
local tempfilename_b = (getdir #image) + "\\ramplayertemp_b.avi"
if existfile tempfilename_b then
(
deletefile tempfilename_a
copyfile tempfilename_b tempfilename_a
tempfilename = tempfilename_b
)
else
(
if existfile tempfilename_a then
tempfilename = tempfilename_b
else
(
tempfilename = tempfilename_a
tempfilename_b = ""
)
)
case r_time.state of
(
1: ( render outputheight:rh.value outputwidth:rw.value pixelaspect:aspect.value outputfile:tempfilename vfb:off)
2: ( render outputheight:rh.value outputwidth:rw.value pixelaspect:aspect.value outputfile:tempfilename vfb:off nthframe:nth.value framerange:#active )
3: ( render outputheight:rh.value outputwidth:rw.value pixelaspect:aspect.value outputfile:tempfilename vfb:off nthframe:nth.value fromframe:r_from.value toframe:r_to.value )
)
ramplayer tempfilename_a tempfilename_b
closerolloutfloater r_dialogue
)--end of on go pressed
)--end of rollout r_size
--close the old rollout floater if it exists
try(closerolloutfloater r_dialogue)catch()
--put up new rollout floater and add rollout to it.
r_dialogue = newrolloutfloater "Render to RAM" 400 300
addrollout r_size r_dialogue
--end of MacroScript, rollout takes over...
)

関連事項