Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/object/object_modes.c
| Show All 24 Lines | |||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_scene_types.h" | #include "DNA_scene_types.h" | ||||
| #include "DNA_workspace_types.h" | #include "DNA_workspace_types.h" | ||||
| #include "BLI_kdopbvh.h" | #include "BLI_kdopbvh.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLT_translation.h" | |||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_gpencil_modifier.h" | #include "BKE_gpencil_modifier.h" | ||||
| #include "BKE_layer.h" | #include "BKE_layer.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_modifier.h" | #include "BKE_modifier.h" | ||||
| #include "BKE_object.h" | #include "BKE_object.h" | ||||
| #include "BKE_paint.h" | #include "BKE_paint.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "BKE_scene.h" | #include "BKE_scene.h" | ||||
| #include "BKE_screen.h" | |||||
| #include "WM_api.h" | #include "WM_api.h" | ||||
| #include "WM_types.h" | #include "WM_types.h" | ||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "RNA_define.h" | |||||
| #include "DEG_depsgraph.h" | #include "DEG_depsgraph.h" | ||||
| #include "DEG_depsgraph_query.h" | #include "DEG_depsgraph_query.h" | ||||
| #include "ED_armature.h" | #include "ED_armature.h" | ||||
| #include "ED_gpencil.h" | #include "ED_gpencil.h" | ||||
| #include "ED_screen.h" | #include "ED_screen.h" | ||||
| #include "ED_transform_snap_object_context.h" | #include "ED_transform_snap_object_context.h" | ||||
| ▲ Show 20 Lines • Show All 340 Lines • ▼ Show 20 Lines | |||||
| bool ED_object_mode_generic_has_data(struct Depsgraph *depsgraph, struct Object *ob) | bool ED_object_mode_generic_has_data(struct Depsgraph *depsgraph, struct Object *ob) | ||||
| { | { | ||||
| return ed_object_mode_generic_exit_ex(NULL, depsgraph, NULL, ob, true); | return ed_object_mode_generic_exit_ex(NULL, depsgraph, NULL, ob, true); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Switch Object | /** \name Transfer Mode | ||||
| * | * | ||||
| * Enters the same mode of the current active object in another object, | * Enters the same mode of the current active object in another object, | ||||
| * leaving the mode of the current object. | * leaving the mode of the current object. | ||||
| * \{ */ | * \{ */ | ||||
| static bool object_switch_object_poll(bContext *C) | static bool object_transfer_mode_poll(bContext *C) | ||||
| { | { | ||||
| if (!U.experimental.use_switch_object_operator) { | |||||
| return false; | |||||
| } | |||||
| if (!CTX_wm_region_view3d(C)) { | if (!CTX_wm_region_view3d(C)) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| const Object *ob = CTX_data_active_object(C); | const Object *ob = CTX_data_active_object(C); | ||||
| return ob && (ob->mode & (OB_MODE_EDIT | OB_MODE_SCULPT)); | return ob && (ob->mode & (OB_MODE_SCULPT)); | ||||
| } | } | ||||
| static int object_switch_object_invoke(bContext *C, wmOperator *op, const wmEvent *event) | /* Update the viewport rotation origin to the mouse cursor. */ | ||||
| static void object_transfer_mode_reposition_view_pivot(bContext *C, const int mval[2]) | |||||
| { | { | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| Scene *scene = CTX_data_scene(C); | Scene *scene = CTX_data_scene(C); | ||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | |||||
| Base *base_dst = ED_view3d_give_base_under_cursor(C, event->mval); | float global_loc[3]; | ||||
| if (!ED_view3d_autodist_simple(region, mval, global_loc, 0, NULL)) { | |||||
| return; | |||||
| } | |||||
| UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; | |||||
| copy_v3_v3(ups->average_stroke_accum, global_loc); | |||||
| ups->average_stroke_counter = 1; | |||||
| ups->last_stroke_valid = true; | |||||
| } | |||||
| static bool object_transfer_mode_to_base(bContext *C, wmOperator *op, Base *base_dst) | |||||
| { | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | |||||
| if (base_dst == NULL) { | if (base_dst == NULL) { | ||||
| return OPERATOR_CANCELLED; | return false; | ||||
| } | } | ||||
| Object *ob_dst = base_dst->object; | Object *ob_dst = base_dst->object; | ||||
| Object *ob_src = CTX_data_active_object(C); | Object *ob_src = CTX_data_active_object(C); | ||||
| if (ob_dst == ob_src) { | if (ob_dst == ob_src) { | ||||
| return OPERATOR_CANCELLED; | return false; | ||||
| } | } | ||||
| const eObjectMode last_mode = (eObjectMode)ob_src->mode; | const eObjectMode last_mode = (eObjectMode)ob_src->mode; | ||||
| if (!ED_object_mode_compat_test(ob_dst, last_mode)) { | if (!ED_object_mode_compat_test(ob_dst, last_mode)) { | ||||
| return OPERATOR_CANCELLED; | return false; | ||||
| } | } | ||||
| int retval = OPERATOR_CANCELLED; | bool mode_transfered = false; | ||||
| ED_undo_group_begin(C); | ED_undo_group_begin(C); | ||||
| if (ED_object_mode_set_ex(C, OB_MODE_OBJECT, true, op->reports)) { | if (ED_object_mode_set_ex(C, OB_MODE_OBJECT, true, op->reports)) { | ||||
| Object *ob_dst_orig = DEG_get_original_object(ob_dst); | Object *ob_dst_orig = DEG_get_original_object(ob_dst); | ||||
| Base *base = BKE_view_layer_base_find(view_layer, ob_dst_orig); | Base *base = BKE_view_layer_base_find(view_layer, ob_dst_orig); | ||||
| BKE_view_layer_base_deselect_all(view_layer); | BKE_view_layer_base_deselect_all(view_layer); | ||||
| BKE_view_layer_base_select_and_set_active(view_layer, base); | BKE_view_layer_base_select_and_set_active(view_layer, base); | ||||
| DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); | DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); | ||||
| ED_undo_push(C, "Change Active"); | ED_undo_push(C, "Change Active"); | ||||
| ob_dst_orig = DEG_get_original_object(ob_dst); | ob_dst_orig = DEG_get_original_object(ob_dst); | ||||
| ED_object_mode_set_ex(C, last_mode, true, op->reports); | ED_object_mode_set_ex(C, last_mode, true, op->reports); | ||||
| /* Update the viewport rotation origin to the mouse cursor. */ | |||||
| if (last_mode & OB_MODE_ALL_PAINT) { | |||||
| float global_loc[3]; | |||||
| if (ED_view3d_autodist_simple(region, event->mval, global_loc, 0, NULL)) { | |||||
| UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; | |||||
| copy_v3_v3(ups->average_stroke_accum, global_loc); | |||||
| ups->average_stroke_counter = 1; | |||||
| ups->last_stroke_valid = true; | |||||
| } | |||||
| } | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); | WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); | ||||
| WM_toolsystem_update_from_context_view3d(C); | WM_toolsystem_update_from_context_view3d(C); | ||||
| retval = OPERATOR_FINISHED; | mode_transfered = true; | ||||
| } | } | ||||
| ED_undo_group_end(C); | ED_undo_group_end(C); | ||||
| return mode_transfered; | |||||
| } | |||||
| static int object_transfer_mode_modal(bContext *C, wmOperator *op, const wmEvent *event) | |||||
| { | |||||
| switch (event->type) { | |||||
| case LEFTMOUSE: | |||||
| if (event->val == KM_PRESS) { | |||||
| WM_cursor_modal_restore(CTX_wm_window(C)); | |||||
| ED_workspace_status_text(C, NULL); | |||||
| /* This ensures that the click was done in an viewport region. */ | |||||
| bScreen *screen = CTX_wm_screen(C); | |||||
| ARegion *region = BKE_screen_find_main_region_at_xy( | |||||
| screen, SPACE_VIEW3D, event->x, event->y); | |||||
| if (!region) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| const int mval[2] = {event->x - region->winrct.xmin, event->y - region->winrct.ymin}; | |||||
| Base *base_dst = ED_view3d_give_base_under_cursor(C, mval); | |||||
| const bool mode_transfered = object_transfer_mode_to_base(C, op, base_dst); | |||||
| if (!mode_transfered) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| break; | |||||
| case RIGHTMOUSE: { | |||||
| WM_cursor_modal_restore(CTX_wm_window(C)); | |||||
| ED_workspace_status_text(C, NULL); | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| } | |||||
| return OPERATOR_RUNNING_MODAL; | |||||
| } | |||||
| return retval; | static int object_transfer_mode_invoke(bContext *C, wmOperator *op, const wmEvent *event) | ||||
| { | |||||
| const bool use_eyedropper = RNA_boolean_get(op->ptr, "use_eyedropper"); | |||||
| if (use_eyedropper) { | |||||
| ED_workspace_status_text(C, TIP_("Click in the viewport to select an object")); | |||||
| WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EYEDROPPER); | |||||
| WM_event_add_modal_handler(C, op); | |||||
| return OPERATOR_RUNNING_MODAL; | |||||
| } | } | ||||
| void OBJECT_OT_switch_object(wmOperatorType *ot) | Object *ob_src = CTX_data_active_object(C); | ||||
| const eObjectMode src_mode = (eObjectMode)ob_src->mode; | |||||
| Base *base_dst = ED_view3d_give_base_under_cursor(C, event->mval); | |||||
| const bool mode_transfered = object_transfer_mode_to_base(C, op, base_dst); | |||||
| if (!mode_transfered) { | |||||
| return OPERATOR_CANCELLED; | |||||
| } | |||||
| if (src_mode & OB_MODE_ALL_PAINT) { | |||||
| object_transfer_mode_reposition_view_pivot(C, event->mval); | |||||
| } | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void OBJECT_OT_transfer_mode(wmOperatorType *ot) | |||||
| { | { | ||||
| /* identifiers */ | /* identifiers */ | ||||
| ot->name = "Switch Object"; | ot->name = "Transfer Mode"; | ||||
| ot->idname = "OBJECT_OT_switch_object"; | ot->idname = "OBJECT_OT_transfer_mode"; | ||||
| ot->description = | ot->description = | ||||
| "Switches the active object and assigns the same mode to a new one under the mouse cursor, " | "Switches the active object and assigns the same mode to a new one under the mouse cursor, " | ||||
| "leaving the active mode in the current one"; | "leaving the active mode in the current one"; | ||||
| /* api callbacks */ | /* api callbacks */ | ||||
| ot->invoke = object_switch_object_invoke; | ot->invoke = object_transfer_mode_invoke; | ||||
| ot->poll = object_switch_object_poll; | ot->modal = object_transfer_mode_modal; | ||||
| ot->poll = object_transfer_mode_poll; | |||||
| /* Undo push is handled by the operator. */ | /* Undo push is handled by the operator. */ | ||||
| ot->flag = OPTYPE_REGISTER; | ot->flag = OPTYPE_REGISTER; | ||||
| RNA_def_boolean(ot->srna, | |||||
| "use_eyedropper", | |||||
| false, | |||||
| "Use Eyedropper", | |||||
| "Pick the object to switch to using an eyedropper"); | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||