From 28b2f1c30504ce0e437b21f7964282fcd6894421 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 26 Jun 2017 15:57:14 +1000 Subject: Manipulator: Python API Initial support for Python/Manipulator integration from 'custom-manipulators' branch. Supports: - Registering custom manipulators & manipulator-groups. - Modifying RNA properties, custom values via get/set callbacks, or invoking an operator. - Drawing shape presets for Python defined manipulators (arrow, circle, face-maps) Limitations: - Only float properties supported. - Drawing only supported via shape presets. (we'll likely want a way to define custom geometry or draw directly). - When to refresh, recalculate manipulators will likely need integration with notifier system. Development will be continued in the 2.8 branch --- source/blender/makesrna/intern/CMakeLists.txt | 1 + source/blender/makesrna/intern/makesrna.c | 2 +- source/blender/makesrna/intern/rna_wm_api.c | 45 + .../blender/makesrna/intern/rna_wm_manipulator.c | 1007 +++++++++++++++++++- .../makesrna/intern/rna_wm_manipulator_api.c | 254 +++++ source/blender/python/intern/CMakeLists.txt | 4 + source/blender/python/intern/bpy.c | 3 + source/blender/python/intern/bpy_intern_string.c | 4 +- source/blender/python/intern/bpy_intern_string.h | 1 + .../blender/python/intern/bpy_manipulator_wrap.c | 231 +++++ .../blender/python/intern/bpy_manipulator_wrap.h | 36 + source/blender/python/intern/bpy_rna.c | 34 +- source/blender/python/intern/bpy_rna_manipulator.c | 341 +++++++ source/blender/python/intern/bpy_rna_manipulator.h | 32 + 14 files changed, 1979 insertions(+), 16 deletions(-) create mode 100644 source/blender/makesrna/intern/rna_wm_manipulator_api.c create mode 100644 source/blender/python/intern/bpy_manipulator_wrap.c create mode 100644 source/blender/python/intern/bpy_manipulator_wrap.h create mode 100644 source/blender/python/intern/bpy_rna_manipulator.c create mode 100644 source/blender/python/intern/bpy_rna_manipulator.h (limited to 'source/blender') diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index d57fbbbd764..75d127079b9 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -127,6 +127,7 @@ set(APISRC rna_ui_api.c rna_vfont_api.c rna_wm_api.c + rna_wm_manipulator_api.c ) string(REGEX REPLACE "rna_([a-zA-Z0-9_-]*).c" "${CMAKE_CURRENT_BINARY_DIR}/rna_\\1_gen.c" GENSRC "${DEFSRC}") diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 20b3daeb79d..7d2ce4cb3b2 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3365,7 +3365,7 @@ static RNAProcessItem PROCESS_ITEMS[] = { {"rna_userdef.c", NULL, RNA_def_userdef}, {"rna_vfont.c", "rna_vfont_api.c", RNA_def_vfont}, {"rna_wm.c", "rna_wm_api.c", RNA_def_wm}, - {"rna_wm_manipulator.c", NULL, RNA_def_wm_manipulator}, + {"rna_wm_manipulator.c", "rna_wm_manipulator_api.c", RNA_def_wm_manipulator}, {"rna_workspace.c", NULL, RNA_def_workspace}, {"rna_world.c", NULL, RNA_def_world}, {"rna_movieclip.c", NULL, RNA_def_movieclip}, diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index 677ea92aea1..166b6f96956 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -71,6 +71,8 @@ EnumPropertyItem rna_enum_window_cursor_items[] = { #include "UI_interface.h" #include "BKE_context.h" +#include "WM_types.h" + static wmKeyMap *rna_keymap_active(wmKeyMap *km, bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); @@ -115,6 +117,37 @@ static void rna_event_timer_remove(struct wmWindowManager *wm, wmTimer *timer) WM_event_remove_timer(wm, timer->win, timer); } + +static wmManipulatorGroupType *wm_manipulatorgrouptype_find_for_add_remove(ReportList *reports, const char *idname) +{ + wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, true); + if (wgt == NULL) { + BKE_reportf(reports, RPT_ERROR, "Manipulator group type '%s' not found!", idname); + return NULL; + } + if (wgt->flag & WM_MANIPULATORGROUPTYPE_PERSISTENT) { + BKE_reportf(reports, RPT_ERROR, "Manipulator group '%s' has 'PERSISTENT' option set!", idname); + return NULL; + } + return wgt; +} + +static void rna_manipulator_group_type_add(ReportList *reports, const char *idname) +{ + wmManipulatorGroupType *wgt = wm_manipulatorgrouptype_find_for_add_remove(reports, idname); + if (wgt != NULL) { + WM_manipulator_group_add_ptr(wgt); + } +} + +static void rna_manipulator_group_type_remove(Main *bmain, ReportList *reports, const char *idname) +{ + wmManipulatorGroupType *wgt = wm_manipulatorgrouptype_find_for_add_remove(reports, idname); + if (wgt != NULL) { + WM_manipulator_group_remove_ptr(bmain, wgt); + } +} + /* placeholder data for final implementation of a true progressbar */ static struct wmStaticProgress { float min; @@ -426,6 +459,18 @@ void RNA_api_wm(StructRNA *srna) parm = RNA_def_pointer(func, "timer", "Timer", "", ""); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + func = RNA_def_function(srna, "manipulator_group_type_add", "rna_manipulator_group_type_add"); + RNA_def_function_ui_description(func, "Activate an existing widget group (when the persistent option isn't set)"); + RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS); + parm = RNA_def_string(func, "identifier", NULL, 0, "", "Manipulator group type name"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + func = RNA_def_function(srna, "manipulator_group_type_remove", "rna_manipulator_group_type_remove"); + RNA_def_function_ui_description(func, "De-activate a widget group (when the persistent option isn't set)"); + RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_MAIN | FUNC_USE_REPORTS); + parm = RNA_def_string(func, "identifier", NULL, 0, "", "Manipulator group type name"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* Progress bar interface */ func = RNA_def_function(srna, "progress_begin", "rna_progress_begin"); RNA_def_function_ui_description(func, "Start progress report"); diff --git a/source/blender/makesrna/intern/rna_wm_manipulator.c b/source/blender/makesrna/intern/rna_wm_manipulator.c index 06e31688a8a..030f1a1628c 100644 --- a/source/blender/makesrna/intern/rna_wm_manipulator.c +++ b/source/blender/makesrna/intern/rna_wm_manipulator.c @@ -63,6 +63,7 @@ #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_workspace.h" +#include "BKE_utildefines.h" #include "MEM_guardedalloc.h" @@ -75,6 +76,171 @@ /** \name Manipulator API * \{ */ +static void rna_manipulator_draw_cb( + const struct bContext *C, struct wmManipulator *mpr) +{ + extern FunctionRNA rna_Manipulator_draw_func; + wmManipulatorGroup *mgroup = mpr->parent_mgroup; + PointerRNA mpr_ptr; + ParameterList list; + FunctionRNA *func; + RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr); + /* RNA_struct_find_function(&mpr_ptr, "draw"); */ + func = &rna_Manipulator_draw_func; + RNA_parameter_list_create(&list, &mpr_ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list); + RNA_parameter_list_free(&list); +} + +static void rna_manipulator_draw_select_cb( + const struct bContext *C, struct wmManipulator *mpr, int select_id) +{ + extern FunctionRNA rna_Manipulator_draw_select_func; + wmManipulatorGroup *mgroup = mpr->parent_mgroup; + PointerRNA mpr_ptr; + ParameterList list; + FunctionRNA *func; + RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr); + /* RNA_struct_find_function(&mpr_ptr, "draw_select"); */ + func = &rna_Manipulator_draw_select_func; + RNA_parameter_list_create(&list, &mpr_ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + RNA_parameter_set_lookup(&list, "select_id", &select_id); + mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list); + RNA_parameter_list_free(&list); +} + +static int rna_manipulator_test_select_cb( + struct bContext *C, struct wmManipulator *mpr, const struct wmEvent *event) +{ + extern FunctionRNA rna_Manipulator_test_select_func; + wmManipulatorGroup *mgroup = mpr->parent_mgroup; + PointerRNA mpr_ptr; + ParameterList list; + FunctionRNA *func; + RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr); + /* RNA_struct_find_function(&mpr_ptr, "test_select"); */ + func = &rna_Manipulator_test_select_func; + RNA_parameter_list_create(&list, &mpr_ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + RNA_parameter_set_lookup(&list, "event", &event); + mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list); + + void *ret; + RNA_parameter_get_lookup(&list, "intersect_id", &ret); + int intersect_id = *(int *)ret; + + RNA_parameter_list_free(&list); + return intersect_id; +} + +static void rna_manipulator_modal_cb( + struct bContext *C, struct wmManipulator *mpr, const struct wmEvent *event, int tweak) +{ + extern FunctionRNA rna_Manipulator_modal_func; + wmManipulatorGroup *mgroup = mpr->parent_mgroup; + PointerRNA mpr_ptr; + ParameterList list; + FunctionRNA *func; + RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr); + /* RNA_struct_find_function(&mpr_ptr, "modal"); */ + func = &rna_Manipulator_modal_func; + RNA_parameter_list_create(&list, &mpr_ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + RNA_parameter_set_lookup(&list, "event", &event); + RNA_parameter_set_lookup(&list, "tweak", &tweak); + mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list); + RNA_parameter_list_free(&list); +} + +static void rna_manipulator_setup_cb( + struct wmManipulator *mpr) +{ + extern FunctionRNA rna_Manipulator_setup_func; + wmManipulatorGroup *mgroup = mpr->parent_mgroup; + PointerRNA mpr_ptr; + ParameterList list; + FunctionRNA *func; + RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr); + /* RNA_struct_find_function(&mpr_ptr, "setup"); */ + func = &rna_Manipulator_setup_func; + RNA_parameter_list_create(&list, &mpr_ptr, func); + mgroup->type->ext.call((bContext *)NULL, &mpr_ptr, func, &list); + RNA_parameter_list_free(&list); +} + + +static void rna_manipulator_invoke_cb( + struct bContext *C, struct wmManipulator *mpr, const struct wmEvent *event) +{ + extern FunctionRNA rna_Manipulator_invoke_func; + wmManipulatorGroup *mgroup = mpr->parent_mgroup; + PointerRNA mpr_ptr; + ParameterList list; + FunctionRNA *func; + RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr); + /* RNA_struct_find_function(&mpr_ptr, "invoke"); */ + func = &rna_Manipulator_invoke_func; + RNA_parameter_list_create(&list, &mpr_ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + RNA_parameter_set_lookup(&list, "event", &event); + mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list); + RNA_parameter_list_free(&list); +} + +static void rna_manipulator_exit_cb( + struct bContext *C, struct wmManipulator *mpr, bool cancel) +{ + extern FunctionRNA rna_Manipulator_exit_func; + wmManipulatorGroup *mgroup = mpr->parent_mgroup; + PointerRNA mpr_ptr; + ParameterList list; + FunctionRNA *func; + RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr); + /* RNA_struct_find_function(&mpr_ptr, "exit"); */ + func = &rna_Manipulator_exit_func; + RNA_parameter_list_create(&list, &mpr_ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + { + int cancel_i = cancel; + RNA_parameter_set_lookup(&list, "cancel", &cancel_i); + } + mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list); + RNA_parameter_list_free(&list); +} + +static void rna_manipulator_select_cb( + struct bContext *C, struct wmManipulator *mpr, int action) +{ + extern FunctionRNA rna_Manipulator_select_func; + wmManipulatorGroup *mgroup = mpr->parent_mgroup; + PointerRNA mpr_ptr; + ParameterList list; + FunctionRNA *func; + RNA_pointer_create(NULL, mpr->type->ext.srna, mpr, &mpr_ptr); + /* RNA_struct_find_function(&mpr_ptr, "select"); */ + func = &rna_Manipulator_select_func; + RNA_parameter_list_create(&list, &mpr_ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + RNA_parameter_set_lookup(&list, "action", &action); + mgroup->type->ext.call((bContext *)C, &mpr_ptr, func, &list); + RNA_parameter_list_free(&list); +} + +/* just to work around 'const char *' warning and to ensure this is a python op */ +static void rna_Manipulator_bl_idname_set(PointerRNA *ptr, const char *value) +{ + wmManipulator *data = ptr->data; + char *str = (char *)data->type->idname; + if (!str[0]) { + BLI_strncpy(str, value, MAX_NAME); /* utf8 already ensured */ + } + else { + assert(!"setting the bl_idname on a non-builtin operator"); + } +} + static wmManipulator *rna_ManipulatorProperties_find_operator(PointerRNA *ptr) { #if 0 @@ -83,7 +249,7 @@ static wmManipulator *rna_ManipulatorProperties_find_operator(PointerRNA *ptr) /* We could try workaruond this lookup, but not trivial. */ for (bScreen *screen = G.main->screen.first; screen; screen = screen->id.next) { - IDProperty *properties = (IDProperty *)ptr->data; + IDProperty *properties = ptr->data; for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { if (ar->manipulator_map) { @@ -127,10 +293,202 @@ static IDProperty *rna_ManipulatorProperties_idprops(PointerRNA *ptr, bool creat static PointerRNA rna_Manipulator_properties_get(PointerRNA *ptr) { - wmManipulator *mpr = (wmManipulator *)ptr->data; + wmManipulator *mpr = ptr->data; return rna_pointer_inherit_refine(ptr, mpr->type->srna, mpr->properties); } +/* wmManipulator.float */ +#define RNA_MANIPULATOR_GENERIC_FLOAT_RW_DEF(func_id, member_id) \ +static float rna_Manipulator_##func_id##_get(PointerRNA *ptr) \ +{ \ + wmManipulator *mpr = ptr->data; \ + return mpr->member_id; \ +} \ +static void rna_Manipulator_##func_id##_set(PointerRNA *ptr, float value) \ +{ \ + wmManipulator *mpr = ptr->data; \ + mpr->member_id = value; \ +} +/* wmManipulator.float[len] */ +#define RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(func_id, member_id, len) \ +static void rna_Manipulator_##func_id##_get(PointerRNA *ptr, float value[len]) \ +{ \ + wmManipulator *mpr = ptr->data; \ + memcpy(value, mpr->member_id, sizeof(float[len])); \ +} \ +static void rna_Manipulator_##func_id##_set(PointerRNA *ptr, const float value[len]) \ +{ \ + wmManipulator *mpr = ptr->data; \ + memcpy(mpr->member_id, value, sizeof(float[len])); \ +} + +/* wmManipulator.flag */ +#define RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(func_id, member_id, flag_value) \ +static int rna_Manipulator_##func_id##_get(PointerRNA *ptr) \ +{ \ + wmManipulator *mpr = ptr->data; \ + return (mpr->member_id & flag_value) != 0; \ +} \ +static void rna_Manipulator_##func_id##_set(PointerRNA *ptr, int value) \ +{ \ + wmManipulator *mpr = ptr->data; \ + BKE_BIT_TEST_SET(mpr->member_id, value, flag_value); \ +} + +#define RNA_MANIPULATOR_FLAG_RO_DEF(func_id, member_id, flag_value) \ +static int rna_Manipulator_##func_id##_get(PointerRNA *ptr) \ +{ \ + wmManipulator *mpr = ptr->data; \ + return (mpr->member_id & flag_value) != 0; \ +} + +RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(color, color, 4); +RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(color_hi, color_hi, 4); + +RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(matrix_basis, matrix_basis, 16); +RNA_MANIPULATOR_GENERIC_FLOAT_ARRAY_RW_DEF(matrix_offset, matrix_offset, 16); + +RNA_MANIPULATOR_GENERIC_FLOAT_RW_DEF(scale_basis, scale_basis); +RNA_MANIPULATOR_GENERIC_FLOAT_RW_DEF(line_width, line_width); + +RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_draw_hover, flag, WM_MANIPULATOR_DRAW_HOVER); +RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_draw_active, flag, WM_MANIPULATOR_DRAW_ACTIVE); +RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_use_draw_value, flag, WM_MANIPULATOR_DRAW_VALUE); +RNA_MANIPULATOR_GENERIC_FLAG_RW_DEF(flag_hide, flag, WM_MANIPULATOR_HIDDEN); + +/* wmManipulator.state */ +RNA_MANIPULATOR_FLAG_RO_DEF(state_is_highlight, state, WM_MANIPULATOR_STATE_HIGHLIGHT); +RNA_MANIPULATOR_FLAG_RO_DEF(state_is_active, state, WM_MANIPULATOR_STATE_ACTIVE); +RNA_MANIPULATOR_FLAG_RO_DEF(state_select, state, WM_MANIPULATOR_STATE_SELECT); + +static void rna_Manipulator_name_get(PointerRNA *ptr, char *value) +{ + wmManipulator *mpr = ptr->data; + strcpy(value, mpr->name); +} + +static void rna_Manipulator_name_set(PointerRNA *ptr, const char *value) +{ + wmManipulator *mpr = ptr->data; + WM_manipulator_name_set(mpr->parent_mgroup, mpr, value); +} + +static int rna_Manipulator_name_length(PointerRNA *ptr) +{ + wmManipulator *mpr = ptr->data; + return strlen(mpr->name); +} + +#ifdef WITH_PYTHON + +static void rna_Manipulator_unregister(struct Main *bmain, StructRNA *type); +void BPY_RNA_manipulator_wrapper(wmManipulatorType *wgt, void *userdata); + +static StructRNA *rna_Manipulator_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +{ + struct { + char idname[MAX_NAME]; + } temp_buffers; + + wmManipulatorType dummywt = {NULL}; + wmManipulator dummymnp = {NULL}; + PointerRNA mnp_ptr; + + /* Two sets of functions. */ + int have_function[8]; + + /* setup dummy manipulator & manipulator type to store static properties in */ + dummymnp.type = &dummywt; + dummywt.idname = temp_buffers.idname; + RNA_pointer_create(NULL, &RNA_Manipulator, &dummymnp, &mnp_ptr); + + /* Clear so we can detect if it's left unset. */ + temp_buffers.idname[0] = '\0'; + + /* validate the python class */ + if (validate(&mnp_ptr, data, have_function) != 0) + return NULL; + + if (strlen(identifier) >= sizeof(temp_buffers.idname)) { + BKE_reportf(reports, RPT_ERROR, "Registering manipulator class: '%s' is too long, maximum length is %d", + identifier, (int)sizeof(temp_buffers.idname)); + return NULL; + } + + /* check if we have registered this manipulator type before, and remove it */ + { + const wmManipulatorType *wt = WM_manipulatortype_find(dummywt.idname, true); + if (wt && wt->ext.srna) { + rna_Manipulator_unregister(bmain, wt->ext.srna); + } + } + + /* create a new manipulator type */ + dummywt.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummywt.idname, &RNA_Manipulator); + /* manipulator properties are registered separately */ + RNA_def_struct_flag(dummywt.ext.srna, STRUCT_NO_IDPROPERTIES); + dummywt.ext.data = data; + dummywt.ext.call = call; + dummywt.ext.free = free; + + { + int i = 0; + dummywt.draw = (have_function[i++]) ? rna_manipulator_draw_cb : NULL; + dummywt.draw_select = (have_function[i++]) ? rna_manipulator_draw_select_cb : NULL; + dummywt.test_select = (have_function[i++]) ? rna_manipulator_test_select_cb : NULL; + dummywt.modal = (have_function[i++]) ? rna_manipulator_modal_cb : NULL; +// dummywt.property_update = (have_function[i++]) ? rna_manipulator_property_update : NULL; +// dummywt.position_get = (have_function[i++]) ? rna_manipulator_position_get : NULL; + dummywt.setup = (have_function[i++]) ? rna_manipulator_setup_cb : NULL; + dummywt.invoke = (have_function[i++]) ? rna_manipulator_invoke_cb : NULL; + dummywt.exit = (have_function[i++]) ? rna_manipulator_exit_cb : NULL; + dummywt.select = (have_function[i++]) ? rna_manipulator_select_cb : NULL; + + BLI_assert(i == ARRAY_SIZE(have_function)); + } + + RNA_def_struct_duplicate_pointers(dummywt.ext.srna); + + /* use duplicated string */ + dummywt.idname = dummywt.ext.srna->identifier; + + WM_manipulatortype_append_ptr(BPY_RNA_manipulator_wrapper, (void *)&dummywt); + + /* update while blender is running */ + WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); + + return dummywt.ext.srna; +} + +static void rna_Manipulator_unregister(struct Main *UNUSED(bmain), StructRNA *type) +{ + wmManipulatorType *wt = RNA_struct_blender_type_get(type); + + /* TODO, remove widgets from interface! */ + + if (!wt) + return; + + WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); + + RNA_struct_free_extension(type, &wt->ext); + + WM_manipulatortype_remove_ptr(wt); + + RNA_struct_free(&BLENDER_RNA, type); +} + +static void **rna_Manipulator_instance(PointerRNA *ptr) +{ + wmManipulator *mpr = ptr->data; + return &mpr->py_instance; +} + +#endif /* WITH_PYTHON */ + + static StructRNA *rna_Manipulator_refine(PointerRNA *mnp_ptr) { wmManipulator *mpr = mnp_ptr->data; @@ -142,6 +500,296 @@ static StructRNA *rna_Manipulator_refine(PointerRNA *mnp_ptr) /** \name Manipulator Group API * \{ */ +static wmManipulator *rna_ManipulatorGroup_manipulator_new( + wmManipulatorGroup *mgroup, ReportList *reports, const char *idname, const char *name) +{ + const wmManipulatorType *wt = WM_manipulatortype_find(idname, true); + if (wt == NULL) { + BKE_reportf(reports, RPT_ERROR, "ManipulatorType '%s' not known", idname); + return NULL; + } + wmManipulator *mpr = WM_manipulator_new_ptr(wt, mgroup, name, NULL); + return mpr; +} + +static void rna_ManipulatorGroup_manipulator_remove( + wmManipulatorGroup *mgroup, bContext *C, wmManipulator *mpr) +{ + WM_manipulator_free(&mgroup->manipulators, mgroup->parent_mmap, mpr, C); +} + +static void rna_ManipulatorGroup_manipulator_clear( + wmManipulatorGroup *mgroup, bContext *C) +{ + while (mgroup->manipulators.first) { + WM_manipulator_free(&mgroup->manipulators, mgroup->parent_mmap, mgroup->manipulators.first, C); + } +} + +static void rna_ManipulatorGroup_name_get(PointerRNA *ptr, char *value) +{ + wmManipulatorGroup *mgroup = ptr->data; + strcpy(value, mgroup->type->name); +} + +static int rna_ManipulatorGroup_name_length(PointerRNA *ptr) +{ + wmManipulatorGroup *mgroup = ptr->data; + return strlen(mgroup->type->name); +} + +/* just to work around 'const char *' warning and to ensure this is a python op */ +static void rna_ManipulatorGroup_bl_idname_set(PointerRNA *ptr, const char *value) +{ + wmManipulatorGroup *data = ptr->data; + char *str = (char *)data->type->idname; + if (!str[0]) + BLI_strncpy(str, value, MAX_NAME); /* utf8 already ensured */ + else + assert(!"setting the bl_idname on a non-builtin operator"); +} + +static void rna_ManipulatorGroup_bl_label_set(PointerRNA *ptr, const char *value) +{ + wmManipulatorGroup *data = ptr->data; + char *str = (char *)data->type->name; + if (!str[0]) + BLI_strncpy(str, value, MAX_NAME); /* utf8 already ensured */ + else + assert(!"setting the bl_label on a non-builtin operator"); +} + +static int rna_ManipulatorGroup_has_reports_get(PointerRNA *ptr) +{ + wmManipulatorGroup *mgroup = ptr->data; + return (mgroup->reports && mgroup->reports->list.first); +} + +#ifdef WITH_PYTHON + +static bool rna_manipulatorgroup_poll_cb(const bContext *C, wmManipulatorGroupType *wgt) +{ + + extern FunctionRNA rna_ManipulatorGroup_poll_func; + + PointerRNA ptr; + ParameterList list; + FunctionRNA *func; + void *ret; + int visible; + + RNA_pointer_create(NULL, wgt->ext.srna, NULL, &ptr); /* dummy */ + func = &rna_ManipulatorGroup_poll_func; /* RNA_struct_find_function(&ptr, "poll"); */ + + RNA_parameter_list_create(&list, &ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + wgt->ext.call((bContext *)C, &ptr, func, &list); + + RNA_parameter_get_lookup(&list, "visible", &ret); + visible = *(int *)ret; + + RNA_parameter_list_free(&list); + + return visible; +} + +static void rna_manipulatorgroup_setup_cb(const bContext *C, wmManipulatorGroup *mgroup) +{ + extern FunctionRNA rna_ManipulatorGroup_setup_func; + + PointerRNA mgroup_ptr; + ParameterList list; + FunctionRNA *func; + + RNA_pointer_create(NULL, mgroup->type->ext.srna, mgroup, &mgroup_ptr); + func = &rna_ManipulatorGroup_setup_func; /* RNA_struct_find_function(&wgroupr, "setup"); */ + + RNA_parameter_list_create(&list, &mgroup_ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + mgroup->type->ext.call((bContext *)C, &mgroup_ptr, func, &list); + + RNA_parameter_list_free(&list); +} + +static wmKeyMap *rna_manipulatorgroup_setup_keymap_cb(const wmManipulatorGroupType *wgt, wmKeyConfig *config) +{ + extern FunctionRNA rna_ManipulatorGroup_setup_keymap_func; + const char *wgroupname = wgt->name; + void *ret; + + PointerRNA ptr; + ParameterList list; + FunctionRNA *func; + + RNA_pointer_create(NULL, wgt->ext.srna, NULL, &ptr); /* dummy */ + func = &rna_ManipulatorGroup_setup_keymap_func; /* RNA_struct_find_function(&wgroupr, "setup_keymap"); */ + + RNA_parameter_list_create(&list, &ptr, func); + RNA_parameter_set_lookup(&list, "keyconfig", &config); + RNA_parameter_set_lookup(&list, "manipulator_group", &wgroupname); + wgt->ext.call(NULL, &ptr, func, &list); + + RNA_parameter_get_lookup(&list, "keymap", &ret); + wmKeyMap *keymap = *(wmKeyMap **)ret; + + RNA_parameter_list_free(&list); + + return keymap; +} + +static void rna_manipulatorgroup_refresh_cb(const bContext *C, wmManipulatorGroup *mgroup) +{ + extern FunctionRNA rna_ManipulatorGroup_refresh_func; + + PointerRNA mgroup_ptr; + ParameterList list; + FunctionRNA *func; + + RNA_pointer_create(NULL, mgroup->type->ext.srna, mgroup, &mgroup_ptr); + func = &rna_ManipulatorGroup_refresh_func; /* RNA_struct_find_function(&wgroupr, "refresh"); */ + + RNA_parameter_list_create(&list, &mgroup_ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + mgroup->type->ext.call((bContext *)C, &mgroup_ptr, func, &list); + + RNA_parameter_list_free(&list); +} + +static void rna_manipulatorgroup_draw_prepare_cb(const bContext *C, wmManipulatorGroup *mgroup) +{ + extern FunctionRNA rna_ManipulatorGroup_draw_prepare_func; + + PointerRNA mgroup_ptr; + ParameterList list; + FunctionRNA *func; + + RNA_pointer_create(NULL, mgroup->type->ext.srna, mgroup, &mgroup_ptr); + func = &rna_ManipulatorGroup_draw_prepare_func; /* RNA_struct_find_function(&wgroupr, "draw_prepare"); */ + + RNA_parameter_list_create(&list, &mgroup_ptr, func); + RNA_parameter_set_lookup(&list, "context", &C); + mgroup->type->ext.call((bContext *)C, &mgroup_ptr, func, &list); + + RNA_parameter_list_free(&list); +} + +void BPY_RNA_manipulatorgroup_wrapper(wmManipulatorGroupType *wgt, void *userdata); + +static StructRNA *rna_ManipulatorGroup_register( + Main *bmain, ReportList *reports, void *data, const char *identifier, + StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) +{ + struct { + char name[MAX_NAME]; + char idname[MAX_NAME]; + } temp_buffers; + + wmManipulatorGroupType dummywgt = {NULL}; + wmManipulatorGroup dummywg = {NULL}; + PointerRNA wgptr; + + /* Two sets of functions. */ + int have_function[5]; + + /* setup dummy manipulatorgroup & manipulatorgroup type to store static properties in */ + dummywg.type = &dummywgt; + dummywgt.name = temp_buffers.name; + dummywgt.idname = temp_buffers.idname; + + RNA_pointer_create(NULL, &RNA_ManipulatorGroup, &dummywg, &wgptr); + + /* Clear so we can detect if it's left unset. */ + temp_buffers.idname[0] = temp_buffers.name[0] = '\0'; + + /* validate the python class */ + if (validate(&wgptr, data, have_function) != 0) + return NULL; + + if (strlen(identifier) >= sizeof(temp_buffers.idname)) { + BKE_reportf(reports, RPT_ERROR, "Registering manipulatorgroup class: '%s' is too long, maximum length is %d", + identifier, (int)sizeof(temp_buffers.idname)); + return NULL; + } + + /* check if the area supports widgets */ + const struct wmManipulatorMapType_Params wmap_params = { + .spaceid = dummywgt.mmap_params.spaceid, + .regionid = dummywgt.mmap_params.regionid, + }; + + wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wmap_params); + if (mmap_type == NULL) { + BKE_reportf(reports, RPT_ERROR, "Area type does not support manipulators"); + return NULL; + } + + /* check if we have registered this manipulatorgroup type before, and remove it */ + { + wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(dummywgt.idname, true); + if (wgt && wgt->ext.srna) { + WM_manipulatormaptype_group_unlink(NULL, bmain, mmap_type, wgt); + WM_manipulatorgrouptype_remove_ptr(wgt); + + WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); + } + } + + /* create a new manipulatorgroup type */ + dummywgt.ext.srna = RNA_def_struct_ptr(&BLENDER_RNA, dummywgt.idname, &RNA_ManipulatorGroup); + RNA_def_struct_flag(dummywgt.ext.srna, STRUCT_NO_IDPROPERTIES); /* manipulatorgroup properties are registered separately */ + dummywgt.ext.data = data; + dummywgt.ext.call = call; + dummywgt.ext.free = free; + + /* We used to register widget group types like this, now we do it similar to + * operator types. Thus we should be able to do the same as operator types now. */ + dummywgt.poll = (have_function[0]) ? rna_manipulatorgroup_poll_cb : NULL; + dummywgt.setup_keymap = (have_function[1]) ? rna_manipulatorgroup_setup_keymap_cb : NULL; + dummywgt.setup = (have_function[2]) ? rna_manipulatorgroup_setup_cb : NULL; + dummywgt.refresh = (have_function[3]) ? rna_manipulatorgroup_refresh_cb : NULL; + dummywgt.draw_prepare = (have_function[4]) ? rna_manipulatorgroup_draw_prepare_cb : NULL; + + RNA_def_struct_duplicate_pointers(dummywgt.ext.srna); + dummywgt.idname = dummywgt.ext.srna->identifier; + dummywgt.name = dummywgt.ext.srna->name; + + wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_append_ptr( + BPY_RNA_manipulatorgroup_wrapper, (void *)&dummywgt); + + if (wgt->flag & WM_MANIPULATORGROUPTYPE_PERSISTENT) { + WM_manipulator_group_add_ptr_ex(wgt, mmap_type); + + /* update while blender is running */ + WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); + } + + return dummywgt.ext.srna; +} + +static void rna_ManipulatorGroup_unregister(struct Main *bmain, StructRNA *type) +{ + wmManipulatorGroupType *wgt = RNA_struct_blender_type_get(type); + + if (!wgt) + return; + + WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); + + RNA_struct_free_extension(type, &wgt->ext); + + WM_manipulator_group_remove_ptr(bmain, wgt); + + RNA_struct_free(&BLENDER_RNA, type); +} + +static void **rna_ManipulatorGroup_instance(PointerRNA *ptr) +{ + wmManipulatorGroup *mgroup = ptr->data; + return &mgroup->py_instance; +} + +#endif /* WITH_PYTHON */ + static StructRNA *rna_ManipulatorGroup_refine(PointerRNA *mgroup_ptr) { wmManipulatorGroup *mgroup = mgroup_ptr->data; @@ -165,10 +813,32 @@ static void rna_def_manipulators(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; + FunctionRNA *func; + PropertyRNA *parm; + RNA_def_property_srna(cprop, "Manipulators"); srna = RNA_def_struct(brna, "Manipulators", NULL); RNA_def_struct_sdna(srna, "wmManipulatorGroup"); RNA_def_struct_ui_text(srna, "Manipulators", "Collection of manipulators"); + + func = RNA_def_function(srna, "new", "rna_ManipulatorGroup_manipulator_new"); + RNA_def_function_ui_description(func, "Add manipulator"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + RNA_def_string(func, "type", "Type", 0, "", "Manipulator identifier"); /* optional */ + RNA_def_string(func, "name", "Name", 0, "", "Manipulator name"); /* optional */ + parm = RNA_def_pointer(func, "manipulator", "Manipulator", "", "New manipulator"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "remove", "rna_ManipulatorGroup_manipulator_remove"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Delete manipulator"); + parm = RNA_def_pointer(func, "manipulator", "Manipulator", "", "New manipulator"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + func = RNA_def_function(srna, "clear", "rna_ManipulatorGroup_manipulator_clear"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + RNA_def_function_ui_description(func, "Delete all manipulators"); } @@ -177,18 +847,222 @@ static void rna_def_manipulator(BlenderRNA *brna, PropertyRNA *cprop) StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; + RNA_def_property_srna(cprop, "Manipulator"); srna = RNA_def_struct(brna, "Manipulator", NULL); RNA_def_struct_sdna(srna, "wmManipulator"); RNA_def_struct_ui_text(srna, "Manipulator", "Collection of manipulators"); RNA_def_struct_refine_func(srna, "rna_Manipulator_refine"); +#ifdef WITH_PYTHON + RNA_def_struct_register_funcs( + srna, + "rna_Manipulator_register", + "rna_Manipulator_unregister", + "rna_Manipulator_instance"); +#endif + RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + prop = RNA_def_property(srna, "properties", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_struct_type(prop, "ManipulatorProperties"); RNA_def_property_ui_text(prop, "Properties", ""); RNA_def_property_pointer_funcs(prop, "rna_Manipulator_properties_get", NULL, NULL, NULL); + /* -------------------------------------------------------------------- */ + /* Registerable Variables */ + + RNA_define_verify_sdna(0); /* not in sdna */ + + prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "type->idname"); + RNA_def_property_string_maxlength(prop, MAX_NAME); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Manipulator_bl_idname_set"); + /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + RNA_def_property_flag(prop, PROP_REGISTER); + + RNA_define_verify_sdna(1); /* not in sdna */ + + /* wmManipulator.draw */ + func = RNA_def_function(srna, "draw", NULL); + RNA_def_function_ui_description(func, ""); + RNA_def_function_flag(func, FUNC_REGISTER); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + + /* wmManipulator.draw_select */ + func = RNA_def_function(srna, "draw_select", NULL); + RNA_def_function_ui_description(func, ""); + RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_int(func, "select_id", 0, 0, INT_MAX, "", "", 0, INT_MAX); + + /* wmManipulator.test_select */ + func = RNA_def_function(srna, "test_select", NULL); + RNA_def_function_ui_description(func, ""); + RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_pointer(func, "event", "Event", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_int(func, "intersect_id", 0, 0, INT_MAX, "", "", 0, INT_MAX); + RNA_def_function_return(func, parm); + + /* wmManipulator.handler */ + static EnumPropertyItem tweak_actions[] = { + {WM_MANIPULATOR_TWEAK_PRECISE, "PRECISE", 0, "Precise", ""}, + {0, NULL, 0, NULL, NULL} + }; + func = RNA_def_function(srna, "modal", NULL); + RNA_def_function_ui_description(func, ""); + RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_pointer(func, "event", "Event", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + /* TODO, shuold be a enum-flag */ + parm = RNA_def_enum(func, "tweak", tweak_actions, 0, "Tweak", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_property_flag(parm, PROP_ENUM_FLAG); + + /* wmManipulator.property_update */ + /* TODO */ + + /* wmManipulator.setup */ + func = RNA_def_function(srna, "setup", NULL); + RNA_def_function_ui_description(func, ""); + RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); + + /* wmManipulator.invoke */ + func = RNA_def_function(srna, "invoke", NULL); + RNA_def_function_ui_description(func, ""); + RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_pointer(func, "event", "Event", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + + /* wmManipulator.exit */ + func = RNA_def_function(srna, "exit", NULL); + RNA_def_function_ui_description(func, ""); + RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_boolean(func, "cancel", 0, "Cancel, otherwise confirm", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + /* wmManipulator.cursor_get */ + /* TODO */ + + /* wmManipulator.select */ + /* TODO, de-duplicate! */ + static EnumPropertyItem select_actions[] = { + {SEL_TOGGLE, "TOGGLE", 0, "Toggle", "Toggle selection for all elements"}, + {SEL_SELECT, "SELECT", 0, "Select", "Select all elements"}, + {SEL_DESELECT, "DESELECT", 0, "Deselect", "Deselect all elements"}, + {SEL_INVERT, "INVERT", 0, "Invert", "Invert selection of all elements"}, + {0, NULL, 0, NULL, NULL} + }; + func = RNA_def_function(srna, "select", NULL); + RNA_def_function_ui_description(func, ""); + RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_enum(func, "action", select_actions, 0, "Action", "Selection action to execute"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + + /* -------------------------------------------------------------------- */ + /* Instance Variables */ + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs( + prop, "rna_Manipulator_name_get", "rna_Manipulator_name_length", "rna_Manipulator_name_set"); + RNA_def_property_ui_text(prop, "Name", ""); + RNA_def_struct_name_property(srna, prop); + RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL); + + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); + RNA_def_property_array(prop, 4); + RNA_def_property_float_funcs(prop, "rna_Manipulator_color_get", "rna_Manipulator_color_set", NULL); + + prop = RNA_def_property(srna, "color_highlight", PROP_FLOAT, PROP_COLOR); + RNA_def_property_array(prop, 4); + RNA_def_property_float_funcs(prop, "rna_Manipulator_color_hi_get", "rna_Manipulator_color_hi_set", NULL); + RNA_def_property_ui_text(prop, "Color", ""); + + prop = RNA_def_property(srna, "matrix_basis", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(prop, "Basis Matrix", ""); + RNA_def_property_float_funcs(prop, "rna_Manipulator_matrix_basis_get", "rna_Manipulator_matrix_basis_set", NULL); + RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + + prop = RNA_def_property(srna, "matrix_offset", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(prop, "Offset Matrix", ""); + RNA_def_property_float_funcs(prop, "rna_Manipulator_matrix_offset_get", "rna_Manipulator_matrix_offset_set", NULL); + RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + + prop = RNA_def_property(srna, "scale_basis", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_ui_text(prop, "Scale Basis", ""); + RNA_def_property_float_funcs(prop, "rna_Manipulator_scale_basis_get", "rna_Manipulator_scale_basis_set", NULL); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + + prop = RNA_def_property(srna, "line_width", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_ui_text(prop, "Line Width", ""); + RNA_def_property_float_funcs(prop, "rna_Manipulator_line_width_get", "rna_Manipulator_line_width_set", NULL); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + + /* wmManipulator.flag */ + /* WM_MANIPULATOR_HIDDEN */ + prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs( + prop, "rna_Manipulator_flag_hide_get", "rna_Manipulator_flag_hide_set"); + RNA_def_property_ui_text(prop, "Hide", ""); + RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + /* WM_MANIPULATOR_DRAW_HOVER */ + prop = RNA_def_property(srna, "use_draw_hover", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs( + prop, "rna_Manipulator_flag_use_draw_hover_get", "rna_Manipulator_flag_use_draw_hover_set"); + RNA_def_property_ui_text(prop, "Draw Hover", ""); + RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + /* WM_MANIPULATOR_DRAW_ACTIVE */ + prop = RNA_def_property(srna, "use_draw_active", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs( + prop, "rna_Manipulator_flag_use_draw_active_get", "rna_Manipulator_flag_use_draw_active_set"); + RNA_def_property_ui_text(prop, "Draw Active", "Draw while dragging"); + RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + /* WM_MANIPULATOR_DRAW_VALUE */ + prop = RNA_def_property(srna, "use_draw_value", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs( + prop, "rna_Manipulator_flag_use_draw_value_get", "rna_Manipulator_flag_use_draw_value_set"); + RNA_def_property_ui_text(prop, "Draw Value", "Show an indicator for the current value while dragging"); + RNA_def_property_update(prop, NC_SCREEN | NA_EDITED, NULL); + + /* wmManipulator.state (readonly) */ + /* WM_MANIPULATOR_STATE_HIGHLIGHT */ + prop = RNA_def_property(srna, "is_highlight", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_Manipulator_state_is_highlight_get", NULL); + RNA_def_property_ui_text(prop, "Highlight", ""); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + /* WM_MANIPULATOR_STATE_ACTIVE */ + prop = RNA_def_property(srna, "is_active", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_Manipulator_state_is_active_get", NULL); + RNA_def_property_ui_text(prop, "Highlight", ""); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + /* WM_MANIPULATOR_STATE_SELECT */ + prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs(prop, "rna_Manipulator_state_select_get", NULL); + RNA_def_property_ui_text(prop, "Select", ""); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + + RNA_api_manipulator(srna); + srna = RNA_def_struct(brna, "ManipulatorProperties", NULL); RNA_def_struct_ui_text(srna, "Manipulator Properties", "Input properties of an Manipulator"); RNA_def_struct_refine_func(srna, "rna_ManipulatorProperties_refine"); @@ -201,10 +1075,137 @@ static void rna_def_manipulatorgroup(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; + srna = RNA_def_struct(brna, "ManipulatorGroup", NULL); RNA_def_struct_ui_text(srna, "ManipulatorGroup", "Storage of an operator being executed, or registered after execution"); RNA_def_struct_sdna(srna, "wmManipulatorGroup"); RNA_def_struct_refine_func(srna, "rna_ManipulatorGroup_refine"); +#ifdef WITH_PYTHON + RNA_def_struct_register_funcs( + srna, + "rna_ManipulatorGroup_register", + "rna_ManipulatorGroup_unregister", + "rna_ManipulatorGroup_instance"); +#endif + RNA_def_struct_translation_context(srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + + /* -------------------------------------------------------------------- */ + /* Registration */ + + RNA_define_verify_sdna(0); /* not in sdna */ + + prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "type->idname"); + RNA_def_property_string_maxlength(prop, MAX_NAME); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ManipulatorGroup_bl_idname_set"); + RNA_def_property_flag(prop, PROP_REGISTER); + RNA_def_struct_name_property(srna, prop); + + prop = RNA_def_property(srna, "bl_label", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "type->name"); + RNA_def_property_string_maxlength(prop, MAX_NAME); /* else it uses the pointer size! */ + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ManipulatorGroup_bl_label_set"); + /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + RNA_def_property_flag(prop, PROP_REGISTER); + + prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type->mmap_params.spaceid"); + RNA_def_property_enum_items(prop, rna_enum_space_type_items); + RNA_def_property_flag(prop, PROP_REGISTER); + RNA_def_property_ui_text(prop, "Space type", "The space where the panel is going to be used in"); + + prop = RNA_def_property(srna, "bl_region_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type->mmap_params.regionid"); + RNA_def_property_enum_items(prop, rna_enum_region_type_items); + RNA_def_property_flag(prop, PROP_REGISTER); + RNA_def_property_ui_text(prop, "Region Type", "The region where the panel is going to be used in"); + + /* bl_options */ + static EnumPropertyItem manipulatorgroup_flag_items[] = { + {WM_MANIPULATORGROUPTYPE_3D, "3D", 0, "3D", + "Use in 3D viewport"}, + {WM_MANIPULATORGROUPTYPE_SCALE, "SCALE", 0, "Scale", + "Scale to respect zoom (otherwise zoom independent draw size)"}, + {WM_MANIPULATORGROUPTYPE_DEPTH_3D, "DEPTH_3D", 0, "Depth 3D", + "Supports culled depth by other objects in the view"}, + {WM_MANIPULATORGROUPTYPE_SELECT, "SELECT", 0, "Select", + "Supports selection"}, + {WM_MANIPULATORGROUPTYPE_PERSISTENT, "PERSISTENT", 0, "Persistent", + ""}, + {0, NULL, 0, NULL, NULL} + }; + prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type->flag"); + RNA_def_property_enum_items(prop, manipulatorgroup_flag_items); + RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG); + RNA_def_property_ui_text(prop, "Options", "Options for this operator type"); + + RNA_define_verify_sdna(1); /* not in sdna */ + + + /* Functions */ + + /* poll */ + func = RNA_def_function(srna, "poll", NULL); + RNA_def_function_ui_description(func, "Test if the manipulator group can be called or not"); + RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL); + RNA_def_function_return(func, RNA_def_boolean(func, "visible", 1, "", "")); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + + /* keymap_init */ + func = RNA_def_function(srna, "setup_keymap", NULL); + RNA_def_function_ui_description( + func, + "Initialize keymaps for this manipulator group, use fallback keymap when not present"); + RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL); + parm = RNA_def_pointer(func, "keyconf", "KeyConfig", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_property(func, "manipulator_group", PROP_STRING, PROP_NONE); + RNA_def_property_ui_text(parm, "Manipulator Group", "Manipulator Group ID"); + // RNA_def_property_string_default(parm, ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* return */ + parm = RNA_def_pointer(func, "keymap", "KeyMap", "", ""); + RNA_def_property_flag(parm, PROP_NEVER_NULL); + RNA_def_function_return(func, parm); + + /* setup */ + func = RNA_def_function(srna, "setup", NULL); + RNA_def_function_ui_description(func, "Create manipulators function for the manipulator group"); + RNA_def_function_flag(func, FUNC_REGISTER); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + + /* refresh */ + func = RNA_def_function(srna, "refresh", NULL); + RNA_def_function_ui_description(func, "Refresh data (called on common state changes such as selection)"); + RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + + func = RNA_def_function(srna, "draw_prepare", NULL); + RNA_def_function_ui_description(func, "Run before each redraw"); + RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + + /* -------------------------------------------------------------------- */ + /* Instance Variables */ + + prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_string_funcs(prop, "rna_ManipulatorGroup_name_get", "rna_ManipulatorGroup_name_length", NULL); + RNA_def_property_ui_text(prop, "Name", ""); + + prop = RNA_def_property(srna, "has_reports", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* this is 'virtual' property */ + RNA_def_property_boolean_funcs(prop, "rna_ManipulatorGroup_has_reports_get", NULL); + RNA_def_property_ui_text(prop, "Has Reports", + "ManipulatorGroup has a set of reports (warnings and errors) from last execution"); + RNA_define_verify_sdna(0); /* not in sdna */ @@ -221,6 +1222,8 @@ static void rna_def_manipulatorgroup(BlenderRNA *brna) rna_def_manipulators(brna, prop); RNA_define_verify_sdna(1); /* not in sdna */ + + RNA_api_manipulatorgroup(srna); } void RNA_def_wm_manipulator(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_wm_manipulator_api.c b/source/blender/makesrna/intern/rna_wm_manipulator_api.c new file mode 100644 index 00000000000..9f011ad7b7d --- /dev/null +++ b/source/blender/makesrna/intern/rna_wm_manipulator_api.c @@ -0,0 +1,254 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/makesrna/intern/rna_wm_manipulator_api.c + * \ingroup RNA + */ + + +#include +#include + +#include "BLI_utildefines.h" + +#include "BKE_report.h" + +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "DNA_windowmanager_types.h" + +#include "WM_api.h" + +#include "rna_internal.h" /* own include */ + +#ifdef RNA_RUNTIME + +#include "UI_interface.h" +#include "BKE_context.h" + +#include "ED_manipulator_library.h" + +static void rna_manipulator_draw_preset_box( + wmManipulator *mpr, float matrix[16], int select_id) +{ + ED_manipulator_draw_preset_box(mpr, (float (*)[4])matrix, select_id); +} + +static void rna_manipulator_draw_preset_arrow( + wmManipulator *mpr, float matrix[16], int axis, int select_id) +{ + ED_manipulator_draw_preset_arrow(mpr, (float (*)[4])matrix, axis, select_id); +} + +static void rna_manipulator_draw_preset_circle( + wmManipulator *mpr, float matrix[16], int axis, int select_id) +{ + ED_manipulator_draw_preset_circle(mpr, (float (*)[4])matrix, axis, select_id); +} + +static void rna_manipulator_draw_preset_facemap( + wmManipulator *mpr, struct bContext *C, struct Object *ob, int facemap, int select_id) +{ + struct Scene *scene = CTX_data_scene(C); + ED_manipulator_draw_preset_facemap(mpr, scene, ob, facemap, select_id); +} + +static void rna_manipulator_target_set_prop( + wmManipulator *mpr, ReportList *reports, const char *target_propname, + PointerRNA *ptr, const char *propname, int index) +{ + const wmManipulatorPropertyType *mpr_prop_type = + WM_manipulatortype_target_property_find(mpr->type, target_propname); + if (mpr_prop_type == NULL) { + BKE_reportf(reports, RPT_ERROR, "Manipulator target property '%s.%s' not found", + mpr->type->idname, target_propname); + return; + } + + PropertyRNA *prop = RNA_struct_find_property(ptr, propname); + if (prop == NULL) { + BKE_reportf(reports, RPT_ERROR, "Property '%s.%s' not found", + RNA_struct_identifier(ptr->type), target_propname); + return; + } + + if (mpr_prop_type->data_type != RNA_property_type(prop)) { + const int manipulator_type_index = RNA_enum_from_value(rna_enum_property_type_items, mpr_prop_type->data_type); + const int prop_type_index = RNA_enum_from_value(rna_enum_property_type_items, RNA_property_type(prop)); + BLI_assert((manipulator_type_index != -1) && (prop_type_index == -1)); + + BKE_reportf(reports, RPT_ERROR, "Manipulator target '%s.%s' expects '%s', '%s.%s' is '%s'", + mpr->type->idname, target_propname, + rna_enum_property_type_items[manipulator_type_index].identifier, + RNA_struct_identifier(ptr->type), propname, + rna_enum_property_type_items[prop_type_index].identifier); + return; + } + + if (RNA_property_array_check(prop)) { + if (index == -1) { + const int prop_array_length = RNA_property_array_length(ptr, prop); + if (mpr_prop_type->array_length != prop_array_length) { + BKE_reportf(reports, RPT_ERROR, + "Manipulator target property '%s.%s' expects an array of length %d, found %d", + mpr->type->idname, target_propname, + mpr_prop_type->array_length, + prop_array_length); + return; + } + } + } + else { + if (mpr_prop_type->array_length != 1) { + BKE_reportf(reports, RPT_ERROR, + "Manipulator target property '%s.%s' expects an array of length %d", + mpr->type->idname, target_propname, + mpr_prop_type->array_length); + return; + } + } + + if (index >= mpr_prop_type->array_length) { + BKE_reportf(reports, RPT_ERROR, "Manipulator target property '%s.%s', index %d must be below %d", + mpr->type->idname, target_propname, index, mpr_prop_type->array_length); + return; + } + + WM_manipulator_target_property_def_rna_ptr(mpr, mpr_prop_type, ptr, prop, index); +} + +static PointerRNA rna_manipulator_target_set_operator( + wmManipulator *mpr, ReportList *reports, const char *opname) +{ + wmOperatorType *ot; + + ot = WM_operatortype_find(opname, 0); /* print error next */ + if (!ot || !ot->srna) { + BKE_reportf(reports, RPT_ERROR, "%s '%s'", ot ? "unknown operator" : "operator missing srna", opname); + return PointerRNA_NULL; + } + + /* For the return value to be usable, we need 'PointerRNA.data' to be set. */ + IDProperty *properties; + { + IDPropertyTemplate val = {0}; + properties = IDP_New(IDP_GROUP, &val, "wmManipulatorProperties"); + } + + WM_manipulator_set_operator(mpr, ot, properties); + + return mpr->op_data.ptr; +} + +#else + +void RNA_api_manipulator(StructRNA *srna) +{ + /* Utility draw functions, since we don't expose new OpenGL drawing wrappers via Python yet. + * exactly how these should be exposed isn't totally clear. + * However it's probably good to have some high level API's for this anyway. + * Just note that this could be re-worked once tests are done. + */ + + FunctionRNA *func; + PropertyRNA *parm; + + /* -------------------------------------------------------------------- */ + /* Primitive Shapes */ + + /* draw_preset_box */ + func = RNA_def_function(srna, "draw_preset_box", "rna_manipulator_draw_preset_box"); + RNA_def_function_ui_description(func, "Draw a box"); + parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_flag(parm, PARM_REQUIRED); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(parm, "", "The matrix to transform"); + RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX); + + /* draw_preset_box */ + func = RNA_def_function(srna, "draw_preset_arrow", "rna_manipulator_draw_preset_arrow"); + RNA_def_function_ui_description(func, "Draw a box"); + parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_flag(parm, PARM_REQUIRED); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(parm, "", "The matrix to transform"); + RNA_def_enum(func, "axis", rna_enum_object_axis_items, 2, "", "Arrow Orientation"); + RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX); + + func = RNA_def_function(srna, "draw_preset_circle", "rna_manipulator_draw_preset_circle"); + RNA_def_function_ui_description(func, "Draw a box"); + parm = RNA_def_property(func, "matrix", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_flag(parm, PARM_REQUIRED); + RNA_def_property_multi_array(parm, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(parm, "", "The matrix to transform"); + RNA_def_enum(func, "axis", rna_enum_object_axis_items, 2, "", "Arrow Orientation"); + RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX); + + /* -------------------------------------------------------------------- */ + /* Other Shapes */ + + /* draw_preset_facemap */ + func = RNA_def_function(srna, "draw_preset_facemap", "rna_manipulator_draw_preset_facemap"); + RNA_def_function_ui_description(func, "Draw the face-map of a mesh object"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + parm = RNA_def_pointer(func, "object", "Object", "", "Object"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + RNA_def_int(func, "facemap", 0, 0, INT_MAX, "Face map index", "", 0, INT_MAX); + RNA_def_int(func, "select_id", -1, -1, INT_MAX, "Zero when not selecting", "", -1, INT_MAX); + + + /* -------------------------------------------------------------------- */ + /* Property API */ + + /* note, 'target_set_handler' is defined in 'bpy_rna_manipulator.c' */ + func = RNA_def_function(srna, "target_set_prop", "rna_manipulator_target_set_prop"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + RNA_def_function_ui_description(func, ""); + parm = RNA_def_string(func, "target", NULL, 0, "", "Target property"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* similar to UILayout.prop */ + parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_int(func, "index", -1, -1, INT_MAX, "", "", -1, INT_MAX); /* RNA_NO_INDEX == -1 */ + + func = RNA_def_function(srna, "target_set_operator", "rna_manipulator_target_set_operator"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + RNA_def_function_ui_description( + func,"Operator to run when activating the manipulator " + "(overrides property targets)"); + parm = RNA_def_string(func, "operator", NULL, 0, "", "Target operator"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + /* similar to UILayout.operator */ + parm = RNA_def_pointer(func, "properties", "OperatorProperties", "", "Operator properties to fill in"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_function_return(func, parm); + +} + + +void RNA_api_manipulatorgroup(StructRNA *UNUSED(srna)) +{ + /* nothing yet */ +} + +#endif diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index be4db6477fe..967e90d22cb 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -65,6 +65,7 @@ set(SRC bpy_intern_string.c bpy_library_load.c bpy_library_write.c + bpy_manipulator_wrap.c bpy_operator.c bpy_operator_wrap.c bpy_path.c @@ -75,6 +76,7 @@ set(SRC bpy_rna_callback.c bpy_rna_driver.c bpy_rna_id_collection.c + bpy_rna_manipulator.c bpy_traceback.c bpy_util.c bpy_utils_previews.c @@ -97,6 +99,7 @@ set(SRC bpy_driver.h bpy_intern_string.h bpy_library.h + bpy_manipulator_wrap.h bpy_operator.h bpy_operator_wrap.h bpy_path.h @@ -106,6 +109,7 @@ set(SRC bpy_rna_callback.h bpy_rna_driver.h bpy_rna_id_collection.h + bpy_rna_manipulator.h bpy_traceback.h bpy_util.h bpy_utils_previews.h diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 5bbfb4912e6..4a29d4f8da1 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -46,6 +46,7 @@ #include "bpy_rna.h" #include "bpy_app.h" #include "bpy_rna_id_collection.h" +#include "bpy_rna_manipulator.h" #include "bpy_props.h" #include "bpy_library.h" #include "bpy_operator.h" @@ -327,6 +328,8 @@ void BPy_init_modules(void) BPY_rna_id_collection_module(mod); + BPY_rna_manipulator_module(mod); + bpy_import_test("bpy_types"); PyModule_AddObject(mod, "data", BPY_rna_module()); /* imports bpy_types by running this */ bpy_import_test("bpy_types"); diff --git a/source/blender/python/intern/bpy_intern_string.c b/source/blender/python/intern/bpy_intern_string.c index e9d84b2099b..6911e985e93 100644 --- a/source/blender/python/intern/bpy_intern_string.c +++ b/source/blender/python/intern/bpy_intern_string.c @@ -34,7 +34,7 @@ #include "BLI_utildefines.h" -static PyObject *bpy_intern_str_arr[15]; +static PyObject *bpy_intern_str_arr[16]; PyObject *bpy_intern_str___doc__; PyObject *bpy_intern_str___main__; @@ -44,6 +44,7 @@ PyObject *bpy_intern_str___slots__; PyObject *bpy_intern_str_attr; PyObject *bpy_intern_str_bl_property; PyObject *bpy_intern_str_bl_rna; +PyObject *bpy_intern_str_bl_target_properties; PyObject *bpy_intern_str_bpy_types; PyObject *bpy_intern_str_frame; PyObject *bpy_intern_str_order; @@ -67,6 +68,7 @@ void bpy_intern_string_init(void) BPY_INTERN_STR(bpy_intern_str_attr, "attr"); BPY_INTERN_STR(bpy_intern_str_bl_property, "bl_property"); BPY_INTERN_STR(bpy_intern_str_bl_rna, "bl_rna"); + BPY_INTERN_STR(bpy_intern_str_bl_target_properties, "bl_target_properties"); BPY_INTERN_STR(bpy_intern_str_bpy_types, "bpy.types"); BPY_INTERN_STR(bpy_intern_str_frame, "frame"); BPY_INTERN_STR(bpy_intern_str_order, "order"); diff --git a/source/blender/python/intern/bpy_intern_string.h b/source/blender/python/intern/bpy_intern_string.h index 66c469f70bc..998c312c321 100644 --- a/source/blender/python/intern/bpy_intern_string.h +++ b/source/blender/python/intern/bpy_intern_string.h @@ -38,6 +38,7 @@ extern PyObject *bpy_intern_str___slots__; extern PyObject *bpy_intern_str_attr; extern PyObject *bpy_intern_str_bl_property; extern PyObject *bpy_intern_str_bl_rna; +extern PyObject *bpy_intern_str_bl_target_properties; extern PyObject *bpy_intern_str_bpy_types; extern PyObject *bpy_intern_str_frame; extern PyObject *bpy_intern_str_order; diff --git a/source/blender/python/intern/bpy_manipulator_wrap.c b/source/blender/python/intern/bpy_manipulator_wrap.c new file mode 100644 index 00000000000..53b6285e880 --- /dev/null +++ b/source/blender/python/intern/bpy_manipulator_wrap.c @@ -0,0 +1,231 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_manipulator_wrap.c + * \ingroup pythonintern + * + * This file is so Python can define widget-group's that C can call into. + * The generic callback functions for Python widget-group are defines in + * 'rna_wm.c', some calling into functions here to do python specific + * functionality. + * + * \note This follows 'bpy_operator_wrap.c' very closely. + * Keep in sync unless there is good reason not to! + */ + +#include + +#include "BLI_utildefines.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "bpy_rna.h" +#include "bpy_intern_string.h" +#include "bpy_manipulator_wrap.h" /* own include */ + +/* we may want to add, but not now */ + +/* -------------------------------------------------------------------- */ + +/** \name Manipulator + * \{ */ + + +static bool bpy_manipulatortype_target_property_def( + wmManipulatorType *wt, PyObject *item) +{ + /* Note: names based on 'rna_rna.c' */ + PyObject *empty_tuple = PyTuple_New(0); + static const char * const _keywords[] = {"id", "type", "array_length", NULL}; + static _PyArg_Parser _parser = {"|$ssi:register_class", _keywords, 0}; + + struct { + char *id; + char *type_id; int type; + int array_length; + } params = { + .id = NULL, /* not optional */ + .type = PROP_FLOAT, + .type_id = NULL, + .array_length = 1, + }; + + if (!_PyArg_ParseTupleAndKeywordsFast( + empty_tuple, item, + &_parser, + ¶ms.id, + ¶ms.type_id, + ¶ms.array_length)) + { + goto fail; + } + + if (params.id == NULL) { + PyErr_SetString(PyExc_ValueError, "'id' argument not given"); + goto fail; + } + + if ((params.type_id != NULL) && + pyrna_enum_value_from_id( + rna_enum_property_type_items, params.type_id, ¶ms.type, "'type' enum value") == -1) + { + goto fail; + } + else { + params.type = rna_enum_property_type_items[params.type].value; + } + + if ((params.array_length < 1 || params.array_length > RNA_MAX_ARRAY_LENGTH)) { + PyErr_SetString(PyExc_ValueError, "'array_length' out of range"); + goto fail; + } + + WM_manipulatortype_target_property_def(wt, params.id, params.type, params.array_length); + Py_DECREF(empty_tuple); + return true; + +fail: + Py_DECREF(empty_tuple); + return false; +} + +static void manipulator_properties_init(wmManipulatorType *wt) +{ + PyTypeObject *py_class = wt->ext.data; + RNA_struct_blender_type_set(wt->ext.srna, wt); + + /* only call this so pyrna_deferred_register_class gives a useful error + * WM_operatortype_append_ptr will call RNA_def_struct_identifier + * later */ + RNA_def_struct_identifier(wt->srna, wt->idname); + + if (pyrna_deferred_register_class(wt->srna, py_class) != 0) { + PyErr_Print(); /* failed to register operator props */ + PyErr_Clear(); + } + + /* Extract target property definitions from 'bl_target_properties' */ + { + /* picky developers will notice that 'bl_targets' won't work with inheritance + * get direct from the dict to avoid raising a load of attribute errors (yes this isnt ideal) - campbell */ + PyObject *py_class_dict = py_class->tp_dict; + PyObject *bl_target_properties = PyDict_GetItem(py_class_dict, bpy_intern_str_bl_target_properties); + PyObject *bl_target_properties_fast; + + if (!(bl_target_properties_fast = PySequence_Fast(bl_target_properties, "bl_target_properties sequence"))) { + /* PySequence_Fast sets the error */ + PyErr_Print(); + PyErr_Clear(); + return; + } + + const uint items_len = PySequence_Fast_GET_SIZE(bl_target_properties_fast); + PyObject **items = PySequence_Fast_ITEMS(bl_target_properties_fast); + + for (uint i = 0; i < items_len; i++) { + if (!bpy_manipulatortype_target_property_def(wt, items[i])) { + PyErr_Print(); + PyErr_Clear(); + break; + } + } + + Py_DECREF(bl_target_properties_fast); + } +} + +void BPY_RNA_manipulator_wrapper(wmManipulatorType *wt, void *userdata) +{ + /* take care not to overwrite anything set in + * WM_manipulatormaptype_group_link_ptr before opfunc() is called */ + StructRNA *srna = wt->srna; + *wt = *((wmManipulatorType *)userdata); + wt->srna = srna; /* restore */ + + /* don't do translations here yet */ +#if 0 + /* Use i18n context from ext.srna if possible (py manipulatorgroups). */ + if (wt->ext.srna) { + RNA_def_struct_translation_context(wt->srna, RNA_struct_translation_context(wt->ext.srna)); + } +#endif + + wt->struct_size = sizeof(wmManipulator); + + manipulator_properties_init(wt); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \name Manipulator Group + * \{ */ + +static void manipulatorgroup_properties_init(wmManipulatorGroupType *wgt) +{ +#ifdef USE_SRNA + PyTypeObject *py_class = wgt->ext.data; +#endif + RNA_struct_blender_type_set(wgt->ext.srna, wgt); + +#ifdef USE_SRNA + /* only call this so pyrna_deferred_register_class gives a useful error + * WM_operatortype_append_ptr will call RNA_def_struct_identifier + * later */ + RNA_def_struct_identifier(wgt->srna, wgt->idname); + + if (pyrna_deferred_register_class(wgt->srna, py_class) != 0) { + PyErr_Print(); /* failed to register operator props */ + PyErr_Clear(); + } +#endif +} + +void BPY_RNA_manipulatorgroup_wrapper(wmManipulatorGroupType *wgt, void *userdata) +{ + /* take care not to overwrite anything set in + * WM_manipulatormaptype_group_link_ptr before opfunc() is called */ +#ifdef USE_SRNA + StructRNA *srna = wgt->srna; +#endif + *wgt = *((wmManipulatorGroupType *)userdata); +#ifdef USE_SRNA + wgt->srna = srna; /* restore */ +#endif + +#ifdef USE_SRNA + /* Use i18n context from ext.srna if possible (py manipulatorgroups). */ + if (wgt->ext.srna) { + RNA_def_struct_translation_context(wgt->srna, RNA_struct_translation_context(wgt->ext.srna)); + } +#endif + + manipulatorgroup_properties_init(wgt); +} + +/** \} */ + diff --git a/source/blender/python/intern/bpy_manipulator_wrap.h b/source/blender/python/intern/bpy_manipulator_wrap.h new file mode 100644 index 00000000000..3f739e26059 --- /dev/null +++ b/source/blender/python/intern/bpy_manipulator_wrap.h @@ -0,0 +1,36 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_manipulator_wrap.h + * \ingroup pythonintern + */ + +#ifndef __BPY_MANIPULATOR_WRAP_H__ +#define __BPY_MANIPULATOR_WRAP_H__ + +struct wmManipulatorType; +struct wmManipulatorGroupType; + +/* exposed to rna/wm api */ +void BPY_RNA_manipulator_wrapper(struct wmManipulatorType *wt, void *userdata); +void BPY_RNA_manipulatorgroup_wrapper(struct wmManipulatorGroupType *wgt, void *userdata); + +#endif /* __BPY_MANIPULATOR_WRAP_H__ */ + diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 6f3d0145d87..51e179fb317 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1839,19 +1839,28 @@ static int pyrna_py_to_prop( * class mixing if this causes problems in the future it should be removed. */ if ((ptr_type == &RNA_AnyType) && - (BPy_StructRNA_Check(value)) && - (RNA_struct_is_a(((BPy_StructRNA *)value)->ptr.type, &RNA_Operator))) + (BPy_StructRNA_Check(value))) { - value = PyObject_GetAttr(value, bpy_intern_str_properties); - value_new = value; + const StructRNA *base_type = + RNA_struct_base_child_of(((const BPy_StructRNA *)value)->ptr.type, NULL); + if (ELEM(base_type, &RNA_Operator, &RNA_Manipulator)) { + value = PyObject_GetAttr(value, bpy_intern_str_properties); + value_new = value; + } } - - /* if property is an OperatorProperties pointer and value is a map, + /* if property is an OperatorProperties/ManipulatorProperties pointer and value is a map, * forward back to pyrna_pydict_to_props */ - if (RNA_struct_is_a(ptr_type, &RNA_OperatorProperties) && PyDict_Check(value)) { - PointerRNA opptr = RNA_property_pointer_get(ptr, prop); - return pyrna_pydict_to_props(&opptr, value, false, error_prefix); + if (PyDict_Check(value)) { + const StructRNA *base_type = RNA_struct_base_child_of(ptr_type, NULL); + if (base_type == &RNA_OperatorProperties) { + PointerRNA opptr = RNA_property_pointer_get(ptr, prop); + return pyrna_pydict_to_props(&opptr, value, false, error_prefix); + } + else if (base_type == &RNA_ManipulatorProperties) { + PointerRNA opptr = RNA_property_pointer_get(ptr, prop); + return pyrna_pydict_to_props(&opptr, value, false, error_prefix); + } } /* another exception, allow to pass a collection as an RNA property */ @@ -6926,7 +6935,7 @@ static PyObject *pyrna_basetype_dir(BPy_BaseTypeRNA *self) StructRNA *srna = itemptr.data; StructRNA *srna_base = RNA_struct_base(itemptr.data); /* skip own operators, these double up [#29666] */ - if (srna_base == &RNA_Operator) { + if (ELEM(srna_base, &RNA_Operator, &RNA_Manipulator)) { /* do nothing */ } else { @@ -7456,7 +7465,8 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param PyGILState_STATE gilstate; #ifdef USE_PEDANTIC_WRITE - const bool is_operator = RNA_struct_is_a(ptr->type, &RNA_Operator); + const bool is_readonly_init = !(RNA_struct_is_a(ptr->type, &RNA_Operator) || + RNA_struct_is_a(ptr->type, &RNA_Manipulator)); // const char *func_id = RNA_function_identifier(func); /* UNUSED */ /* testing, for correctness, not operator and not draw function */ const bool is_readonly = !(RNA_function_flag(func) & FUNC_ALLOW_WRITE); @@ -7521,7 +7531,7 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param if (py_class->tp_init) { #ifdef USE_PEDANTIC_WRITE const int prev_write = rna_disallow_writes; - rna_disallow_writes = is_operator ? false : true; /* only operators can write on __init__ */ + rna_disallow_writes = is_readonly_init ? false : true; /* only operators can write on __init__ */ #endif /* true in most cases even when the class its self doesn't define an __init__ function. */ diff --git a/source/blender/python/intern/bpy_rna_manipulator.c b/source/blender/python/intern/bpy_rna_manipulator.c new file mode 100644 index 00000000000..245735f679e --- /dev/null +++ b/source/blender/python/intern/bpy_rna_manipulator.c @@ -0,0 +1,341 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_rna_manipulator.c + * \ingroup pythonintern + * + * . + */ + +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "BKE_main.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "bpy_util.h" +#include "bpy_rna_manipulator.h" + +#include "../generic/py_capi_utils.h" +#include "../generic/python_utildefines.h" + +#include "RNA_access.h" +#include "RNA_types.h" +#include "RNA_enum_types.h" + +#include "bpy_rna.h" + +enum { + BPY_MANIPULATOR_FN_SLOT_GET = 0, + BPY_MANIPULATOR_FN_SLOT_SET, + BPY_MANIPULATOR_FN_SLOT_RANGE_GET, +}; +#define BPY_MANIPULATOR_FN_SLOT_LEN (BPY_MANIPULATOR_FN_SLOT_RANGE_GET + 1) + +struct BPyManipulatorHandlerUserData { + + PyObject *fn_slots[BPY_MANIPULATOR_FN_SLOT_LEN]; +}; + +static void py_rna_manipulator_handler_get_cb( + const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, + void *value_p) +{ + PyGILState_STATE gilstate = PyGILState_Ensure(); + + struct BPyManipulatorHandlerUserData *data = mpr_prop->custom_func.user_data; + PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_MANIPULATOR_FN_SLOT_GET], NULL); + if (ret == NULL) { + goto fail; + } + + if (mpr_prop->type->data_type == PROP_FLOAT) { + float *value = value_p; + if (mpr_prop->type->array_length == 1) { + if (((*value = PyFloat_AsDouble(ret)) == -1.0f && PyErr_Occurred()) == 0) { + goto fail; + } + } + else { + if (PyC_AsArray(value, ret, mpr_prop->type->array_length, &PyFloat_Type, false, + "Manipulator get callback: ") == -1) + { + goto fail; + } + } + } + else { + PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type"); + goto fail; + } + + Py_DECREF(ret); + + PyGILState_Release(gilstate); + return; + +fail: + PyErr_Print(); + PyErr_Clear(); + + PyGILState_Release(gilstate); +} + +static void py_rna_manipulator_handler_set_cb( + const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, + const void *value_p) +{ + PyGILState_STATE gilstate = PyGILState_Ensure(); + + struct BPyManipulatorHandlerUserData *data = mpr_prop->custom_func.user_data; + + PyObject *args = PyTuple_New(1); + + if (mpr_prop->type->data_type == PROP_FLOAT) { + const float *value = value_p; + PyObject *py_value; + if (mpr_prop->type->array_length == 1) { + py_value = PyFloat_FromDouble(*value); + } + else { + py_value = PyC_FromArray((void *)value, mpr_prop->type->array_length, &PyFloat_Type, false, + "Manipulator set callback: "); + } + if (py_value == NULL) { + goto fail; + } + PyTuple_SET_ITEM(args, 0, py_value); + } + else { + PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type"); + goto fail; + } + + PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_MANIPULATOR_FN_SLOT_SET], args); + if (ret == NULL) { + goto fail; + } + Py_DECREF(ret); + + PyGILState_Release(gilstate); + return; + +fail: + PyErr_Print(); + PyErr_Clear(); + + Py_DECREF(args); + + PyGILState_Release(gilstate); +} + +static void py_rna_manipulator_handler_range_get_cb( + const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop, + void *value_p) +{ + struct BPyManipulatorHandlerUserData *data = mpr_prop->custom_func.user_data; + + PyGILState_STATE gilstate = PyGILState_Ensure(); + + PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_MANIPULATOR_FN_SLOT_RANGE_GET], NULL); + if (ret == NULL) { + goto fail; + } + + if (!PyTuple_Check(ret)) { + PyErr_Format(PyExc_TypeError, + "Expected a tuple, not %.200s", + Py_TYPE(ret)->tp_name); + goto fail; + } + + if (PyTuple_GET_SIZE(ret) != 2) { + PyErr_Format(PyExc_TypeError, + "Expected a tuple of size 2, not %d", + PyTuple_GET_SIZE(ret)); + goto fail; + } + + if (mpr_prop->type->data_type == PROP_FLOAT) { + float range[2]; + for (int i = 0; i < 2; i++) { + if (((range[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(ret, i))) == -1.0f && PyErr_Occurred()) == 0) { + /* pass */ + } + else { + goto fail; + } + } + memcpy(value_p, range, sizeof(range)); + } + else { + PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type"); + goto fail; + } + + Py_DECREF(ret); + PyGILState_Release(gilstate); + return; + +fail: + Py_XDECREF(ret); + + PyErr_Print(); + PyErr_Clear(); + + PyGILState_Release(gilstate); +} + +static void py_rna_manipulator_handler_free_cb( + const wmManipulator *UNUSED(mpr), wmManipulatorProperty *mpr_prop) +{ + struct BPyManipulatorHandlerUserData *data = mpr_prop->custom_func.user_data; + + PyGILState_STATE gilstate = PyGILState_Ensure(); + for (int i = 0; i < BPY_MANIPULATOR_FN_SLOT_LEN; i++) { + Py_XDECREF(data->fn_slots[i]); + } + PyGILState_Release(gilstate); + + MEM_freeN(data); + +} + +PyDoc_STRVAR(bpy_manipulator_target_set_handler_doc, +".. method:: target_set_handler(target, get, set, range=None):\n" +"\n" +" Assigns callbacks to a manipulators property.\n" +"\n" +" :arg get: Function that returns the value for this property (single value or sequence).\n" +" :type get: callable\n" +" :arg set: Function that takes a single value argument and applies it.\n" +" :type set: callable\n" +" :arg range: Function that returns a (min, max) tuple for manipulators that use a range.\n" +" :type range: callable\n" +); +static PyObject *bpy_manipulator_target_set_handler(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) +{ + /* Note: this is a counter-part to functions: + * 'Manipulator.target_set_prop & target_set_operator' + * (see: rna_wm_manipulator_api.c). conventions should match. */ + static const char * const _keywords[] = {"self", "target", "get", "set", "range", NULL}; + static _PyArg_Parser _parser = {"Os|$OOO:target_set_handler", _keywords, 0}; + + PyGILState_STATE gilstate = PyGILState_Ensure(); + + struct { + PyObject *self; + char *target; + PyObject *py_fn_slots[BPY_MANIPULATOR_FN_SLOT_LEN]; + } params = { + .self = NULL, + .target = NULL, + .py_fn_slots = {NULL}, + }; + + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, + &_parser, + ¶ms.self, + ¶ms.target, + ¶ms.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_GET], + ¶ms.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_SET], + ¶ms.py_fn_slots[BPY_MANIPULATOR_FN_SLOT_RANGE_GET])) + { + goto fail; + } + + wmManipulator *mpr = ((BPy_StructRNA *)params.self)->ptr.data; + + const wmManipulatorPropertyType *mpr_prop_type = + WM_manipulatortype_target_property_find(mpr->type, params.target); + if (mpr_prop_type == NULL) { + PyErr_Format(PyExc_ValueError, + "Manipulator target property '%s.%s' not found", + mpr->type->idname, params.target); + goto fail; + } + + { + const int slots_required = 2; + const int slots_start = 2; + for (int i = 0; i < BPY_MANIPULATOR_FN_SLOT_LEN; i++) { + if (params.py_fn_slots[i] == NULL) { + if (i < slots_required) { + PyErr_Format(PyExc_ValueError, "Argument '%s' not given", _keywords[slots_start + i]); + goto fail; + } + } + else if (!PyCallable_Check(params.py_fn_slots[i])) { + PyErr_Format(PyExc_ValueError, "Argument '%s' not callable", _keywords[slots_start + i]); + goto fail; + } + } + } + + struct BPyManipulatorHandlerUserData *data = MEM_callocN(sizeof(*data), __func__); + + for (int i = 0; i < BPY_MANIPULATOR_FN_SLOT_LEN; i++) { + data->fn_slots[i] = params.py_fn_slots[i]; + Py_XINCREF(params.py_fn_slots[i]); + } + + WM_manipulator_target_property_def_func_ptr( + mpr, mpr_prop_type, + &(const struct wmManipulatorPropertyFnParams) { + .value_get_fn = py_rna_manipulator_handler_get_cb, + .value_set_fn = py_rna_manipulator_handler_set_cb, + .range_get_fn = py_rna_manipulator_handler_range_get_cb, + .free_fn = py_rna_manipulator_handler_free_cb, + .user_data = data, + }); + + PyGILState_Release(gilstate); + + Py_RETURN_NONE; + +fail: + PyGILState_Release(gilstate); + return NULL; +} + +int BPY_rna_manipulator_module(PyObject *mod_par) +{ + static PyMethodDef method_def = { + "target_set_handler", (PyCFunction)bpy_manipulator_target_set_handler, METH_VARARGS | METH_KEYWORDS, + bpy_manipulator_target_set_handler_doc}; + + PyObject *func = PyCFunction_New(&method_def, NULL); + PyObject *func_inst = PyInstanceMethod_New(func); + + + /* TODO, return a type that binds nearly to a method. */ + PyModule_AddObject(mod_par, "_rna_manipulator_target_set_handler", func_inst); + + return 0; +} + + diff --git a/source/blender/python/intern/bpy_rna_manipulator.h b/source/blender/python/intern/bpy_rna_manipulator.h new file mode 100644 index 00000000000..b6f3a2e651d --- /dev/null +++ b/source/blender/python/intern/bpy_rna_manipulator.h @@ -0,0 +1,32 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * 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. + * + * Contributor(s): Bastien Montagne + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/python/intern/bpy_rna_manipulator.h + * \ingroup pythonintern + */ + +#ifndef __BPY_RNA_MANIPULATOR_H__ +#define __BPY_RNA_MANIPULATOR_H__ + +int BPY_rna_manipulator_module(PyObject *); + +#endif /* __BPY_RNA_MANIPULATOR_H__ */ -- cgit v1.2.3