Developer wiki > Code Doc. > context の訳のような何か
これ↓の意訳というには問題がありそうな、便乗して書いた何か (画像も違う)
Context
context をより明示的にするため、Blender 2.5 で bContext 構造体が追加された。適切な context の中では、オペレーター/python スクリプト/描画処理のコードを常に機能させることができる。
context は bContext構造体として表現され、関連する APIは BKE_context.h で定義されている。
-
context の要素の呼び出し:
ほとんどの場合、bContext を引数として関数CTX_data_*
やCTX_wm_ *
を呼び出す。 -
context の要素の設定:
要素が呼ばれたとき、screen や area、region で定義されたコールバック関数によって設定される。
What's in the context?
コードの種類に応じた、アクセスする context の持ち主
User Preferences
全てのコードは User Preferences が設定する context の要素にアクセスする。
このデータは Blender のどんな状態でも存在し、本来の意味の"context"ではない。
Main
全てのコードは Main が設定する context の要素にアクセスする。
これは blendファイルであり、 それ自身のデータブロックと、他の blend ファイルからリンクされているデータブロックを含んでいる。
Window Manager
(元ページの図ではわかりにくいが、実際には"window manager"というデータの持ち主がいるわけではなく、wm.screen
, wm.area
, wm.region
の3つに分離して存在している、はず)
-
Window Manager の context にアクセスするコード:drawing と operator のコード
これらのコードは window manager が設定する context の要素に基づいて処理を行う。window manager による実際の context の設定は、screen、area、 region のうちのそれぞれの階層において行われている。この3つの階層は固有のデータ、例えば screen はアクティブな Scene のデータ、area や region は何らかの Data を持っており、それぞれが自分の持つデータを context に追加する。 -
Window Manager の context にアクセスしないコード:Evaluation と レンダリング のコード
window manager が設定する context にアクセスしないコードを書くこともできる。これらのコードは、window の設定のないバックグラウンドでの起動時でも実行することが可能で、例えばレンダリングのために利用できる。レンダリングやモディファイアやコンストレイントなどの Evaluation では、scene やその他の data が必要になるが、上記のようなバックグラウンドでの実行を想定する場合は、 context にアクセスする以外の方法でこれらのデータを取得するべきである。
その他
ファイルの読み取りと書き込み、カーネルの様々な機能、window manager のコードがある。一般的に、これらの処理は context の極一部しか必要としない、あるいは context を全く必要としない。
Setting Context
context は永続的ではなく、呼び出しに応じて作成されるもので、operator や drawing の処理が実行された時点での「一時的で局所的な状態」である。
アクティブオブジェクトを変更する場合を考えてみる
-
context.active_object
を変更することができても、アクティブオブジェクトは変更されない -
ViewLayer.objects.active
を変更することで、アクティブオブジェクトは変更される
→ その後でcontext.active_object
を呼ぶと、新しいアクティブオブジェクトが取得できる
つまり、context とは、
- ユーザーがあちこちにアクセスする手間を省くために、実際にデータを管理している部分から必要な情報を収集し、ひとまとめにして提供するもの
- 予め作成しておいて随時更新するのではなく、必要になったときに情報を集めて作成される
Callback
context の多くの要素は、screen, space, region が持つコールバック関数xx_context()
で設定される。
static int image_context(const bContext *C, const char *member, bContextDataResult *result)
この関数の3つの引数は、以下のように利用される(はず)
-
C
:大元のデータの持ち主(この場合は SpaceImageEditor)を取得するために利用 -
member
:context に追加することが要求されている要素(メンバ)の名前 -
result
:コールバック関数の様々な処理の結果を格納するもの
コールバック関数における処理は、
- 要求されている context の要素(
member
)が、その関数が設定を担当する要素であるか確認する - 担当する要素であった場合は、RNA ポインタあるいはコレクションを
result
に代入する
コードともう少し詳しめの説明 (正確性は全く保証しない)
static int image_context(const bContext *C, const char *member, bContextDataResult *result)
{
SpaceImage *sima= CTX_wm_space_image(C);
if(CTX_data_dir(member)) {
static const char *dir[] = {"edit_image", NULL};
CTX_data_dir_set(result, dir);
}
else if(CTX_data_equals(member, "edit_image")) {
CTX_data_id_pointer_set(result, (ID*)ED_space_image(sima));
return 1;
}
return 0;
}
ポインタ/実体の違い は、ここでは無視
-
CTX_wm_space_image
によって、C
から SpaceImageEditor のデータを取得 -
CTX_data_dir
によってmember
が空文字列がどうか判定- 空文字列ならば、
result.dir
に{"edit_image", NULL}
を代入し、処理を終える
(→C.edit_image = None
)
- 空文字列ならば、
- 空文字列でないならば、
CTX_data_equals
によって、member
が"edit_image"
かどうかを判定 - True ならば、
ED_space_image
で Space から Imageのデータを取得し、CTX_data_id_pointer_set
でそのRNAポインタをresult.ptr
に代入し、処理を終える
(→C.edit_image = SpaceImageEditor で開いている画像
) - どの条件にも合致しない、つまり
member
が画像エディタとは無関係な文字列のときは、なにもせず終了
(→C.edit_image
自体が作成されない)
コメント:member
が空文字列 → C.edit_image = None
は直感的でない
そもそも空文字列のmember
を渡すときってどんなとき? 要確認
UILayout
UIレイアウトでは、bpy.types.UILayout.set_context_pointer
を利用してユーザーが context の要素を設定することで、特定のデータへのアクセス手段を確保することができる。
def draw(self, context):
box = self.layout.box()
box.set_context_pointer("modifier", 特定のモディファイア)
box.operator(何かのオペレータ)
上記のコードを実行すると、このボックス内で設定されるオペレータでは、context.modifier
を使うことでこのモディファイアのデータにアクセスすることができる。
Lookups
context を設定する担当者の間で、順番に context の要素が検索される
operator や drawing の処理で context の要素xx
が要求されたとき、以下の順で確認が行われる。
- UIレイアウトの context の要素に
xx
が含まれる? -
xx
は、region のコールバック関数が設定する context の要素? -
xx
は、area のコールバック関数が設定する context の要素? -
xx
は、screen のコールバック関数が設定する context の要素?
-
xx
を設定する担当者が存在すれば、そこでxx
が設定され結果が返される。 - どの部分でも
xx
が設定されなければ、NULLポインタあるいは空のコレクションが返される。
したがって、もし異なる階層で同じ名前の context の要素が設定される場合、より下の階層の設定するデータが返り値となる。
コメントとか
UIレイアウトの context ってなに? Buttons のこと?
Getting Context
Window Manager
window manager に関する context の要素は、screen, are, space data, region/region data への単なるポインタである。
これらは data に関する context を設定する起点となるので、コードでは、これらの要素が context 内に実際に存在することを確認する必要がある。
- drawing のコード:処理が呼ばれたときにこれらが存在することは明白で、確認する必要はない
- operator のコード:poll()関数の中や処理の実行時の最初の時点で確認する必要がある。
この確認を怠ると、ユーザーが独自のキーマップを使い想定されていない場所で operator を呼び出した場合、Blender がクラッシュする可能性がある。
Data
Data に関する context の要素はRNAポインタとコレクションである。
C では、context からデータを取得するために呼び出す関数として、2種類が存在する。
- 要素に対応して定義されたアクセサ関数:
CTX_data_edit_object
のようなもの - 文字列を用いて context のメンバを検索する方法:
CTX_data_pointer_get_type(C, "edit_object", &RNA_Object).data
のようなもの
(CTX_data_pointer_get_type
の返り値は PointerRNA なので、.data
を使ってデータにアクセスする)
2 の方法は、得られたデータの型が適正であることは保証されない。そのため、必要な型の情報(例では&RNA_Object
)も指定することが望ましい。
Where to Look
context の要素を調べるには、それを設定するコールバック関数を確認するのが最善である。例えば、画像ウィンドウに関しては、 space_image.c で定義されているコールバック関数を調べれば良い。
Pythonでは、print(dir(context))
を実行することで、その時点の context の内容を確認できる。
Always Available
ファイル読み込み処理のコードを除けば、コードの中では以下の context の要素が常に存在すると考えて良い。つまり、これらは operator の poll()関数で存在を確認しなくて良いが、これら以外の全ての要素は確認の対象になりうる。
CTX_wm_manager | CTX_wm_window | CTX_wm_screen |
CTX_data_main | CTX_data_scene | CTX_data_tool_settings |
API
より詳しい情報が必要な場合は、以下のファイルを確認する。