| On this page |
概要 ¶
ホットキーを押すとRadialメニューがポップアップ表示されます。 よく使用する項目をこのメニューに割り当てることができます。 さらに、サブメニューを特定の位置に割り当てて、Radialメニューの階層を作成することができます。 これによって、ビューア内で作業する時に指先で多数のツールにアクセスすることができます。
Radialメニューはマウスポインタ下に出現し、大きな標的を用意し、マウスをあまり動かすことがないようにマウスポインタから等距離にすべてのオプションを配置します。 このRadialメニューを使用すれば、ツールに到達する“方向”を学習すれば、最終的にはラベルを読まなくても迅速にそのツールに到達することができます。
Houdiniには、3Dビューアで作業する際に利用可能なデフォルトのRadialメニューが用意されています。 他にも、Radial Menu Editorで独自のRadialメニューを作成して、3DビューアまたはネットワークエディタでのホットキーにそのRadialメニューを割り当てることができます。
現在のところ、Radialメニューは 3Dビューア と ネットワークエディタ で対応しています。
Radialメニューの使い方 ¶
3つの方法でメニューを操作することができます。人によってはインタラクティブスタイルの方が快適なこともあったり、入力デバイスによっては別のスタイルが適切なこともあります。
-
キーを押したまま にするとメニューが表示され、マウスを動かしてメニューアイテムを選択しから キーを離します 。
-
キーをタップ するとメニューが表示され、マウスを動かしてメニューアイテムを選択してから クリック します。
-
キーを押してマウスドラッグを開始 して、マウスを動かしてメニューアイテムを選択してから マウスボタンを離します 。
このスタイルは、今までマーキングメニューを使ってきた場合やタブレットを使用している場合にうまく動作します。
-
その円の中をクリックするか、 ⎋ Escを押してメニューをキャンセルします。
-
メニューが開いている時に テンキー (1-9)を使用することで、マウスを使わずに現在のメニューから別の指示を“選択”することができます。
メニュー作成者は、各メニューアイテムの“ショートカット”キーを指定することもできます。 メニューが表示されている時にそのキーを押すことで、そのメニューからそのメニューアイテムを選択することができます。
デフォルトメニュー ¶
Houdiniには事前に定義されたRadialメニューがいくつか用意されています。
以下のキーを使用することで、 3Dビューア 内で既製のRadialメニューにアクセスすることができます:
キー |
メニュータイプ |
|---|---|
X |
スナップコントロール。 |
C |
“Current”メニュー。
メインインターフェースの上部にある |
V |
ビューコントロール。 |
以下のキーを使用することで、 ネットワークエディタ 内で既製のRadialメニューにアクセスすることができます:
キー |
メニュータイプ |
|---|---|
N |
ナビゲーションコントロール。 |
ホットキーエディタでRadialメニューを他のホットキーに割り当てることができます。
“Current”メニュー ¶
デフォルトで、3Dビューア内でCキーを押すと、“Current” Radialメニューが表示されます。
-
このCキーにCurrentメニューを設定するには、メインインターフェスの上部にある
Radial切り替えメニューをクリックします。
ここには、カーブモデリング用、ポリゴンモデリング用、UV編集用、他のワークフロー用に特別に事前に構築されたメニューが用意されています。
-
通常ではHoudiniにはデスクトップ毎に別々の“Current”メニューを持っています。
例えば、Modelingデスクトップに切り替えると、そのCキーはモデリングツールを含んだメニューを表示します。 汎用的なBuildデスクトップは、全般的に役立つツールをたくさん含んだメニューを持っています。
-
通常ではデスクトップを切り替えると、Houdiniは、そのCキーを、そのデスクトップに関連した独自のRadialメニューに切り替えます。 Radial切り替えメニューを開いて下部にある Pin Current Menu を有効にすることで、デスクトップと連動しないようにCurrent Radialメニューを“ピン留め”することができます。
Radialメニューを管理する方法 ¶
| To... | Do this |
|---|---|
|
|
|
新しいカスタムメニューを作成する |
|
|
Radialメニューをホットキーに割り当てる |
Radialメニューをホットキーに割り当てる方法を参照してください。 |
|
既存のメニューを編集する |
Tip エディタ内で“Current”メニューをすぐに開きたいのであれば、メインインターフェースの上部にある |
Radialメニューを編集する方法 ¶
| To... | Do this |
|---|---|
|
シェルフツールを呼び出すメニュー項目を作成する |
|
|
ノードを作成するメニュー項目を作成する |
|
|
任意のPythonスクリプトを実行するメニュー項目を作成する |
メニュー項目をオン/オフのトグルにしたい場合、 Check on/off タブをクリックして、そのメニュー項目がオンなら 例えば、 # ユーザがこのメニュー項目を呼び出した時に、 # そのトグル状態を反転します。 hou.session.mytoggle = not hou.session.mytoggle …そして、以下のように Check on/off タブを設定します: hou.session.mytoggle is True または単に hou.session.mytoggle Pythonスクリプトの詳細は、PythonによるHoudiniのスクリプティングを参照してください。 |
|
サブメニューを作成する |
|
|
スクリプト制御のサブメニューを作成する |
|
スクリプト制御のRadialメニューの生成方法 ¶
スクリプト制御のメニュー/サブメニューは、ユーザがメニューを開いた瞬間に“その場で”メニューの内容を生成するPythonスクリプトを記述することができます。 これによって、現在の状況に応じて動的に変更されるRadialメニューを作成することができます。
-
このスクリプトは、
kwargsという名前のdictオブジェクトにアクセスすることができます。現在のところ、この辞書には1個の項目が含まれています:-
kwargs["pane"]ユーザがRadialメニューを開いたペインを表現したhou.PaneTabオブジェクト。3Dシーンビューアはhou.SceneViewerオブジェクトです。 このビューアペインは、1つ以上の ビューポート に分割されています。 hou.SceneViewer.curViewportを使用することで現行ビューポートを取得することができます。
-
-
このスクリプトは、表示するメニューを表現したJSONライクな構造を生成します(以下参照)。
-
このスクリプトは、自動的に
radialmenuモジュールにアクセスすることもできます。このスクリプトは、メニューの内容として設定したいメニューデータを使ってradialmenu.setRadialMenu()をコールします。 -
別の方法だと、メニュー構造を構築せずに、メニューの内容を表示したい既存のRadialメニューの名前を使って
setRadialMenu()をコールすることができます。 これによって、既存のメニューを表示するかどうかを動的に選択することができます。例:if someCondition: radialmenu.setRadialMenu("cloth") else: radialmenu.setRadialMenu("polymodel")
-
基本的なメニュー構造は辞書になっていて、キーが径方向を示し、値がその方向でのアイテムまたはサブメニューを記述した辞書です。
def openAnimationEditor(**kwargs): desk = hou.ui.curDesktop() desk.createFloatingPaneTab(hou.paneTabType.ChannelEditor) def openParmEditor(**kwargs): desk = hou.ui.curDesktop() desk.createFloatingPaneTab(hou.paneTabType.Parm) def makeSubMenu(**kwargs): menu = { "se": {"type": "script_action", "script": "hou.ui.displayMessage('Hi!')"} } radialmenu.setRadialMenu(menu) menu = { "n": { "type": "script_action", "label": "Animation Editor", "script": openAnimationEditor, }, "s": { "type": "script_action", "label": "Parameters", "script": openParmEditor, }, "e": { "type": "link", "label": "Cloth", "name": "cloth", } "se": { "type": "script_submenu", "label": "Go To", "script": makeSubMenu, } } radialmenu.setRadialMenu(menu)
(上記のサンプルは、辞書の構造を説明するために意図されたものですが、スクリプト制御のメニューの肝は、何かしらの条件に基づいて内容が変更できることなので、上記で記述しているような文字列どおりの辞書の代わりに、通常ではスクリプト内で辞書を構築することになります。以下のサンプルを参照してください。)
-
径方向を示すキーを色々な方法で指定することができます:
-
0から7までの数字を指定する方法。0は頂上(北)のアイテムで、数字が大きいほど時計回りです。
-
n,ne,e,se,s,sw,w,nwの文字列を指定する方法。 -
north,northeast,east,southeast,south,southwest,west,northwestの文字列を指定する方法。
-
-
各アイテムの辞書には、以下のキーを格納します:
typetypeには、script_action,script_submenu,linkのどれかを指定することができます。以下参照。labelアイテム/サブメニューの人が解読可能なラベルで、Radialメニューに表示されます。
icon(任意)Radialメニュー内のこのアイテムの隣に表示するアイコンの名前またはファイルパス。
shortcut(任意)Radialメニューが表示されている時にこのアイテムを発動するキーを指定します。
-
script_actionタイプアイテムは、ユーザがRadialメニュー内でアイテムを選択した時にスクリプトを実行します。 これは、以下の追加キーを持ちます:scriptユーザがメニュー内でこのアイテムを選択した時に実行するコール可能な関数、または、Pythonコードを含んだ文字列。
現在のところ、このスクリプトは1個のキーワード引数(
pane,hou.PaneTabオブジェクト)でコールされます。 後で私どもがキーワード引数を追加しても関数が壊れないように、あなたの関数が**kwargs(任意の追加キーワード引数)を受け取るように記述しておくと良いでしょう。checkこのキーが存在すれば、そのアイテムのトグルを有効または無効にすることができます。
ここには、コール可能な関数を指定してください。 この関数は、そのアイテムに現在チェックが付いていれば
True、チェックが付いてなければFalseを返すようにしてください。 これは、そのアイテムをRadialメニュー内に“オン”または“オフ”として表示するかどうかを制御します。ユーザインターフェースをすっきりさせるために、メニューアイテムが選択されるとトグルが有効または無効になるように
scriptはそのトグルの状態を変更します。 -
script_submenuタイプアイテムは、ユーザがRadialメニュー内でサブメニューを選択した時にスクリプト制御のサブメニューを生成します。 これは、以下の追加キーを持ちます:scriptコール可能な関数、または、Pythonコードを含んだ文字列。 これは、スクリプト制御のサブメニューの内容を生成します。
現在のところ、このスクリプトは1個のキーワード引数(
pane,hou.PaneTabオブジェクト)でコールされます。 後で私どもがキーワード引数を追加しても関数が壊れないように、あなたの関数が**kwargs(任意の追加キーワード引数)を受け取るように記述しておくと良いでしょう。 -
linkタイプアイテムは、ユーザがRadialメニュー内でサブメニューを選択した時に既存のRadialメニューをサブメニューとして表示します。 これは、以下の追加キーを持ちます:nameサブメニューが選択された時に表示するそのサブメニューの内部名を含んだ文字列。
Tip
linkアイテム内にlabelキーを指定しなかった場合、リンク先のメニューのラベルが使用されます。labelキーを指定した場合、そのラベルが代わりに表示されます。
スクリプト制御のメニューのサンプル ¶
このスクリプトは、直近で編集された8個のLight LOPsを表示するメニューを生成します。 それらのLight LOPsのどれかを選択すると、そのLight LOPが選択されます。
# まず最初に基本方位(N, S, E, W)を入力してから、対角方位を入力します。 slots = ("n", "s", "e", "w", "ne", "se", "nw", "sw") light_types = ("light", "distantlight", "domelight") lop_category = hou.nodeTypeCategories()["Lop"] lights = [] for light_type in light_types: # ノードタイプオブジェクトを取得します。 nodetype = hou.nodeType(lop_category, light_type) # このノードタイプのインスタンスを検索して、それらのインスタンスをリストに追加します。 lights.extend(nodetype.instances()) # 最後に編集された時間でLight LOPsのリストをソートします(直近で編集されたLOPが最初になるように並びを逆にします)。 lights.sort(key=lambda n: n.modificationTime(), reverse=True) # 直近の8個のLight LOPsからメニューを構築します。 menu = {} for slot, light in zip(slots, lights[:8]): menu[slot] = { "type": "script_action", "label": light.name(), "icon": light.type().icon(), "script": lambda n=light, **kwargs: n.setCurrent(True, clear_all_selected=True) } radialmenu.setRadialMenu(menu)
Tip
Pythonの残念な“落とし穴”は、lambdaまたはローカル関数でループ変数の値を取得しようとすると、期待した値が得られないことです。例:
for i, light in enumerate(lights):
menu[slot] = {"script": lambda **kwargs: light.setCurrent(True)}
あなたが期待していたのは、ループで定義された各lambdaがそのループの反復時点でのLight LOPの参照を持っていることだったのではないでしょうか。 しかし、Pythonが行なっている事は そうではありません 。
代わりにlambdaはlightのLexical参照(字句参照)を取得します。
これは、ローカルコンテキストでの変数の 現行 値を常に指しています。
つまり、ループの最後では、生成されたlambdaのすべてのlight参照は、同じであり、lightの 最終 値(リスト内の最後の値)を指します。
サンプルのスクリプトで言えば、すべてのアイテムがまったく同じノード(リスト内の最後のノード)を選択することを意味します。
下記のサンプルで示しているとおり、簡単な回避策は、取得したい変数をキーワード引数としてlambdaに渡すことです:
for i, light in enumerate(lights):
menu[slot] = {"script": lambda n=light, **kwargs: n.setCurrent(True)}
別の方法としては、コール元のループとは別の独自のコンテキスト内で変数を取得する別の“ラッパー”関数をコールすることです:
def makeSelectFn(light):
# コールされると、指定したライトを選択する関数を返します。
def wrapper(**kwargs):
light.setCurrent(True)
return wrapper
for i, light in enumerate(lights):
menu[slot] = {"script": makeSelectFn(light)}
Tipsとメモ ¶
-
Radialメニューショートカットを使用することで、スクリプトを ホットキーシーケンス に割り当てることができます。
例えば、Radialメニューを作成することができます。
-
メニューに8個未満の項目しかない場合、その“隙間”の隣の項目の“ヒット領域”が、その隙間を埋めるために大きくなります。つまり、項目の少ないメニューの方が、それらの項目をヒットしやすくなります。
-
hou.SceneViewer.displayRadialMenuを使ってプログラム的にメニューを表示させることができます。このメニューはマウスポイント下で開かれます。