Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/object/object_edit.c
| Show First 20 Lines • Show All 178 Lines • ▼ Show 20 Lines | if (obedit->type == OB_MESH) { | ||||
| EDBM_mesh_load(obedit); | EDBM_mesh_load(obedit); | ||||
| if (freedata) { | if (freedata) { | ||||
| EDBM_mesh_free(me->edit_btmesh); | EDBM_mesh_free(me->edit_btmesh); | ||||
| MEM_freeN(me->edit_btmesh); | MEM_freeN(me->edit_btmesh); | ||||
| me->edit_btmesh = NULL; | me->edit_btmesh = NULL; | ||||
| } | } | ||||
| /* XXX not sure what to do with this? */ | |||||
| if (obedit->restore_mode & OB_MODE_WEIGHT_PAINT) { | if (obedit->restore_mode & OB_MODE_WEIGHT_PAINT) { | ||||
| ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e'); | ED_mesh_mirror_spatial_table(NULL, NULL, NULL, NULL, 'e'); | ||||
| ED_mesh_mirror_topo_table(NULL, NULL, 'e'); | ED_mesh_mirror_topo_table(NULL, NULL, 'e'); | ||||
| } | } | ||||
| } | } | ||||
| else if (obedit->type == OB_ARMATURE) { | else if (obedit->type == OB_ARMATURE) { | ||||
| ED_armature_from_edit(obedit->data); | ED_armature_from_edit(obedit->data); | ||||
| if (freedata) | if (freedata) | ||||
| ▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | void ED_object_editmode_exit(bContext *C, int flag) | ||||
| const bool freedata = (flag & EM_FREEDATA) != 0; | const bool freedata = (flag & EM_FREEDATA) != 0; | ||||
| if (flag & EM_WAITCURSOR) waitcursor(1); | if (flag & EM_WAITCURSOR) waitcursor(1); | ||||
| if (ED_object_editmode_load_ex(CTX_data_main(C), obedit, freedata) == false) { | if (ED_object_editmode_load_ex(CTX_data_main(C), obedit, freedata) == false) { | ||||
| /* in rare cases (background mode) its possible active object | /* in rare cases (background mode) its possible active object | ||||
| * is flagged for editmode, without 'obedit' being set [#35489] */ | * is flagged for editmode, without 'obedit' being set [#35489] */ | ||||
| if (UNLIKELY(view_layer->basact && (view_layer->basact->object->mode & OB_MODE_EDIT))) { | if (UNLIKELY(view_layer->basact && (view_layer->basact->object->mode & OB_MODE_EDIT))) { | ||||
| view_layer->basact->object->mode &= ~OB_MODE_EDIT; | BKE_workspace_object_mode_ensure_updated( | ||||
| CTX_wm_workspace(C), view_layer->basact->object, | |||||
| OB_MODE_OBJECT, true); | |||||
| } | } | ||||
| if (flag & EM_WAITCURSOR) waitcursor(0); | if (flag & EM_WAITCURSOR) waitcursor(0); | ||||
| return; | return; | ||||
| } | } | ||||
| /* freedata only 0 now on file saves and render */ | /* freedata only 0 now on file saves and render */ | ||||
| if (freedata) { | if (freedata) { | ||||
| ListBase pidlist; | ListBase pidlist; | ||||
| Show All 15 Lines | if (freedata) { | ||||
| /* also flush ob recalc, doesn't take much overhead, but used for particles */ | /* also flush ob recalc, doesn't take much overhead, but used for particles */ | ||||
| DEG_id_tag_update(&obedit->id, OB_RECALC_OB | OB_RECALC_DATA); | DEG_id_tag_update(&obedit->id, OB_RECALC_OB | OB_RECALC_DATA); | ||||
| if (flag & EM_DO_UNDO) | if (flag & EM_DO_UNDO) | ||||
| ED_undo_push(C, "Editmode"); | ED_undo_push(C, "Editmode"); | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene); | WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene); | ||||
| obedit->mode &= ~OB_MODE_EDIT; | BKE_workspace_object_mode_for_object_set(CTX_wm_workspace(C), scene, obedit, obedit->mode & ~OB_MODE_EDIT); | ||||
| } | } | ||||
| if (flag & EM_WAITCURSOR) waitcursor(0); | if (flag & EM_WAITCURSOR) waitcursor(0); | ||||
| /* This way we ensure scene's obedit is copied into all CoW scenes. */ | /* This way we ensure scene's obedit is copied into all CoW scenes. */ | ||||
| DEG_id_tag_update(&scene->id, 0); | DEG_id_tag_update(&scene->id, 0); | ||||
| } | } | ||||
| void ED_object_editmode_enter(bContext *C, int flag) | void ED_object_editmode_enter(bContext *C, int flag) | ||||
| { | { | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | ViewLayer *view_layer = CTX_data_view_layer(C); | ||||
| WorkSpace *workspace = CTX_wm_workspace(C); | |||||
| Object *ob; | Object *ob; | ||||
| bool ok = false; | bool ok = false; | ||||
| if (ID_IS_LINKED(scene)) return; | if (ID_IS_LINKED(scene)) return; | ||||
| if ((flag & EM_IGNORE_LAYER) == 0) { | if ((flag & EM_IGNORE_LAYER) == 0) { | ||||
| ob = CTX_data_active_object(C); /* active layer checked here for view3d */ | ob = CTX_data_active_object(C); /* active layer checked here for view3d */ | ||||
| Show All 11 Lines | void ED_object_editmode_enter(bContext *C, int flag) | ||||
| if (BKE_object_obdata_is_libdata(ob)) { | if (BKE_object_obdata_is_libdata(ob)) { | ||||
| error_libdata(); | error_libdata(); | ||||
| return; | return; | ||||
| } | } | ||||
| if (flag & EM_WAITCURSOR) waitcursor(1); | if (flag & EM_WAITCURSOR) waitcursor(1); | ||||
| ob->restore_mode = ob->mode; | BKE_workspace_object_mode_for_object_set(workspace, scene, ob, OB_MODE_EDIT); | ||||
| /* note, when switching scenes the object can have editmode data but | |||||
| * not be scene->obedit: bug 22954, this avoids calling self eternally */ | |||||
| if ((ob->restore_mode & OB_MODE_EDIT) == 0) | |||||
| ED_object_toggle_modes(C, ob->mode); | |||||
| ob->mode = OB_MODE_EDIT; | |||||
| if (ob->type == OB_MESH) { | if (ob->type == OB_MESH) { | ||||
| BMEditMesh *em; | BMEditMesh *em; | ||||
| ok = 1; | ok = 1; | ||||
| scene->obedit = ob; /* context sees this */ | scene->obedit = ob; /* context sees this */ | ||||
| const bool use_key_index = mesh_needs_keyindex(ob->data); | const bool use_key_index = mesh_needs_keyindex(ob->data); | ||||
| ▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | void ED_object_editmode_enter(bContext *C, int flag) | ||||
| if (ok) { | if (ok) { | ||||
| DEG_id_tag_update(&ob->id, OB_RECALC_DATA); | DEG_id_tag_update(&ob->id, OB_RECALC_DATA); | ||||
| /* This way we ensure scene's obedit is copied into all CoW scenes. */ | /* This way we ensure scene's obedit is copied into all CoW scenes. */ | ||||
| DEG_id_tag_update(&scene->id, 0); | DEG_id_tag_update(&scene->id, 0); | ||||
| } | } | ||||
| else { | else { | ||||
| scene->obedit = NULL; /* XXX for context */ | scene->obedit = NULL; /* XXX for context */ | ||||
| ob->mode &= ~OB_MODE_EDIT; | BKE_workspace_object_mode_for_object_set(workspace, scene, ob, ob->mode & ~OB_MODE_EDIT); | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene); | WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene); | ||||
| } | } | ||||
| if (flag & EM_DO_UNDO) ED_undo_push(C, "Enter Editmode"); | if (flag & EM_DO_UNDO) ED_undo_push(C, "Enter Editmode"); | ||||
| if (flag & EM_WAITCURSOR) waitcursor(0); | if (flag & EM_WAITCURSOR) waitcursor(0); | ||||
| } | } | ||||
| static int editmode_toggle_exec(bContext *C, wmOperator *op) | static int editmode_toggle_exec(bContext *C, wmOperator *op) | ||||
| ▲ Show 20 Lines • Show All 1,098 Lines • ▼ Show 20 Lines | |||||
| */ | */ | ||||
| bool ED_object_mode_compat_set(bContext *C, Object *ob, int mode, ReportList *reports) | bool ED_object_mode_compat_set(bContext *C, Object *ob, int mode, ReportList *reports) | ||||
| { | { | ||||
| bool ok; | bool ok; | ||||
| if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) { | if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) { | ||||
| const char *opstring = object_mode_op_string(ob->mode); | const char *opstring = object_mode_op_string(ob->mode); | ||||
| WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); | WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); | ||||
| #ifdef USE_WORKSPACE_MODE | |||||
| BKE_workspace_object_mode_set(CTX_wm_workspace(C), CTX_data_scene(C), ob->mode); | |||||
| #endif | |||||
| ok = ELEM(ob->mode, mode, OB_MODE_OBJECT); | ok = ELEM(ob->mode, mode, OB_MODE_OBJECT); | ||||
| if (!ok) { | if (!ok) { | ||||
| wmOperatorType *ot = WM_operatortype_find(opstring, false); | wmOperatorType *ot = WM_operatortype_find(opstring, false); | ||||
| BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name); | BKE_reportf(reports, RPT_ERROR, "Unable to execute '%s', error changing modes", ot->name); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| Show All 11 Lines | static int object_mode_set_poll(bContext *C) | ||||
| * so that users can exit editmode this way as per normal. | * so that users can exit editmode this way as per normal. | ||||
| */ | */ | ||||
| if (ED_operator_object_active_editable(C)) | if (ED_operator_object_active_editable(C)) | ||||
| return true; | return true; | ||||
| else | else | ||||
| return (CTX_data_gpencil_data(C) != NULL); | return (CTX_data_gpencil_data(C) != NULL); | ||||
| } | } | ||||
| static bool object_mode_set_force( | |||||
| bContext *C, Object *active_object, eObjectMode mode_to_enforce, | |||||
| ReportList *reports) | |||||
| { | |||||
| if (!object_mode_compat_test(active_object, mode_to_enforce)) { | |||||
| return false; | |||||
| } | |||||
| ED_object_mode_compat_set(C, active_object, mode_to_enforce, reports); | |||||
| ED_object_toggle_modes(C, mode_to_enforce); | |||||
| return true; | |||||
| } | |||||
| /** | |||||
| * Toggle between OB_MODE_OBJECT and \a mode_to_toggle. Fails if | |||||
| * \a mode_to_toggle is OB_MODE_OBJECT too. | |||||
| * | |||||
| * \return false on error. | |||||
| */ | |||||
| static bool object_mode_toggle( | |||||
| bContext *C, Object *active_object, eObjectMode mode_to_toggle, | |||||
| ReportList *reports) | |||||
| { | |||||
| if (mode_to_toggle == OB_MODE_OBJECT || !object_mode_compat_test(active_object, mode_to_toggle)) { | |||||
| return false; | |||||
| } | |||||
| if (active_object->mode == mode_to_toggle) { | |||||
| /* Change to OB_MODE_OBJECT */ | |||||
| ED_object_mode_compat_set(C, active_object, OB_MODE_OBJECT, reports); | |||||
| } | |||||
| else { | |||||
| /* Change to mode_to_toggle */ | |||||
| ED_object_toggle_modes(C, mode_to_toggle); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| static int object_mode_set_exec(bContext *C, wmOperator *op) | static int object_mode_set_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| Object *ob = CTX_data_active_object(C); | Object *ob = CTX_data_active_object(C); | ||||
| bGPdata *gpd = CTX_data_gpencil_data(C); | bGPdata *gpd = CTX_data_gpencil_data(C); | ||||
| eObjectMode mode = RNA_enum_get(op->ptr, "mode"); | |||||
| eObjectMode restore_mode = (ob) ? ob->mode : OB_MODE_OBJECT; | |||||
| const bool toggle = RNA_boolean_get(op->ptr, "toggle"); | const bool toggle = RNA_boolean_get(op->ptr, "toggle"); | ||||
| eObjectMode mode; | |||||
| bool error; | |||||
| if (gpd) { | if (gpd) { | ||||
| /* GP Mode is not bound to a specific object. Therefore, | /* GP Mode is not bound to a specific object. Therefore, | ||||
| * we don't want it to be actually saved on any objects, | * we don't want it to be actually saved on any objects, | ||||
| * as weirdness can happen if you select other objects, | * as weirdness can happen if you select other objects, | ||||
| * or load old files. | * or load old files. | ||||
| * | * | ||||
| * Instead, we use the following 2 rules to ensure that | * Instead, we use the following 2 rules to ensure that | ||||
| * the mode selector works as expected: | * the mode selector works as expected: | ||||
| * 1) If there's no object, we want to enter editmode. | * 1) If there's no object, we want to enter editmode. | ||||
| * (i.e. with no object, we're in object mode) | * (i.e. with no object, we're in object mode) | ||||
| * 2) Otherwise, exit stroke editmode, so that we can | * 2) Otherwise, exit stroke editmode, so that we can | ||||
| * enter another mode... | * enter another mode... | ||||
| */ | */ | ||||
| if (!ob || (gpd->flag & GP_DATA_STROKE_EDITMODE)) { | if (!ob || (gpd->flag & GP_DATA_STROKE_EDITMODE)) { | ||||
| WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_EXEC_REGION_WIN, NULL); | WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_EXEC_REGION_WIN, NULL); | ||||
| } | } | ||||
| } | } | ||||
| if (!ob || !object_mode_compat_test(ob, mode)) | if (!ob) { | ||||
| return OPERATOR_PASS_THROUGH; | return OPERATOR_PASS_THROUGH; | ||||
| if (ob->mode != mode) { | |||||
| /* we should be able to remove this call, each operator calls */ | |||||
| ED_object_mode_compat_set(C, ob, mode, op->reports); | |||||
| } | } | ||||
| /* Exit current mode if it's not the mode we're setting */ | /* RNA "mode" property has priority. If it's set, use it. */ | ||||
| if (mode != OB_MODE_OBJECT && (ob->mode != mode || toggle)) { | if (RNA_struct_property_is_set(op->ptr, "mode")) { | ||||
| /* Enter new mode */ | mode = RNA_enum_get(op->ptr, "mode"); | ||||
| ED_object_toggle_modes(C, mode); | |||||
| } | |||||
| if (toggle) { | if (toggle) { | ||||
| /* Special case for Object mode! */ | error = (object_mode_toggle(C, ob, mode, op->reports) == false); | ||||
| if (mode == OB_MODE_OBJECT && restore_mode == OB_MODE_OBJECT && ob->restore_mode != OB_MODE_OBJECT) { | |||||
| ED_object_toggle_modes(C, ob->restore_mode); | |||||
| } | |||||
| else if (ob->mode == mode) { | |||||
| /* For toggling, store old mode so we know what to go back to */ | |||||
| ob->restore_mode = restore_mode; | |||||
| } | } | ||||
| else if (ob->restore_mode != OB_MODE_OBJECT && ob->restore_mode != mode) { | else { | ||||
| ED_object_toggle_modes(C, ob->restore_mode); | error = (object_mode_set_force(C, ob, mode, op->reports) == false); | ||||
| } | } | ||||
| } | } | ||||
| /* RNA "mode" property is not set, so use workspace mode. */ | |||||
| else { | |||||
| WorkSpace *workspace = CTX_wm_workspace(C); | |||||
| return OPERATOR_FINISHED; | mode = toggle ? BKE_workspace_object_mode_for_toggle_get(workspace, ob) : workspace->preferred_mode; | ||||
| error = object_mode_set_force(C, ob, mode, op->reports); | |||||
| } | |||||
| return error ? OPERATOR_PASS_THROUGH : OPERATOR_FINISHED; | |||||
| } | } | ||||
| void OBJECT_OT_mode_set(wmOperatorType *ot) | void OBJECT_OT_mode_set(wmOperatorType *ot) | ||||
| { | { | ||||
| PropertyRNA *prop; | PropertyRNA *prop; | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Set Object Mode"; | ot->name = "Set Object Mode"; | ||||
| Show All 18 Lines | |||||
| void ED_object_toggle_modes(bContext *C, int mode) | void ED_object_toggle_modes(bContext *C, int mode) | ||||
| { | { | ||||
| if (mode != OB_MODE_OBJECT) { | if (mode != OB_MODE_OBJECT) { | ||||
| const char *opstring = object_mode_op_string(mode); | const char *opstring = object_mode_op_string(mode); | ||||
| if (opstring) { | if (opstring) { | ||||
| #ifdef USE_WORKSPACE_MODE | |||||
| WorkSpace *workspace = CTX_wm_workspace(C); | |||||
| #endif | |||||
| WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); | WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); | ||||
| #ifdef USE_WORKSPACE_MODE | |||||
| Object *ob = CTX_data_active_object(C); | |||||
| if (ob) { | |||||
| BKE_workspace_object_mode_set(workspace, CTX_data_scene(C), ob->mode); | |||||
| } | |||||
| #endif | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /************************ Game Properties ***********************/ | /************************ Game Properties ***********************/ | ||||
| static int game_property_new_exec(bContext *C, wmOperator *op) | static int game_property_new_exec(bContext *C, wmOperator *op) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 446 Lines • Show Last 20 Lines | |||||