237 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			237 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * This program is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU General Public License
 | |
|  * as published by the Free Software Foundation; either version 2
 | |
|  * of the License, or (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program; if not, write to the Free Software Foundation,
 | |
|  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 | |
|  *
 | |
|  * The Original Code is Copyright (C) 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 "interface_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 = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL);
 | |
| 
 | |
|   /* 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");
 | |
| }
 |