This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/editors/screen/screen_context.c
Philipp Oeser d13970de86 Fix T92930: Outliner "Show Active" bone fails in certain situations
Outliner would frame the armature object instead of the bone if the bone
was on a hidden armature layer.

Similar to issues reported in e.g. T58068 and T80464, this is due to the
fact that `BKE_pose_channel_active` always checks for the armature layer
(and returns NULL if a bone is not on a visible armature layer).

Now propose to make this layer check **optional** (and e.g. from the
Outliner be more permissive). This also introduces
`BKE_pose_channel_active_if_layer_visible` which just wraps
`BKE_pose_channel_active` with the check being ON.

Maniphest Tasks: T92930

Differential Revision: https://developer.blender.org/D13154
2021-12-21 14:07:48 +01:00

1301 lines
47 KiB
C

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2008 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup edscr
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_workspace_types.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_blender.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
#include "BKE_layer.h"
#include "BKE_object.h"
#include "BKE_tracking.h"
#include "RNA_access.h"
#include "ED_anim_api.h"
#include "ED_armature.h"
#include "ED_clip.h"
#include "ED_gpencil.h"
#include "SEQ_select.h"
#include "SEQ_sequencer.h"
#include "UI_interface.h"
#include "WM_api.h"
#include "screen_intern.h"
const char *screen_context_dir[] = {
"scene",
"view_layer",
"visible_objects",
"selectable_objects",
"selected_objects",
"editable_objects",
"selected_editable_objects",
"objects_in_mode",
"objects_in_mode_unique_data",
"visible_bones",
"editable_bones",
"selected_bones",
"selected_editable_bones",
"visible_pose_bones",
"selected_pose_bones",
"selected_pose_bones_from_active_object",
"active_bone",
"active_pose_bone",
"active_object",
"object",
"edit_object",
"sculpt_object",
"vertex_paint_object",
"weight_paint_object",
"image_paint_object",
"particle_edit_object",
"pose_object",
"active_sequence_strip",
"sequences",
"selected_sequences",
"selected_editable_sequences", /* sequencer */
"active_nla_track",
"active_nla_strip",
"selected_nla_strips", /* nla editor */
"selected_movieclip_tracks",
"gpencil_data",
"gpencil_data_owner", /* grease pencil data */
"annotation_data",
"annotation_data_owner",
"visible_gpencil_layers",
"editable_gpencil_layers",
"editable_gpencil_strokes",
"active_gpencil_layer",
"active_gpencil_frame",
"active_annotation_layer",
"active_operator",
"selected_visible_actions",
"selected_editable_actions",
"visible_fcurves",
"editable_fcurves",
"selected_visible_fcurves",
"selected_editable_fcurves",
"active_editable_fcurve",
"selected_editable_keyframes",
"ui_list",
"asset_library_ref",
NULL,
};
/* Each function `screen_ctx_XXX()` will be called when the screen context "XXX" is requested.
* ensure_ed_screen_context_functions() is responsible for creating the hash map from context
* member name to function. */
static eContextResult screen_ctx_scene(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(win);
CTX_data_id_pointer_set(result, &scene->id);
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_visible_objects(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
View3D *v3d = CTX_wm_view3d(C); /* This may be NULL in a lot of cases. */
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_VISIBLE(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_selectable_objects(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
View3D *v3d = CTX_wm_view3d(C); /* This may be NULL in a lot of cases. */
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTABLE(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_selected_objects(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
View3D *v3d = CTX_wm_view3d(C); /* This may be NULL in a lot of cases. */
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTED(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_selected_editable_objects(const bContext *C,
bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
View3D *v3d = CTX_wm_view3d(C); /* This may be NULL in a lot of cases. */
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTED_EDITABLE(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_editable_objects(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
View3D *v3d = CTX_wm_view3d(C); /* This may be NULL in a lot of cases. */
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
/* Visible + Editable, but not necessarily selected */
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_EDITABLE(v3d, base)) {
CTX_data_id_list_add(result, &base->object->id);
}
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_objects_in_mode(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
View3D *v3d = CTX_wm_view3d(C); /* This may be NULL in a lot of cases. */
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
if (obact && (obact->mode != OB_MODE_OBJECT)) {
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, obact->type, obact->mode, ob_iter) {
CTX_data_id_list_add(result, &ob_iter->id);
}
FOREACH_OBJECT_IN_MODE_END;
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_objects_in_mode_unique_data(const bContext *C,
bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
View3D *v3d = CTX_wm_view3d(C); /* This may be NULL in a lot of cases. */
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
if (obact && (obact->mode != OB_MODE_OBJECT)) {
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, obact->type, obact->mode, ob_iter) {
ob_iter->id.tag |= LIB_TAG_DOIT;
}
FOREACH_OBJECT_IN_MODE_END;
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, obact->type, obact->mode, ob_iter) {
if (ob_iter->id.tag & LIB_TAG_DOIT) {
ob_iter->id.tag &= ~LIB_TAG_DOIT;
CTX_data_id_list_add(result, &ob_iter->id);
}
}
FOREACH_OBJECT_IN_MODE_END;
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_visible_or_editable_bones_(const bContext *C,
bContextDataResult *result,
const bool editable_bones)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
bArmature *arm = (obedit && obedit->type == OB_ARMATURE) ? obedit->data : NULL;
EditBone *flipbone = NULL;
if (arm && arm->edbo) {
uint objects_len;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
view_layer, CTX_wm_view3d(C), &objects_len);
for (uint i = 0; i < objects_len; i++) {
Object *ob = objects[i];
arm = ob->data;
/* Attention: X-Axis Mirroring is also handled here... */
LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
/* first and foremost, bone must be visible and selected */
if (EBONE_VISIBLE(arm, ebone)) {
/* Get 'x-axis mirror equivalent' bone if the X-Axis Mirroring option is enabled
* so that most users of this data don't need to explicitly check for it themselves.
*
* We need to make sure that these mirrored copies are not selected, otherwise some
* bones will be operated on twice.
*/
if (arm->flag & ARM_MIRROR_EDIT) {
flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
}
/* if we're filtering for editable too, use the check for that instead,
* as it has selection check too */
if (editable_bones) {
/* only selected + editable */
if (EBONE_EDITABLE(ebone)) {
CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
if ((flipbone) && !(flipbone->flag & BONE_SELECTED)) {
CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
}
}
}
else {
/* only include bones if visible */
CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
if ((flipbone) && EBONE_VISIBLE(arm, flipbone) == 0) {
CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
}
}
}
}
}
MEM_freeN(objects);
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_visible_bones(const bContext *C, bContextDataResult *result)
{
return screen_ctx_visible_or_editable_bones_(C, result, false);
}
static eContextResult screen_ctx_editable_bones(const bContext *C, bContextDataResult *result)
{
return screen_ctx_visible_or_editable_bones_(C, result, true);
}
static eContextResult screen_ctx_selected_bones_(const bContext *C,
bContextDataResult *result,
const bool selected_editable_bones)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
bArmature *arm = (obedit && obedit->type == OB_ARMATURE) ? obedit->data : NULL;
EditBone *flipbone = NULL;
if (arm && arm->edbo) {
uint objects_len;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
view_layer, CTX_wm_view3d(C), &objects_len);
for (uint i = 0; i < objects_len; i++) {
Object *ob = objects[i];
arm = ob->data;
/* Attention: X-Axis Mirroring is also handled here... */
LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
/* first and foremost, bone must be visible and selected */
if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_SELECTED)) {
/* Get 'x-axis mirror equivalent' bone if the X-Axis Mirroring option is enabled
* so that most users of this data don't need to explicitly check for it themselves.
*
* We need to make sure that these mirrored copies are not selected, otherwise some
* bones will be operated on twice.
*/
if (arm->flag & ARM_MIRROR_EDIT) {
flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
}
/* if we're filtering for editable too, use the check for that instead,
* as it has selection check too */
if (selected_editable_bones) {
/* only selected + editable */
if (EBONE_EDITABLE(ebone)) {
CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
if ((flipbone) && !(flipbone->flag & BONE_SELECTED)) {
CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
}
}
}
else {
/* only include bones if selected */
CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
if ((flipbone) && !(flipbone->flag & BONE_SELECTED)) {
CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
}
}
}
}
}
MEM_freeN(objects);
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_selected_bones(const bContext *C, bContextDataResult *result)
{
return screen_ctx_selected_bones_(C, result, false);
}
static eContextResult screen_ctx_selected_editable_bones(const bContext *C,
bContextDataResult *result)
{
return screen_ctx_selected_bones_(C, result, true);
}
static eContextResult screen_ctx_visible_pose_bones(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
View3D *v3d = CTX_wm_view3d(C); /* This may be NULL in a lot of cases. */
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
Object *obpose = BKE_object_pose_armature_get(obact);
if (obpose && obpose->pose && obpose->data) {
if (obpose != obact) {
FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN (obpose, pchan) {
CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
}
FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
}
else if (obact->mode & OB_MODE_POSE) {
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter) {
FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN (ob_iter, pchan) {
CTX_data_list_add(result, &ob_iter->id, &RNA_PoseBone, pchan);
}
FOREACH_PCHAN_VISIBLE_IN_OBJECT_END;
}
FOREACH_OBJECT_IN_MODE_END;
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_selected_pose_bones(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
View3D *v3d = CTX_wm_view3d(C); /* This may be NULL in a lot of cases. */
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
Object *obpose = BKE_object_pose_armature_get(obact);
if (obpose && obpose->pose && obpose->data) {
if (obpose != obact) {
FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (obpose, pchan) {
CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
}
FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
}
else if (obact->mode & OB_MODE_POSE) {
FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, OB_ARMATURE, OB_MODE_POSE, ob_iter) {
FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan) {
CTX_data_list_add(result, &ob_iter->id, &RNA_PoseBone, pchan);
}
FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
}
FOREACH_OBJECT_IN_MODE_END;
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_selected_pose_bones_from_active_object(const bContext *C,
bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
Object *obpose = BKE_object_pose_armature_get(obact);
if (obpose && obpose->pose && obpose->data) {
if (obpose != obact) {
FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (obpose, pchan) {
CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
}
FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
}
else if (obact->mode & OB_MODE_POSE) {
FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (obact, pchan) {
CTX_data_list_add(result, &obact->id, &RNA_PoseBone, pchan);
}
FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_active_bone(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
if (obact && obact->type == OB_ARMATURE) {
bArmature *arm = obact->data;
if (arm->edbo) {
if (arm->act_edbone) {
CTX_data_pointer_set(result, &arm->id, &RNA_EditBone, arm->act_edbone);
return CTX_RESULT_OK;
}
}
else {
if (arm->act_bone) {
CTX_data_pointer_set(result, &arm->id, &RNA_Bone, arm->act_bone);
return CTX_RESULT_OK;
}
}
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_active_pose_bone(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
Object *obpose = BKE_object_pose_armature_get(obact);
bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(obpose);
if (pchan) {
CTX_data_pointer_set(result, &obpose->id, &RNA_PoseBone, pchan);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_active_object(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
if (obact) {
CTX_data_id_pointer_set(result, &obact->id);
}
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_object(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
if (obact) {
CTX_data_id_pointer_set(result, &obact->id);
}
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_edit_object(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obedit = OBEDIT_FROM_VIEW_LAYER(view_layer);
/* convenience for now, 1 object per scene in editmode */
if (obedit) {
CTX_data_id_pointer_set(result, &obedit->id);
}
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_sculpt_object(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
if (obact && (obact->mode & OB_MODE_SCULPT)) {
CTX_data_id_pointer_set(result, &obact->id);
}
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_vertex_paint_object(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
if (obact && (obact->mode & OB_MODE_VERTEX_PAINT)) {
CTX_data_id_pointer_set(result, &obact->id);
}
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_weight_paint_object(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
if (obact && (obact->mode & OB_MODE_ALL_WEIGHT_PAINT)) {
CTX_data_id_pointer_set(result, &obact->id);
}
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_image_paint_object(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
CTX_data_id_pointer_set(result, &obact->id);
}
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_particle_edit_object(const bContext *C,
bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
if (obact && (obact->mode & OB_MODE_PARTICLE_EDIT)) {
CTX_data_id_pointer_set(result, &obact->id);
}
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_pose_object(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
Object *obpose = BKE_object_pose_armature_get(obact);
if (obpose) {
CTX_data_id_pointer_set(result, &obpose->id);
}
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_active_sequence_strip(const bContext *C,
bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(win);
Sequence *seq = SEQ_select_active_get(scene);
if (seq) {
CTX_data_pointer_set(result, &scene->id, &RNA_Sequence, seq);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_sequences(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(win);
Editing *ed = SEQ_editing_get(scene);
if (ed) {
LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
CTX_data_list_add(result, &scene->id, &RNA_Sequence, seq);
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_selected_sequences(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(win);
Editing *ed = SEQ_editing_get(scene);
if (ed) {
LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
if (seq->flag & SELECT) {
CTX_data_list_add(result, &scene->id, &RNA_Sequence, seq);
}
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_selected_editable_sequences(const bContext *C,
bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
Scene *scene = WM_window_get_active_scene(win);
Editing *ed = SEQ_editing_get(scene);
if (ed) {
LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
if (seq->flag & SELECT && !(seq->flag & SEQ_LOCK)) {
CTX_data_list_add(result, &scene->id, &RNA_Sequence, seq);
}
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_active_nla_track(const bContext *C, bContextDataResult *result)
{
PointerRNA ptr;
if (ANIM_nla_context_track_ptr(C, &ptr)) {
CTX_data_pointer_set_ptr(result, &ptr);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_active_nla_strip(const bContext *C, bContextDataResult *result)
{
PointerRNA ptr;
if (ANIM_nla_context_strip_ptr(C, &ptr)) {
CTX_data_pointer_set_ptr(result, &ptr);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_selected_nla_strips(const bContext *C, bContextDataResult *result)
{
bAnimContext ac;
if (ANIM_animdata_get_context(C, &ac) != 0) {
ListBase anim_data = {NULL, NULL};
ANIM_animdata_filter(&ac, &anim_data, ANIMFILTER_DATA_VISIBLE, ac.data, ac.datatype);
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ale->datatype != ALE_NLASTRIP) {
continue;
}
NlaTrack *nlt = (NlaTrack *)ale->data;
LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
if (strip->flag & NLASTRIP_FLAG_SELECT) {
CTX_data_list_add(result, ale->id, &RNA_NlaStrip, strip);
}
}
}
ANIM_animdata_freelist(&anim_data);
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_selected_movieclip_tracks(const bContext *C,
bContextDataResult *result)
{
SpaceClip *space_clip = CTX_wm_space_clip(C);
if (space_clip == NULL) {
return CTX_RESULT_NO_DATA;
}
MovieClip *clip = ED_space_clip_get_clip(space_clip);
if (clip == NULL) {
return CTX_RESULT_NO_DATA;
}
MovieTracking *tracking = &clip->tracking;
if (tracking == NULL) {
return CTX_RESULT_NO_DATA;
}
ListBase *tracks_list = BKE_tracking_get_active_tracks(tracking);
LISTBASE_FOREACH (MovieTrackingTrack *, track, tracks_list) {
if (!TRACK_SELECTED(track)) {
continue;
}
CTX_data_list_add(result, &clip->id, &RNA_MovieTrackingTrack, track);
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_gpencil_data(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
/* FIXME: for some reason, CTX_data_active_object(C) returns NULL when called from these
* situations (as outlined above - see Campbell's #ifdefs).
* That causes the get_active function to fail when called from context.
* For that reason, we end up using an alternative where we pass everything in!
*/
bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
CTX_data_id_pointer_set(result, &gpd->id);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_gpencil_data_owner(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
/* Pointer to which data/datablock owns the reference to the Grease Pencil data being used
* (as gpencil_data). */
PointerRNA ptr;
bGPdata **gpd_ptr = ED_gpencil_data_get_pointers_direct(area, obact, &ptr);
if (gpd_ptr) {
CTX_data_pointer_set_ptr(result, &ptr);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_annotation_data(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
Scene *scene = WM_window_get_active_scene(win);
bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)screen, area, scene);
if (gpd) {
CTX_data_id_pointer_set(result, &gpd->id);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_annotation_data_owner(const bContext *C,
bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
Scene *scene = WM_window_get_active_scene(win);
/* Pointer to which data/datablock owns the reference to the Grease Pencil data being used. */
PointerRNA ptr;
bGPdata **gpd_ptr = ED_annotation_data_get_pointers_direct((ID *)screen, area, scene, &ptr);
if (gpd_ptr) {
CTX_data_pointer_set_ptr(result, &ptr);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_active_gpencil_layer(const bContext *C,
bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
if (gpl) {
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl);
return CTX_RESULT_OK;
}
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_active_annotation_layer(const bContext *C,
bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
Scene *scene = WM_window_get_active_scene(win);
bGPdata *gpd = ED_annotation_data_get_active_direct((ID *)screen, area, scene);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
if (gpl) {
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl);
return CTX_RESULT_OK;
}
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_active_gpencil_frame(const bContext *C,
bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
if (gpl) {
CTX_data_pointer_set(result, &gpd->id, &RNA_GPencilLayer, gpl->actframe);
return CTX_RESULT_OK;
}
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_visible_gpencil_layers(const bContext *C,
bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if ((gpl->flag & GP_LAYER_HIDE) == 0) {
CTX_data_list_add(result, &gpd->id, &RNA_GPencilLayer, gpl);
}
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_editable_gpencil_layers(const bContext *C,
bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
if (gpd) {
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if (BKE_gpencil_layer_is_editable(gpl)) {
CTX_data_list_add(result, &gpd->id, &RNA_GPencilLayer, gpl);
}
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_editable_gpencil_strokes(const bContext *C,
bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
ViewLayer *view_layer = WM_window_get_active_view_layer(win);
Object *obact = view_layer->basact ? view_layer->basact->object : NULL;
bGPdata *gpd = ED_gpencil_data_get_active_direct(area, obact);
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
if (gpd == NULL) {
return CTX_RESULT_NO_DATA;
}
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe)) {
bGPDframe *gpf;
bGPDframe *init_gpf = gpl->actframe;
if (is_multiedit) {
init_gpf = gpl->frames.first;
}
for (gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
if (ED_gpencil_stroke_can_use_direct(area, gps)) {
/* check if the color is editable */
if (ED_gpencil_stroke_material_editable(obact, gpl, gps) == false) {
continue;
}
CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps);
}
}
}
/* If not multi-edit out of loop. */
if (!is_multiedit) {
break;
}
}
}
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_active_operator(const bContext *C, bContextDataResult *result)
{
wmOperator *op = NULL;
SpaceFile *sfile = CTX_wm_space_file(C);
if (sfile) {
op = sfile->op;
}
else if ((op = UI_context_active_operator_get(C))) {
/* do nothing */
}
else {
/* NOTE: this checks poll, could be a problem, but this also
* happens for the toolbar */
op = WM_operator_last_redo(C);
}
/* TODO: get the operator from popup's. */
if (op && op->ptr) {
CTX_data_pointer_set(result, NULL, &RNA_Operator, op);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_sel_actions_impl(const bContext *C,
bContextDataResult *result,
bool editable)
{
bAnimContext ac;
if (ANIM_animdata_get_context(C, &ac) && ELEM(ac.spacetype, SPACE_ACTION, SPACE_GRAPH)) {
/* In the Action and Shape Key editor always use the action field at the top. */
if (ac.spacetype == SPACE_ACTION) {
SpaceAction *saction = (SpaceAction *)ac.sl;
if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY)) {
if (saction->action && !(editable && ID_IS_LINKED(saction->action))) {
CTX_data_id_list_add(result, &saction->action->id);
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
}
/* Search for selected animation data items. */
ListBase anim_data = {NULL, NULL};
int filter = ANIMFILTER_DATA_VISIBLE;
bool check_selected = false;
switch (ac.spacetype) {
case SPACE_GRAPH:
filter |= ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_SEL;
break;
case SPACE_ACTION:
filter |= ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS;
check_selected = true;
break;
}
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
GSet *seen_set = BLI_gset_ptr_new("seen actions");
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
/* In dopesheet check selection status of individual items, skipping
* if not selected or has no selection flag. This is needed so that
* selecting action or group rows without any channels works. */
if (check_selected && ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_SELECT) <= 0) {
continue;
}
bAction *action = ANIM_channel_action_get(ale);
if (action) {
if (editable && ID_IS_LINKED(action)) {
continue;
}
/* Add the action to the output list if not already added. */
if (!BLI_gset_haskey(seen_set, action)) {
CTX_data_id_list_add(result, &action->id);
BLI_gset_add(seen_set, action);
}
}
}
BLI_gset_free(seen_set, NULL);
ANIM_animdata_freelist(&anim_data);
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_selected_visible_actions(const bContext *C,
bContextDataResult *result)
{
return screen_ctx_sel_actions_impl(C, result, false);
}
static eContextResult screen_ctx_selected_editable_actions(const bContext *C,
bContextDataResult *result)
{
return screen_ctx_sel_actions_impl(C, result, true);
}
static eContextResult screen_ctx_sel_edit_fcurves_(const bContext *C,
bContextDataResult *result,
const int extra_filter)
{
bAnimContext ac;
if (ANIM_animdata_get_context(C, &ac) && ELEM(ac.spacetype, SPACE_ACTION, SPACE_GRAPH)) {
ListBase anim_data = {NULL, NULL};
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS) |
(ac.spacetype == SPACE_GRAPH ? ANIMFILTER_CURVE_VISIBLE :
ANIMFILTER_LIST_VISIBLE) |
extra_filter;
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
CTX_data_list_add(result, ale->fcurve_owner_id, &RNA_FCurve, ale->data);
}
}
ANIM_animdata_freelist(&anim_data);
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_editable_fcurves(const bContext *C, bContextDataResult *result)
{
return screen_ctx_sel_edit_fcurves_(C, result, ANIMFILTER_FOREDIT);
}
static eContextResult screen_ctx_visible_fcurves(const bContext *C, bContextDataResult *result)
{
return screen_ctx_sel_edit_fcurves_(C, result, 0);
}
static eContextResult screen_ctx_selected_editable_fcurves(const bContext *C,
bContextDataResult *result)
{
return screen_ctx_sel_edit_fcurves_(C, result, ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
}
static eContextResult screen_ctx_selected_visible_fcurves(const bContext *C,
bContextDataResult *result)
{
return screen_ctx_sel_edit_fcurves_(C, result, ANIMFILTER_SEL);
}
static eContextResult screen_ctx_active_editable_fcurve(const bContext *C,
bContextDataResult *result)
{
bAnimContext ac;
if (ANIM_animdata_get_context(C, &ac) && ELEM(ac.spacetype, SPACE_GRAPH)) {
ListBase anim_data = {NULL, NULL};
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT |
ANIMFILTER_CURVE_VISIBLE);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
CTX_data_pointer_set(result, ale->fcurve_owner_id, &RNA_FCurve, ale->data);
break;
}
}
ANIM_animdata_freelist(&anim_data);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_selected_editable_keyframes(const bContext *C,
bContextDataResult *result)
{
bAnimContext ac;
if (ANIM_animdata_get_context(C, &ac) && ELEM(ac.spacetype, SPACE_ACTION, SPACE_GRAPH)) {
ListBase anim_data = {NULL, NULL};
/* Use keyframes from editable selected FCurves. */
int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS | ANIMFILTER_FOREDIT |
ANIMFILTER_SEL) |
(ac.spacetype == SPACE_GRAPH ? ANIMFILTER_CURVE_VISIBLE :
ANIMFILTER_LIST_VISIBLE);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
int i;
FCurve *fcurve;
BezTriple *bezt;
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
if (!ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
continue;
}
fcurve = (FCurve *)ale->data;
if (fcurve->bezt == NULL) {
/* Skip baked FCurves. */
continue;
}
for (i = 0, bezt = fcurve->bezt; i < fcurve->totvert; i++, bezt++) {
if ((bezt->f2 & SELECT) == 0) {
continue;
}
CTX_data_list_add(result, ale->fcurve_owner_id, &RNA_Keyframe, bezt);
}
}
ANIM_animdata_freelist(&anim_data);
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return CTX_RESULT_OK;
}
return CTX_RESULT_NO_DATA;
}
static eContextResult screen_ctx_asset_library(const bContext *C, bContextDataResult *result)
{
WorkSpace *workspace = CTX_wm_workspace(C);
CTX_data_pointer_set(
result, &workspace->id, &RNA_AssetLibraryReference, &workspace->asset_library_ref);
return CTX_RESULT_OK;
}
static eContextResult screen_ctx_ui_list(const bContext *C, bContextDataResult *result)
{
wmWindow *win = CTX_wm_window(C);
ARegion *region = CTX_wm_region(C);
if (region) {
uiList *list = UI_list_find_mouse_over(region, win->eventstate);
if (list) {
CTX_data_pointer_set(result, NULL, &RNA_UIList, list);
return CTX_RESULT_OK;
}
}
return CTX_RESULT_NO_DATA;
}
/* Registry of context callback functions. */
typedef eContextResult (*context_callback)(const bContext *C, bContextDataResult *result);
static GHash *ed_screen_context_functions = NULL;
static void free_context_function_ghash(void *UNUSED(user_data))
{
BLI_ghash_free(ed_screen_context_functions, NULL, NULL);
}
static inline void register_context_function(const char *member, context_callback function)
{
BLI_ghash_insert(ed_screen_context_functions, (void *)member, function);
}
static void ensure_ed_screen_context_functions(void)
{
if (ed_screen_context_functions != NULL) {
return;
}
/* Murmur hash is faster for smaller strings (according to BLI_hash_mm2). */
ed_screen_context_functions = BLI_ghash_new(
BLI_ghashutil_strhash_p_murmur, BLI_ghashutil_strcmp, __func__);
BKE_blender_atexit_register(free_context_function_ghash, NULL);
register_context_function("scene", screen_ctx_scene);
register_context_function("visible_objects", screen_ctx_visible_objects);
register_context_function("selectable_objects", screen_ctx_selectable_objects);
register_context_function("selected_objects", screen_ctx_selected_objects);
register_context_function("selected_editable_objects", screen_ctx_selected_editable_objects);
register_context_function("editable_objects", screen_ctx_editable_objects);
register_context_function("objects_in_mode", screen_ctx_objects_in_mode);
register_context_function("objects_in_mode_unique_data", screen_ctx_objects_in_mode_unique_data);
register_context_function("visible_bones", screen_ctx_visible_bones);
register_context_function("editable_bones", screen_ctx_editable_bones);
register_context_function("selected_bones", screen_ctx_selected_bones);
register_context_function("selected_editable_bones", screen_ctx_selected_editable_bones);
register_context_function("visible_pose_bones", screen_ctx_visible_pose_bones);
register_context_function("selected_pose_bones", screen_ctx_selected_pose_bones);
register_context_function("selected_pose_bones_from_active_object",
screen_ctx_selected_pose_bones_from_active_object);
register_context_function("active_bone", screen_ctx_active_bone);
register_context_function("active_pose_bone", screen_ctx_active_pose_bone);
register_context_function("active_object", screen_ctx_active_object);
register_context_function("object", screen_ctx_object);
register_context_function("edit_object", screen_ctx_edit_object);
register_context_function("sculpt_object", screen_ctx_sculpt_object);
register_context_function("vertex_paint_object", screen_ctx_vertex_paint_object);
register_context_function("weight_paint_object", screen_ctx_weight_paint_object);
register_context_function("image_paint_object", screen_ctx_image_paint_object);
register_context_function("particle_edit_object", screen_ctx_particle_edit_object);
register_context_function("pose_object", screen_ctx_pose_object);
register_context_function("active_sequence_strip", screen_ctx_active_sequence_strip);
register_context_function("sequences", screen_ctx_sequences);
register_context_function("selected_sequences", screen_ctx_selected_sequences);
register_context_function("selected_editable_sequences", screen_ctx_selected_editable_sequences);
register_context_function("active_nla_track", screen_ctx_active_nla_track);
register_context_function("active_nla_strip", screen_ctx_active_nla_strip);
register_context_function("selected_nla_strips", screen_ctx_selected_nla_strips);
register_context_function("selected_movieclip_tracks", screen_ctx_selected_movieclip_tracks);
register_context_function("gpencil_data", screen_ctx_gpencil_data);
register_context_function("gpencil_data_owner", screen_ctx_gpencil_data_owner);
register_context_function("annotation_data", screen_ctx_annotation_data);
register_context_function("annotation_data_owner", screen_ctx_annotation_data_owner);
register_context_function("active_gpencil_layer", screen_ctx_active_gpencil_layer);
register_context_function("active_annotation_layer", screen_ctx_active_annotation_layer);
register_context_function("active_gpencil_frame", screen_ctx_active_gpencil_frame);
register_context_function("visible_gpencil_layers", screen_ctx_visible_gpencil_layers);
register_context_function("editable_gpencil_layers", screen_ctx_editable_gpencil_layers);
register_context_function("editable_gpencil_strokes", screen_ctx_editable_gpencil_strokes);
register_context_function("active_operator", screen_ctx_active_operator);
register_context_function("selected_visible_actions", screen_ctx_selected_visible_actions);
register_context_function("selected_editable_actions", screen_ctx_selected_editable_actions);
register_context_function("editable_fcurves", screen_ctx_editable_fcurves);
register_context_function("visible_fcurves", screen_ctx_visible_fcurves);
register_context_function("selected_editable_fcurves", screen_ctx_selected_editable_fcurves);
register_context_function("selected_visible_fcurves", screen_ctx_selected_visible_fcurves);
register_context_function("active_editable_fcurve", screen_ctx_active_editable_fcurve);
register_context_function("selected_editable_keyframes", screen_ctx_selected_editable_keyframes);
register_context_function("asset_library_ref", screen_ctx_asset_library);
register_context_function("ui_list", screen_ctx_ui_list);
}
int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result)
{
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, screen_context_dir);
return CTX_RESULT_OK;
}
ensure_ed_screen_context_functions();
context_callback callback = BLI_ghash_lookup(ed_screen_context_functions, member);
if (callback == NULL) {
return CTX_RESULT_MEMBER_NOT_FOUND;
}
return callback(C, result);
}