static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, ItemTypeCheckFunc check_item_type, const char *item_type_str, int *totitem, const char *error_prefix) { int dimsize[MAX_ARRAY_DIMENSION]; int totdim = RNA_property_array_dimension(ptr, prop, dimsize); /* validate type first because length validation may modify property array length */ #ifdef USE_MATHUTILS if (lvalue_dim == 0) { /* only valid for first level array */ if (MatrixObject_Check(rvalue)) { MatrixObject *pymat = (MatrixObject *)rvalue; if (BaseMath_ReadCallback(pymat) == -1) return -1; if (RNA_property_type(prop) != PROP_FLOAT) { PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, matrix assign to non float array", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop)); return -1; } else if (totdim != 2) { PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, matrix assign array with %d dimensions", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), totdim); return -1; } else if (pymat->num_col != dimsize[0] || pymat->num_row != dimsize[1]) { PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, matrix assign dimension size mismatch, " "is %dx%d, expected be %dx%d", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), pymat->num_col, pymat->num_row, dimsize[0], dimsize[1]); return -1; } else { *totitem = dimsize[0] * dimsize[1]; return 0; } } } #endif /* USE_MATHUTILS */ { if (validate_array_type(rvalue, lvalue_dim, totdim, dimsize, check_item_type, item_type_str, error_prefix) == -1) return -1; return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, error_prefix); } }
static int file_panel_check_prop(PropertyRNA *prop) { const char *prop_id= RNA_property_identifier(prop); return !( strcmp(prop_id, "filepath") == 0 || strcmp(prop_id, "directory") == 0 || strcmp(prop_id, "filename") == 0 ); }
static bool file_panel_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop) { const char *prop_id = RNA_property_identifier(prop); return !(STREQ(prop_id, "filepath") || STREQ(prop_id, "directory") || STREQ(prop_id, "filename") ); }
static bool screenshot_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop, void *UNUSED(user_data)) { const char *prop_id = RNA_property_identifier(prop); return !(STREQ(prop_id, "filepath")); }
static int py_to_array_index(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int arrayoffset, int index, ItemTypeCheckFunc check_item_type, const char *item_type_str, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index, const char *error_prefix) { int totdim, dimsize[MAX_ARRAY_DIMENSION]; int totitem, i; totdim = RNA_property_array_dimension(ptr, prop, dimsize); /* convert index */ /* arr[3][4][5] * * arr[2] = x * lvalue_dim = 0, index = 0 + 2 * 4 * 5 * * arr[2][3] = x * lvalue_dim = 1, index = 40 + 3 * 5 */ lvalue_dim++; for (i = lvalue_dim; i < totdim; i++) index *= dimsize[i]; index += arrayoffset; if (lvalue_dim == totdim) { /* single item, assign directly */ if (!check_item_type(py)) { PyErr_Format(PyExc_TypeError, "%s %.200s.%.200s, expected a %s type, not %s", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), item_type_str, Py_TYPE(py)->tp_name); return -1; } copy_value_single(py, ptr, prop, NULL, 0, &index, convert_item, rna_set_index); } else { if (validate_array(py, ptr, prop, lvalue_dim, check_item_type, item_type_str, &totitem, error_prefix) == -1) { return -1; } if (totitem) { copy_values(py, ptr, prop, lvalue_dim, NULL, 0, &index, convert_item, rna_set_index); } } return 0; }
/* medium match strictness: path match only (i.e. ignore ID) */ static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short from_single, const short UNUSED(to_simple)) { tAnimCopybufItem *aci; for (aci= animcopybuf.first; aci; aci= aci->next) { /* check that paths exist */ if (aci->rna_path && fcu->rna_path) { /* find the property of the fcurve and compare against the end of the tAnimCopybufItem * more involved since it needs to to path lookups. * This is not 100% reliable since the user could be editing the curves on a path that wont * resolve, or a bone could be renamed after copying for eg. but in normal copy & paste * this should work out ok. */ if (BLI_findindex(which_libbase(G.main, aci->id_type), aci->id) == -1) { /* pedantic but the ID could have been removed, and beats crashing! */ printf("paste_animedit_keys: error ID has been removed!\n"); } else { PointerRNA id_ptr, rptr; PropertyRNA *prop; RNA_id_pointer_create(aci->id, &id_ptr); RNA_path_resolve(&id_ptr, aci->rna_path, &rptr, &prop); if (prop) { const char *identifier= RNA_property_identifier(prop); int len_id = strlen(identifier); int len_path = strlen(fcu->rna_path); if (len_id <= len_path) { /* note, paths which end with "] will fail with this test - Animated ID Props */ if (strcmp(identifier, fcu->rna_path + (len_path-len_id))==0) { if ((from_single) || (aci->array_index == fcu->array_index)) break; } } } else { printf("paste_animedit_keys: failed to resolve path id:%s, '%s'!\n", aci->id->name, aci->rna_path); } } } } return aci; }
static EnumPropertyItem *dt_layers_select_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free) { const bool reverse_transfer = RNA_boolean_get(ptr, "use_reverse_transfer"); if (STREQ(RNA_property_identifier(prop), "layers_select_dst")) { if (reverse_transfer) { return dt_layers_select_src_itemf(C, ptr, prop, r_free); } else { return dt_layers_select_dst_itemf(C, ptr, prop, r_free); } } else if (reverse_transfer) { return dt_layers_select_dst_itemf(C, ptr, prop, r_free); } else { return dt_layers_select_src_itemf(C, ptr, prop, r_free); } }
/* Hide one of offset or offset_pct, depending on offset_type */ static bool edbm_bevel_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) { const char *prop_id = RNA_property_identifier(prop); if (STRPREFIX(prop_id, "offset")) { int offset_type = RNA_enum_get(op->ptr, "offset_type"); if (STREQ(prop_id, "offset") && offset_type == BEVEL_AMT_PERCENT) { return false; } else if (STREQ(prop_id, "offset_pct") && offset_type != BEVEL_AMT_PERCENT) { return false; } } return true; }
/* Used by both OBJECT_OT_data_transfer and OBJECT_OT_datalayout_transfer */ static bool data_transfer_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) { PropertyRNA *prop_other; const char *prop_id = RNA_property_identifier(prop); const int data_type = RNA_enum_get(ptr, "data_type"); bool use_auto_transform = false; bool use_max_distance = false; bool use_modifier = false; if ((prop_other = RNA_struct_find_property(ptr, "use_auto_transform"))) { use_auto_transform = RNA_property_boolean_get(ptr, prop_other); } if ((prop_other = RNA_struct_find_property(ptr, "use_max_distance"))) { use_max_distance = RNA_property_boolean_get(ptr, prop_other); } if ((prop_other = RNA_struct_find_property(ptr, "modifier"))) { use_modifier = RNA_property_is_set(ptr, prop_other); } if (STREQ(prop_id, "modifier")) { return use_modifier; } if (use_modifier) { /* Hide everything but 'modifier' property, if set. */ return false; } if (STREQ(prop_id, "use_object_transform") && use_auto_transform) { return false; } if (STREQ(prop_id, "max_distance") && !use_max_distance) { return false; } if (STREQ(prop_id, "islands_precision") && !DT_DATATYPE_IS_LOOP(data_type)) { return false; } if (STREQ(prop_id, "vert_mapping") && !DT_DATATYPE_IS_VERT(data_type)) { return false; } if (STREQ(prop_id, "edge_mapping") && !DT_DATATYPE_IS_EDGE(data_type)) { return false; } if (STREQ(prop_id, "loop_mapping") && !DT_DATATYPE_IS_LOOP(data_type)) { return false; } if (STREQ(prop_id, "poly_mapping") && !DT_DATATYPE_IS_POLY(data_type)) { return false; } if ((STREQ(prop_id, "layers_select_src") || STREQ(prop_id, "layers_select_dst")) && !DT_DATATYPE_IS_MULTILAYERS(data_type)) { return false; } /* Else, show it! */ return true; }
static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop) { const char *prop_id = RNA_property_identifier(prop); const bool link_strokes = RNA_boolean_get(ptr, "use_link_strokes"); int timing_mode = RNA_enum_get(ptr, "timing_mode"); bool realtime = RNA_boolean_get(ptr, "use_realtime"); float gap_duration = RNA_float_get(ptr, "gap_duration"); float gap_randomness = RNA_float_get(ptr, "gap_randomness"); const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data"); /* Always show those props */ if (STREQ(prop_id, "type") || STREQ(prop_id, "use_normalize_weights") || STREQ(prop_id, "radius_multiplier") || STREQ(prop_id, "use_link_strokes")) { return true; } /* Never show this prop */ if (STREQ(prop_id, "use_timing_data")) return false; if (link_strokes) { /* Only show when link_stroke is true */ if (STREQ(prop_id, "timing_mode")) return true; if (timing_mode != GP_STROKECONVERT_TIMING_NONE) { /* Only show when link_stroke is true and stroke timing is enabled */ if (STREQ(prop_id, "frame_range") || STREQ(prop_id, "start_frame")) { return true; } /* Only show if we have valid timing data! */ if (valid_timing && STREQ(prop_id, "use_realtime")) return true; /* Only show if realtime or valid_timing is false! */ if ((!realtime || !valid_timing) && STREQ(prop_id, "end_frame")) return true; if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) { /* Only show for custom gaps! */ if (STREQ(prop_id, "gap_duration")) return true; /* Only show randomness for non-null custom gaps! */ if (STREQ(prop_id, "gap_randomness") && (gap_duration > 0.0f)) return true; /* Only show seed for randomize action! */ if (STREQ(prop_id, "seed") && (gap_duration > 0.0f) && (gap_randomness > 0.0f)) return true; } } } /* Else, hidden! */ return false; }
/* Helper for ANIM_add_driver_with_target - Adds the actual driver */ static int add_driver_with_target(ReportList *UNUSED(reports), ID *dst_id, const char dst_path[], int dst_index, ID *src_id, const char src_path[], int src_index, PointerRNA *dst_ptr, PropertyRNA *dst_prop, PointerRNA *src_ptr, PropertyRNA *src_prop, short flag, int driver_type) { FCurve *fcu; short add_mode = (flag & CREATEDRIVER_WITH_FMODIFIER) ? 2 : 1; const char *prop_name = RNA_property_identifier(src_prop); /* Create F-Curve with Driver */ fcu = verify_driver_fcurve(dst_id, dst_path, dst_index, add_mode); if (fcu && fcu->driver) { ChannelDriver *driver = fcu->driver; DriverVar *dvar; /* Set the type of the driver */ driver->type = driver_type; /* Set driver expression, so that the driver works out of the box * * The following checks define a bit of "autodetection magic" we use * to ensure that the drivers will behave as expected out of the box * when faced with properties with different units. */ /* XXX: if we have N-1 mapping, should we include all those in the expression? */ if ((RNA_property_unit(dst_prop) == PROP_UNIT_ROTATION) && (RNA_property_unit(src_prop) != PROP_UNIT_ROTATION)) { /* Rotation Destination: normal -> radians, so convert src to radians * (However, if both input and output is a rotation, don't apply such corrections) */ BLI_strncpy(driver->expression, "radians(var)", sizeof(driver->expression)); } else if ((RNA_property_unit(src_prop) == PROP_UNIT_ROTATION) && (RNA_property_unit(dst_prop) != PROP_UNIT_ROTATION)) { /* Rotation Source: radians -> normal, so convert src to degrees * (However, if both input and output is a rotation, don't apply such corrections) */ BLI_strncpy(driver->expression, "degrees(var)", sizeof(driver->expression)); } else { /* Just a normal property without any unit problems */ BLI_strncpy(driver->expression, "var", sizeof(driver->expression)); } /* Create a driver variable for the target * - For transform properties, we want to automatically use "transform channel" instead * (The only issue is with quat rotations vs euler channels...) * - To avoid problems with transform properties depending on the final transform that they * control (thus creating pseudo-cycles - see T48734), we don't use transform channels * when both the source and destinations are in same places. */ dvar = driver_add_new_variable(driver); if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) && (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")) && (src_ptr->data != dst_ptr->data)) { /* Transform Channel */ DriverTarget *dtar; driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN); dtar = &dvar->targets[0]; /* Bone or Object target? */ dtar->id = src_id; dtar->idtype = GS(src_id->name); if (src_ptr->type == &RNA_PoseBone) { RNA_string_get(src_ptr, "name", dtar->pchan_name); } /* Transform channel depends on type */ if (STREQ(prop_name, "location")) { if (src_index == 2) { dtar->transChan = DTAR_TRANSCHAN_LOCZ; } else if (src_index == 1) { dtar->transChan = DTAR_TRANSCHAN_LOCY; } else { dtar->transChan = DTAR_TRANSCHAN_LOCX; } } else if (STREQ(prop_name, "scale")) { if (src_index == 2) { dtar->transChan = DTAR_TRANSCHAN_SCALEZ; } else if (src_index == 1) { dtar->transChan = DTAR_TRANSCHAN_SCALEY; } else { dtar->transChan = DTAR_TRANSCHAN_SCALEX; } } else { /* XXX: With quaternions and axis-angle, this mapping might not be correct... * But since those have 4 elements instead, there's not much we can do */ if (src_index == 2) { dtar->transChan = DTAR_TRANSCHAN_ROTZ; } else if (src_index == 1) { dtar->transChan = DTAR_TRANSCHAN_ROTY; } else { dtar->transChan = DTAR_TRANSCHAN_ROTX; } } } else { /* Single RNA Property */ DriverTarget *dtar = &dvar->targets[0]; /* ID is as-is */ dtar->id = src_id; dtar->idtype = GS(src_id->name); /* Need to make a copy of the path (or build one with array index built in) */ if (RNA_property_array_check(src_prop)) { dtar->rna_path = BLI_sprintfN("%s[%d]", src_path, src_index); } else { dtar->rna_path = BLI_strdup(src_path); } } } /* set the done status */ return (fcu != NULL); }
static int file_browse_exec(bContext *C, wmOperator *op) { FileBrowseOp *fbo = op->customdata; ID *id; char *str, path[FILE_MAX]; const char *path_prop = RNA_struct_find_property(op->ptr, "directory") ? "directory" : "filepath"; if (RNA_struct_property_is_set(op->ptr, path_prop) == 0 || fbo == NULL) return OPERATOR_CANCELLED; str = RNA_string_get_alloc(op->ptr, path_prop, NULL, 0); /* add slash for directories, important for some properties */ if (RNA_property_subtype(fbo->prop) == PROP_DIRPATH) { const bool is_relative = RNA_boolean_get(op->ptr, "relative_path"); id = fbo->ptr.id.data; BLI_strncpy(path, str, FILE_MAX); BLI_path_abs(path, id ? ID_BLEND_PATH(G.main, id) : G.main->name); if (BLI_is_dir(path)) { /* do this first so '//' isnt converted to '//\' on windows */ BLI_add_slash(path); if (is_relative) { BLI_strncpy(path, str, FILE_MAX); BLI_path_rel(path, G.main->name); str = MEM_reallocN(str, strlen(path) + 2); BLI_strncpy(str, path, FILE_MAX); } else { str = MEM_reallocN(str, strlen(str) + 2); } } else { char * const lslash = (char *)BLI_last_slash(str); if (lslash) lslash[1] = '\0'; } } RNA_property_string_set(&fbo->ptr, fbo->prop, str); RNA_property_update(C, &fbo->ptr, fbo->prop); MEM_freeN(str); if (fbo->is_undo) { const char *undostr = RNA_property_identifier(fbo->prop); ED_undo_push(C, undostr); } /* special, annoying exception, filesel on redo panel [#26618] */ { wmOperator *redo_op = WM_operator_last_redo(C); if (redo_op) { if (fbo->ptr.data == redo_op->ptr->data) { ED_undo_operator_repeat(C, redo_op); } } } MEM_freeN(op->customdata); return OPERATOR_FINISHED; }
static int screenshot_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop) { const char *prop_id = RNA_property_identifier(prop); return !(strcmp(prop_id, "filepath") == 0); }
/* Modifies property array length if needed and PROP_DYNAMIC flag is set. */ static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int *totitem, const char *error_prefix) { int dimsize[MAX_ARRAY_DIMENSION]; int tot, totdim, len; totdim = RNA_property_array_dimension(ptr, prop, dimsize); tot = count_items(rvalue, totdim - lvalue_dim); if (tot == -1) { PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, error validating the sequence length", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop)); return -1; } else if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) { if (RNA_property_array_length(ptr, prop) != tot) { #if 0 /* length is flexible */ if (!RNA_property_dynamic_array_set_length(ptr, prop, tot)) { /* BLI_snprintf(error_str, error_str_size, * "%s.%s: array length cannot be changed to %d", * RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot); */ PyErr_Format(PyExc_ValueError, "%s %s.%s: array length cannot be changed to %d", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot); return -1; } #else *totitem = tot; return 0; #endif } len = tot; } else { /* length is a constraint */ if (!lvalue_dim) { len = RNA_property_array_length(ptr, prop); } /* array item assignment */ else { int i; len = 1; /* arr[3][4][5] * * arr[2] = x * dimsize = {4, 5} * dimsize[1] = 4 * dimsize[2] = 5 * lvalue_dim = 0, totdim = 3 * * arr[2][3] = x * lvalue_dim = 1 * * arr[2][3][4] = x * lvalue_dim = 2 */ for (i = lvalue_dim; i < totdim; i++) len *= dimsize[i]; } if (tot != len) { /* BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); */ PyErr_Format(PyExc_ValueError, "%s %.200s.%.200s, sequence must have %d items total, not %d", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), len, tot); return -1; } } *totitem = len; return 0; }