diff options
Diffstat (limited to 'source/blender/editors/interface/eyedroppers/eyedropper_driver.c')
-rw-r--r-- | source/blender/editors/interface/eyedroppers/eyedropper_driver.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/source/blender/editors/interface/eyedroppers/eyedropper_driver.c b/source/blender/editors/interface/eyedroppers/eyedropper_driver.c new file mode 100644 index 00000000000..14c00c21a5c --- /dev/null +++ b/source/blender/editors/interface/eyedroppers/eyedropper_driver.c @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2009 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup edinterface + * + * Eyedropper (Animation Driver Targets). + * + * Defines: + * - #UI_OT_eyedropper_driver + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_anim_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" + +#include "BKE_animsys.h" +#include "BKE_context.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "ED_keyframing.h" + +#include "eyedropper_intern.h" +#include "interface_intern.h" + +typedef struct DriverDropper { + /* Destination property (i.e. where we'll add a driver) */ + PointerRNA ptr; + PropertyRNA *prop; + int index; + bool is_undo; + + /* TODO: new target? */ +} DriverDropper; + +static bool driverdropper_init(bContext *C, wmOperator *op) +{ + DriverDropper *ddr = MEM_callocN(sizeof(DriverDropper), __func__); + + uiBut *but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index); + + if ((ddr->ptr.data == NULL) || (ddr->prop == NULL) || + (RNA_property_editable(&ddr->ptr, ddr->prop) == false) || + (RNA_property_animateable(&ddr->ptr, ddr->prop) == false) || (but->flag & UI_BUT_DRIVEN)) { + MEM_freeN(ddr); + return false; + } + op->customdata = ddr; + + ddr->is_undo = UI_but_flag_is_set(but, UI_BUT_UNDO); + + return true; +} + +static void driverdropper_exit(bContext *C, wmOperator *op) +{ + WM_cursor_modal_restore(CTX_wm_window(C)); + + MEM_SAFE_FREE(op->customdata); +} + +static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *event) +{ + DriverDropper *ddr = (DriverDropper *)op->customdata; + uiBut *but = eyedropper_get_property_button_under_mouse(C, event); + + const short mapping_type = RNA_enum_get(op->ptr, "mapping_type"); + const short flag = 0; + + /* we can only add a driver if we know what RNA property it corresponds to */ + if (but == NULL) { + return; + } + /* Get paths for src... */ + PointerRNA *target_ptr = &but->rnapoin; + PropertyRNA *target_prop = but->rnaprop; + const int target_index = but->rnaindex; + + char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop); + + /* ... and destination */ + char *dst_path = RNA_path_from_ID_to_property(&ddr->ptr, ddr->prop); + + /* Now create driver(s) */ + if (target_path && dst_path) { + int success = ANIM_add_driver_with_target(op->reports, + ddr->ptr.owner_id, + dst_path, + ddr->index, + target_ptr->owner_id, + target_path, + target_index, + flag, + DRIVER_TYPE_PYTHON, + mapping_type); + + if (success) { + /* send updates */ + UI_context_update_anim_flag(C); + DEG_relations_tag_update(CTX_data_main(C)); + DEG_id_tag_update(ddr->ptr.owner_id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); /* XXX */ + } + } + + /* cleanup */ + if (target_path) { + MEM_freeN(target_path); + } + if (dst_path) { + MEM_freeN(dst_path); + } +} + +static void driverdropper_cancel(bContext *C, wmOperator *op) +{ + driverdropper_exit(C, op); +} + +/* main modal status check */ +static int driverdropper_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + DriverDropper *ddr = op->customdata; + + /* handle modal keymap */ + if (event->type == EVT_MODAL_MAP) { + switch (event->val) { + case EYE_MODAL_CANCEL: { + driverdropper_cancel(C, op); + return OPERATOR_CANCELLED; + } + case EYE_MODAL_SAMPLE_CONFIRM: { + const bool is_undo = ddr->is_undo; + driverdropper_sample(C, op, event); + driverdropper_exit(C, op); + /* Could support finished & undo-skip. */ + return is_undo ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + } + } + } + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal Operator init */ +static int driverdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + /* init */ + if (driverdropper_init(C, op)) { + wmWindow *win = CTX_wm_window(C); + /* Workaround for de-activating the button clearing the cursor, see T76794 */ + UI_context_active_but_clear(C, win, CTX_wm_region(C)); + WM_cursor_modal_set(win, WM_CURSOR_EYEDROPPER); + + /* add temp handler */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; + } + return OPERATOR_CANCELLED; +} + +/* Repeat operator */ +static int driverdropper_exec(bContext *C, wmOperator *op) +{ + /* init */ + if (driverdropper_init(C, op)) { + /* cleanup */ + driverdropper_exit(C, op); + + return OPERATOR_FINISHED; + } + return OPERATOR_CANCELLED; +} + +static bool driverdropper_poll(bContext *C) +{ + if (!CTX_wm_window(C)) { + return false; + } + return true; +} + +void UI_OT_eyedropper_driver(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Eyedropper Driver"; + ot->idname = "UI_OT_eyedropper_driver"; + ot->description = "Pick a property to use as a driver target"; + + /* api callbacks */ + ot->invoke = driverdropper_invoke; + ot->modal = driverdropper_modal; + ot->cancel = driverdropper_cancel; + ot->exec = driverdropper_exec; + ot->poll = driverdropper_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING | OPTYPE_INTERNAL; + + /* properties */ + RNA_def_enum(ot->srna, + "mapping_type", + prop_driver_create_mapping_types, + 0, + "Mapping Type", + "Method used to match target and driven properties"); +} |