static int report_copy_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceInfo *sinfo = CTX_wm_space_info(C); ReportList *reports = CTX_wm_reports(C); int report_mask = info_report_mask(sinfo); Report *report; DynStr *buf_dyn = BLI_dynstr_new(); char *buf_str; for (report = reports->list.first; report; report = report->next) { if ((report->type & report_mask) && (report->flag & SELECT)) { BLI_dynstr_append(buf_dyn, report->message); BLI_dynstr_append(buf_dyn, "\n"); } } buf_str = BLI_dynstr_get_cstring(buf_dyn); BLI_dynstr_free(buf_dyn); WM_clipboard_text_set(buf_str, 0); MEM_freeN(buf_str); return OPERATOR_FINISHED; }
static int console_copy_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceConsole *sc = CTX_wm_space_console(C); DynStr *buf_dyn; char *buf_str; ConsoleLine *cl; int sel[2]; int offset = 0; ConsoleLine cl_dummy = {NULL}; if (sc->sel_start == sc->sel_end) return OPERATOR_CANCELLED; console_scrollback_prompt_begin(sc, &cl_dummy); for (cl = sc->scrollback.first; cl; cl = cl->next) { offset += cl->len + 1; } if (offset == 0) { console_scrollback_prompt_end(sc, &cl_dummy); return OPERATOR_CANCELLED; } buf_dyn = BLI_dynstr_new(); offset -= 1; sel[0] = offset - sc->sel_end; sel[1] = offset - sc->sel_start; for (cl = sc->scrollback.first; cl; cl = cl->next) { if (sel[0] <= cl->len && sel[1] >= 0) { int sta = max_ii(sel[0], 0); int end = min_ii(sel[1], cl->len); if (BLI_dynstr_get_len(buf_dyn)) BLI_dynstr_append(buf_dyn, "\n"); BLI_dynstr_nappend(buf_dyn, cl->line + sta, end - sta); } sel[0] -= cl->len + 1; sel[1] -= cl->len + 1; } buf_str = BLI_dynstr_get_cstring(buf_dyn); BLI_dynstr_free(buf_dyn); WM_clipboard_text_set(buf_str, 0); MEM_freeN(buf_str); console_scrollback_prompt_end(sc, &cl_dummy); return OPERATOR_FINISHED; }
static void console_cursor_set_exit(bContext *UNUSED(C), wmOperator *op) { // SpaceConsole *sc = CTX_wm_space_console(C); SetConsoleCursor *scu = op->customdata; #if 0 if (txt_has_sel(text)) { buffer = txt_sel_to_buf(text); WM_clipboard_text_set(buffer, 1); MEM_freeN(buffer); } #endif MEM_freeN(scu); }
static int copy_python_command_button_exec(bContext *C, wmOperator *UNUSED(op)) { uiBut *but = UI_context_active_but_get(C); if (but && (but->optype != NULL)) { PointerRNA *opptr; char *str; opptr = UI_but_operator_ptr_get(but); /* allocated when needed, the button owns it */ str = WM_operator_pystring_ex(C, NULL, false, true, but->optype, opptr); WM_clipboard_text_set(str, 0); MEM_freeN(str); return OPERATOR_FINISHED; } return OPERATOR_CANCELLED; }
static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op)) { PointerRNA ptr; PropertyRNA *prop; char *path; int index; /* try to create driver using property retrieved from UI */ uiContextActiveProperty(C, &ptr, &prop, &index); if (ptr.id.data && ptr.data && prop) { path = RNA_path_from_ID_to_property(&ptr, prop); if (path) { WM_clipboard_text_set(path, false); MEM_freeN(path); return OPERATOR_FINISHED; } } return OPERATOR_CANCELLED; }
static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op)) { PointerRNA ptr; PropertyRNA *prop; char *path; int success= 0; int index; /* try to create driver using property retrieved from UI */ uiContextActiveProperty(C, &ptr, &prop, &index); if (ptr.id.data && ptr.data && prop) { path= RNA_path_from_ID_to_property(&ptr, prop); if (path) { WM_clipboard_text_set(path, FALSE); MEM_freeN(path); } } /* since we're just copying, we don't really need to do anything else...*/ return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED; }
static int copy_data_path_button_exec(bContext *C, wmOperator *op) { PointerRNA ptr; PropertyRNA *prop; char *path; int index; const bool full_path = RNA_boolean_get(op->ptr, "full_path"); /* try to create driver using property retrieved from UI */ UI_context_active_but_prop_get(C, &ptr, &prop, &index); if (ptr.id.data != NULL) { if (full_path) { if (prop) { path = RNA_path_full_property_py_ex(&ptr, prop, index, true); } else { path = RNA_path_full_struct_py(&ptr); } } else { path = RNA_path_from_ID_to_property(&ptr, prop); } if (path) { WM_clipboard_text_set(path, false); MEM_freeN(path); return OPERATOR_FINISHED; } } return OPERATOR_CANCELLED; }
static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) { bool do_draw = false; int exit_code = OPERATOR_RUNNING_MODAL; RulerInfo *ruler_info = op->customdata; ScrArea *sa = ruler_info->sa; ARegion *ar = ruler_info->ar; RegionView3D *rv3d = ar->regiondata; /* its possible to change spaces while running the operator [#34894] */ if (UNLIKELY(ar != CTX_wm_region(C))) { exit_code = OPERATOR_FINISHED; goto exit; } switch (event->type) { case LEFTMOUSE: if (event->val == KM_RELEASE) { if (ruler_info->state == RULER_STATE_DRAG) { /* rubber-band angle removal */ RulerItem *ruler_item = ruler_item_active_get(ruler_info); if (ruler_item && (ruler_item->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) { if (!BLI_rcti_isect_pt_v(&ar->winrct, &event->x)) { ruler_item->flag &= ~RULERITEM_USE_ANGLE; do_draw = true; } } if (ruler_info->snap_flag & RULER_SNAP_OK) { ruler_info->snap_flag &= ~RULER_SNAP_OK; do_draw = true; } ruler_info->state = RULER_STATE_NORMAL; } } else { if (ruler_info->state == RULER_STATE_NORMAL) { if (event->ctrl || /* weak - but user friendly */ BLI_listbase_is_empty(&ruler_info->items)) { View3D *v3d = CTX_wm_view3d(C); const bool use_depth = (v3d->drawtype >= OB_SOLID); /* Create new line */ RulerItem *ruler_item_prev = ruler_item_active_get(ruler_info); RulerItem *ruler_item; /* check if we want to drag an existing point or add a new one */ ruler_info->state = RULER_STATE_DRAG; ruler_item = ruler_item_add(ruler_info); ruler_item_active_set(ruler_info, ruler_item); if (use_depth) { /* snap the first point added, not essential but handy */ ruler_item->co_index = 0; view3d_ruler_item_mousemove(C, ruler_info, event->mval, false, true); copy_v3_v3(ruler_info->drag_start_co, ruler_item->co[ruler_item->co_index]); } else { /* initial depth either previous ruler, view offset */ if (ruler_item_prev) { copy_v3_v3(ruler_info->drag_start_co, ruler_item_prev->co[ruler_item_prev->co_index]); } else { negate_v3_v3(ruler_info->drag_start_co, rv3d->ofs); } copy_v3_v3(ruler_item->co[0], ruler_info->drag_start_co); view3d_ruler_item_project(ruler_info, ruler_item->co[0], event->mval); } copy_v3_v3(ruler_item->co[2], ruler_item->co[0]); ruler_item->co_index = 2; do_draw = true; } else { float mval_fl[2] = {UNPACK2(event->mval)}; RulerItem *ruler_item_pick; int co_index; /* select and drag */ if (view3d_ruler_pick(ruler_info, mval_fl, &ruler_item_pick, &co_index)) { if (co_index == -1) { if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) { /* Add Center Point */ ruler_item_active_set(ruler_info, ruler_item_pick); ruler_item_pick->flag |= RULERITEM_USE_ANGLE; ruler_item_pick->co_index = 1; ruler_info->state = RULER_STATE_DRAG; /* find the factor */ { float co_ss[2][2]; float fac; ED_view3d_project_float_global(ar, ruler_item_pick->co[0], co_ss[0], V3D_PROJ_TEST_NOP); ED_view3d_project_float_global(ar, ruler_item_pick->co[2], co_ss[1], V3D_PROJ_TEST_NOP); fac = line_point_factor_v2(mval_fl, co_ss[0], co_ss[1]); CLAMP(fac, 0.0f, 1.0f); interp_v3_v3v3(ruler_item_pick->co[1], ruler_item_pick->co[0], ruler_item_pick->co[2], fac); } /* update the new location */ view3d_ruler_item_mousemove(C, ruler_info, event->mval, event->shift != 0, event->ctrl != 0); do_draw = true; } } else { ruler_item_active_set(ruler_info, ruler_item_pick); ruler_item_pick->co_index = co_index; ruler_info->state = RULER_STATE_DRAG; /* store the initial depth */ copy_v3_v3(ruler_info->drag_start_co, ruler_item_pick->co[ruler_item_pick->co_index]); do_draw = true; } } else { exit_code = OPERATOR_PASS_THROUGH; } } } } break; case CKEY: { if (event->ctrl) { RulerItem *ruler_item = ruler_item_active_get(ruler_info); if (ruler_item) { const int prec = 8; char numstr[256]; Scene *scene = CTX_data_scene(C); UnitSettings *unit = &scene->unit; ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec); WM_clipboard_text_set((void *) numstr, false); } } break; } case RIGHTCTRLKEY: case LEFTCTRLKEY: { WM_event_add_mousemove(C); break; } case MOUSEMOVE: { if (ruler_info->state == RULER_STATE_DRAG) { if (view3d_ruler_item_mousemove(C, ruler_info, event->mval, event->shift != 0, event->ctrl != 0)) { do_draw = true; } } break; } case ESCKEY: { do_draw = true; exit_code = OPERATOR_CANCELLED; break; } case RETKEY: { view3d_ruler_to_gpencil(C, ruler_info); do_draw = true; exit_code = OPERATOR_FINISHED; break; } case DELKEY: { if (event->val == KM_PRESS) { if (ruler_info->state == RULER_STATE_NORMAL) { RulerItem *ruler_item = ruler_item_active_get(ruler_info); if (ruler_item) { RulerItem *ruler_item_other = ruler_item->prev ? ruler_item->prev : ruler_item->next; ruler_item_remove(ruler_info, ruler_item); ruler_item_active_set(ruler_info, ruler_item_other); do_draw = true; } } } break; } default: exit_code = OPERATOR_PASS_THROUGH; break; } if (do_draw) { view3d_ruler_header_update(sa); /* all 3d views draw rulers */ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); } exit: if (ELEM(exit_code, OPERATOR_FINISHED, OPERATOR_CANCELLED)) { WM_cursor_modal_restore(ruler_info->win); view3d_ruler_end(C, ruler_info); view3d_ruler_free(ruler_info); op->customdata = NULL; ED_area_headerprint(sa, NULL); } return exit_code; }
bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event) { const char *utf8_buf = NULL; char ascii[2] = {'\0', '\0'}; bool updated = false; short idx = n->idx, idx_max = n->idx_max; short dir = STRCUR_DIR_NEXT, mode = STRCUR_JUMP_NONE; int cur; double val; switch (event->type) { case EVT_MODAL_MAP: if (ELEM(event->val, NUM_MODAL_INCREMENT_UP, NUM_MODAL_INCREMENT_DOWN)) { n->val[idx] += (event->val == NUM_MODAL_INCREMENT_UP) ? n->val_inc[idx] : -n->val_inc[idx]; value_to_editstr(n, idx); n->val_flag[idx] |= NUM_EDITED; updated = true; } else { /* might be a char too... */ utf8_buf = event->utf8_buf; ascii[0] = event->ascii; } break; case BACKSPACEKEY: /* Part specific to backspace... */ if (!(n->val_flag[idx] & NUM_EDITED)) { copy_v3_v3(n->val, n->val_org); n->val_flag[0] &= ~NUM_EDITED; n->val_flag[1] &= ~NUM_EDITED; n->val_flag[2] &= ~NUM_EDITED; updated = true; break; } else if (event->shift || !n->str[0]) { n->val[idx] = n->val_org[idx]; n->val_flag[idx] &= ~NUM_EDITED; n->str[0] = '\0'; n->str_cur = 0; updated = true; break; } /* Else, common behavior with DELKEY, only difference is remove char(s) before/after the cursor. */ dir = STRCUR_DIR_PREV; /* fall-through */ case DELKEY: if ((n->val_flag[idx] & NUM_EDITED) && n->str[0]) { int t_cur = cur = n->str_cur; if (event->ctrl) { mode = STRCUR_JUMP_DELIM; } BLI_str_cursor_step_utf8(n->str, strlen(n->str), &t_cur, dir, mode, true); if (t_cur != cur) { if (t_cur < cur) { SWAP(int, t_cur, cur); n->str_cur = cur; } memmove(&n->str[cur], &n->str[t_cur], strlen(&n->str[t_cur]) + 1); /* +1 for trailing '\0'. */ updated = true; } } else { return false; } break; case LEFTARROWKEY: dir = STRCUR_DIR_PREV; /* fall-through */ case RIGHTARROWKEY: cur = n->str_cur; if (event->ctrl) { mode = STRCUR_JUMP_DELIM; } BLI_str_cursor_step_utf8(n->str, strlen(n->str), &cur, dir, mode, true); if (cur != n->str_cur) { n->str_cur = cur; return true; } return false; case HOMEKEY: if (n->str[0]) { n->str_cur = 0; return true; } return false; case ENDKEY: if (n->str[0]) { n->str_cur = strlen(n->str); return true; } return false; case TABKEY: n->val_org[idx] = n->val[idx]; n->val_flag[idx] &= ~(NUM_NEGATE | NUM_INVERSE); idx += event->ctrl ? -1 : 1; idx %= idx_max + 1; n->idx = idx; n->val[idx] = n->val_org[idx]; if (n->val_flag[idx] & NUM_EDITED) { value_to_editstr(n, idx); } else { n->str[0] = '\0'; n->str_cur = 0; } return true; case PADPERIOD: /* Force numdot, some OSs/countries generate a comma char in this case, sic... (T37992) */ ascii[0] = '.'; utf8_buf = ascii; break; case EQUALKEY: case PADASTERKEY: if (!(n->flag & NUM_EDIT_FULL)) { n->flag |= NUM_EDIT_FULL; n->val_flag[idx] |= NUM_EDITED; return true; } else if (event->ctrl) { n->flag &= ~NUM_EDIT_FULL; return true; } /* fall-through */ case PADMINUS: case MINUSKEY: if (event->ctrl || !(n->flag & NUM_EDIT_FULL)) { n->val_flag[idx] ^= NUM_NEGATE; updated = true; break; } /* fall-through */ case PADSLASHKEY: case SLASHKEY: if (event->ctrl || !(n->flag & NUM_EDIT_FULL)) { n->val_flag[idx] ^= NUM_INVERSE; updated = true; break; } /* fall-through */ case CKEY: if (event->ctrl) { /* Copy current str to the copypaste buffer. */ WM_clipboard_text_set(n->str, 0); updated = true; break; } /* fall-through */ case VKEY: if (event->ctrl) { /* extract the first line from the clipboard */ int pbuf_len; char *pbuf = WM_clipboard_text_get_firstline(false, &pbuf_len); if (pbuf) { bool success; success = editstr_insert_at_cursor(n, pbuf, pbuf_len); MEM_freeN(pbuf); if (!success) { return false; } n->val_flag[idx] |= NUM_EDITED; } updated = true; break; } /* fall-through */ default: utf8_buf = event->utf8_buf; ascii[0] = event->ascii; break; } if (utf8_buf && !utf8_buf[0] && ascii[0]) { /* Fallback to ascii. */ utf8_buf = ascii; } if (utf8_buf && utf8_buf[0]) { if (!(n->flag & NUM_EDIT_FULL)) { /* In simple edit mode, we only keep a few chars as valid! */ /* no need to decode unicode, ascii is first char only */ if (!editstr_is_simple_numinput(utf8_buf[0])) { return false; } } if (!editstr_insert_at_cursor(n, utf8_buf, BLI_str_utf8_size(utf8_buf))) { return false; } n->val_flag[idx] |= NUM_EDITED; } else if (!updated) { return false; } /* At this point, our value has changed, try to interpret it with python (if str is not empty!). */ if (n->str[0]) { #ifdef WITH_PYTHON char str_unit_convert[NUM_STR_REP_LEN * 6]; /* Should be more than enough! */ const char *default_unit = NULL; /* Make radian default unit when needed. */ if (n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) default_unit = "r"; BLI_strncpy(str_unit_convert, n->str, sizeof(str_unit_convert)); bUnit_ReplaceString(str_unit_convert, sizeof(str_unit_convert), default_unit, 1.0, n->unit_sys, n->unit_type[idx]); /* Note: with angles, we always get values as radians here... */ if (BPY_button_exec(C, str_unit_convert, &val, false) != -1) { n->val[idx] = (float)val; n->val_flag[idx] &= ~NUM_INVALID; } else { n->val_flag[idx] |= NUM_INVALID; } #else /* Very unlikely, but does not harm... */ n->val[idx] = (float)atof(n->str); #endif /* WITH_PYTHON */ if (n->val_flag[idx] & NUM_NEGATE) { n->val[idx] = -n->val[idx]; } if (n->val_flag[idx] & NUM_INVERSE) { n->val[idx] = 1.0f / n->val[idx]; } } /* REDRAW SINCE NUMBERS HAVE CHANGED */ return true; }
bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event) { const char *utf8_buf = NULL; char ascii[2] = {'\0', '\0'}; bool updated = false; short idx = n->idx, idx_max = n->idx_max; short dir = STRCUR_DIR_NEXT, mode = STRCUR_JUMP_NONE; int cur; switch (event->type) { case EVT_MODAL_MAP: if (ELEM(event->val, NUM_MODAL_INCREMENT_UP, NUM_MODAL_INCREMENT_DOWN)) { n->val[idx] += (event->val == NUM_MODAL_INCREMENT_UP) ? n->val_inc[idx] : -n->val_inc[idx]; value_to_editstr(n, idx); n->val_flag[idx] |= NUM_EDITED; updated = true; } else { /* might be a char too... */ utf8_buf = event->utf8_buf; ascii[0] = event->ascii; } break; case BACKSPACEKEY: /* Part specific to backspace... */ if (!(n->val_flag[idx] & NUM_EDITED)) { copy_v3_v3(n->val, n->val_org); n->val_flag[0] &= ~NUM_EDITED; n->val_flag[1] &= ~NUM_EDITED; n->val_flag[2] &= ~NUM_EDITED; n->flag |= NUM_FAKE_EDITED; updated = true; break; } else if (event->shift || !n->str[0]) { n->val[idx] = n->val_org[idx]; n->val_flag[idx] &= ~NUM_EDITED; n->str[0] = '\0'; n->str_cur = 0; updated = true; break; } /* Else, common behavior with DELKEY, only difference is remove char(s) before/after the cursor. */ dir = STRCUR_DIR_PREV; ATTR_FALLTHROUGH; case DELKEY: if ((n->val_flag[idx] & NUM_EDITED) && n->str[0]) { int t_cur = cur = n->str_cur; if (event->ctrl) { mode = STRCUR_JUMP_DELIM; } BLI_str_cursor_step_utf8(n->str, strlen(n->str), &t_cur, dir, mode, true); if (t_cur != cur) { if (t_cur < cur) { SWAP(int, t_cur, cur); n->str_cur = cur; } memmove(&n->str[cur], &n->str[t_cur], strlen(&n->str[t_cur]) + 1); /* +1 for trailing '\0'. */ updated = true; } if (!n->str[0]) { n->val[idx] = n->val_org[idx]; } } else { return false; } break; case LEFTARROWKEY: dir = STRCUR_DIR_PREV; ATTR_FALLTHROUGH; case RIGHTARROWKEY: cur = n->str_cur; if (event->ctrl) { mode = STRCUR_JUMP_DELIM; } BLI_str_cursor_step_utf8(n->str, strlen(n->str), &cur, dir, mode, true); if (cur != n->str_cur) { n->str_cur = cur; return true; } return false; case HOMEKEY: if (n->str[0]) { n->str_cur = 0; return true; } return false; case ENDKEY: if (n->str[0]) { n->str_cur = strlen(n->str); return true; } return false; case TABKEY: n->val_flag[idx] &= ~(NUM_NEGATE | NUM_INVERSE); idx = (idx + idx_max + (event->ctrl ? 0 : 2)) % (idx_max + 1); n->idx = idx; if (n->val_flag[idx] & NUM_EDITED) { value_to_editstr(n, idx); } else { n->str[0] = '\0'; n->str_cur = 0; } return true; case PADPERIOD: case PERIODKEY: /* Force numdot, some OSs/countries generate a comma char in this case, sic... (T37992) */ ascii[0] = '.'; utf8_buf = ascii; break; #if 0 /* Those keys are not directly accessible in all layouts, preventing to generate matching events. * So we use a hack (ascii value) instead, see below. */ case EQUALKEY: case PADASTERKEY: if (!(n->flag & NUM_EDIT_FULL)) { n->flag |= NUM_EDIT_FULL; n->val_flag[idx] |= NUM_EDITED; return true; } else if (event->ctrl) { n->flag &= ~NUM_EDIT_FULL; return true; } break; #endif case PADMINUS: case MINUSKEY: if (event->ctrl || !(n->flag & NUM_EDIT_FULL)) { n->val_flag[idx] ^= NUM_NEGATE; updated = true; } break; case PADSLASHKEY: case SLASHKEY: if (event->ctrl || !(n->flag & NUM_EDIT_FULL)) { n->val_flag[idx] ^= NUM_INVERSE; updated = true; } break; case CKEY: if (event->ctrl) { /* Copy current str to the copypaste buffer. */ WM_clipboard_text_set(n->str, 0); updated = true; } break; case VKEY: if (event->ctrl) { /* extract the first line from the clipboard */ int pbuf_len; char *pbuf = WM_clipboard_text_get_firstline(false, &pbuf_len); if (pbuf) { const bool success = editstr_insert_at_cursor(n, pbuf, pbuf_len); MEM_freeN(pbuf); if (!success) { return false; } n->val_flag[idx] |= NUM_EDITED; } updated = true; } break; default: break; } if (!updated && !utf8_buf && (event->utf8_buf[0] || event->ascii)) { utf8_buf = event->utf8_buf; ascii[0] = event->ascii; } /* XXX Hack around keyboards without direct access to '=' nor '*'... */ if (ELEM(ascii[0], '=', '*')) { if (!(n->flag & NUM_EDIT_FULL)) { n->flag |= NUM_EDIT_FULL; n->val_flag[idx] |= NUM_EDITED; return true; } else if (event->ctrl) { n->flag &= ~NUM_EDIT_FULL; return true; } } /* Up to this point, if we have a ctrl modifier, skip. * This allows to still access most of modals' shortcuts even in numinput mode. */ if (!updated && event->ctrl) { return false; } if ((!utf8_buf || !utf8_buf[0]) && ascii[0]) { /* Fallback to ascii. */ utf8_buf = ascii; } if (utf8_buf && utf8_buf[0]) { if (!(n->flag & NUM_EDIT_FULL)) { /* In simple edit mode, we only keep a few chars as valid! */ /* no need to decode unicode, ascii is first char only */ if (!editstr_is_simple_numinput(utf8_buf[0])) { return false; } } if (!editstr_insert_at_cursor(n, utf8_buf, BLI_str_utf8_size(utf8_buf))) { return false; } n->val_flag[idx] |= NUM_EDITED; } else if (!updated) { return false; } /* At this point, our value has changed, try to interpret it with python (if str is not empty!). */ if (n->str[0]) { const float val_prev = n->val[idx]; #ifdef WITH_PYTHON Scene *sce = CTX_data_scene(C); double val; char str_unit_convert[NUM_STR_REP_LEN * 6]; /* Should be more than enough! */ const char *default_unit = NULL; /* Use scale_length if needed! */ const float fac = (float)BKE_scene_unit_scale(&sce->unit, n->unit_type[idx], 1.0); /* Make radian default unit when needed. */ if (n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) default_unit = "r"; BLI_strncpy(str_unit_convert, n->str, sizeof(str_unit_convert)); bUnit_ReplaceString(str_unit_convert, sizeof(str_unit_convert), default_unit, fac, n->unit_sys, n->unit_type[idx]); /* Note: with angles, we always get values as radians here... */ if (BPY_execute_string_as_number(C, str_unit_convert, false, &val)) { n->val[idx] = (float)val; n->val_flag[idx] &= ~NUM_INVALID; } else { n->val_flag[idx] |= NUM_INVALID; } #else /* Very unlikely, but does not harm... */ n->val[idx] = (float)atof(n->str); (void)C; #endif /* WITH_PYTHON */ if (n->val_flag[idx] & NUM_NEGATE) { n->val[idx] = -n->val[idx]; } if (n->val_flag[idx] & NUM_INVERSE) { n->val[idx] = 1.0f / n->val[idx]; } if (UNLIKELY(!isfinite(n->val[idx]))) { n->val[idx] = val_prev; n->val_flag[idx] |= NUM_INVALID; } } /* REDRAW SINCE NUMBERS HAVE CHANGED */ return true; }