Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/interface/interface_eyedropper.c')
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c442
1 files changed, 366 insertions, 76 deletions
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index ceea4ff42d9..2cbc56b14d3 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -29,6 +29,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_anim_types.h"
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
#include "DNA_object_types.h"
@@ -41,10 +42,13 @@
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_report.h"
+#include "BKE_animsys.h"
+#include "BKE_depsgraph.h"
#include "BKE_idcode.h"
#include "BKE_unit.h"
#include "RNA_access.h"
+#include "RNA_define.h"
#include "BIF_gl.h"
@@ -67,6 +71,62 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+/* for Driver eyedropper */
+#include "ED_keyframing.h"
+
+
+/* -------------------------------------------------------------------- */
+/* Keymap
+ */
+/** \name Modal Keymap
+ * \{ */
+
+enum {
+ EYE_MODAL_CANCEL = 1,
+ EYE_MODAL_SAMPLE_CONFIRM,
+ EYE_MODAL_SAMPLE_BEGIN,
+ EYE_MODAL_SAMPLE_RESET,
+};
+
+wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
+{
+ static EnumPropertyItem modal_items[] = {
+ {EYE_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
+ {EYE_MODAL_SAMPLE_CONFIRM, "SAMPLE_CONFIRM", 0, "Confirm Sampling", ""},
+ {EYE_MODAL_SAMPLE_BEGIN, "SAMPLE_BEGIN", 0, "Start Sampling", ""},
+ {EYE_MODAL_SAMPLE_RESET, "SAMPLE_RESET", 0, "Reset Sampling", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper Modal Map");
+
+ /* this function is called for each spacetype, only needs to add map once */
+ if (keymap && keymap->modal_items)
+ return NULL;
+
+ keymap = WM_modalkeymap_add(keyconf, "Eyedropper Modal Map", modal_items);
+
+ /* items for modal map */
+ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
+ WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
+ WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
+ WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
+ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_CONFIRM);
+ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_SAMPLE_BEGIN);
+ WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_SAMPLE_RESET);
+
+ /* assign to operators */
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color");
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id");
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth");
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_driver");
+
+ return keymap;
+}
+
+/** \} */
+
+
/* -------------------------------------------------------------------- */
/* Utility Functions
*/
@@ -97,6 +157,32 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c
UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg);
}
+
+/**
+ * Utility to retrieve a button representing a RNA property that is currently under the cursor.
+ *
+ * This is to be used by any eyedroppers which fetch properties (e.g. UI_OT_eyedropper_driver).
+ * Especially during modal operations (e.g. as with the eyedroppers), context cannot be relied
+ * upon to provide this information, as it is not updated until the operator finishes.
+ *
+ * \return A button under the mouse which relates to some RNA Property, or NULL
+ */
+static uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
+{
+ wmWindow *win = CTX_wm_window(C);
+ ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, event->x, event->y);
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_ANY, event->x, event->y);
+
+ uiBut *but = ui_but_find_mouse_over(ar, event);
+
+ if (ELEM(NULL, but, but->rnapoin.data, but->rnaprop)) {
+ return NULL;
+ }
+ else {
+ return but;
+ }
+}
+
/** \} */
@@ -114,7 +200,9 @@ typedef struct Eyedropper {
PropertyRNA *prop;
int index;
- bool accum_start; /* has mouse been presed */
+ float init_col[3]; /* for resetting on cancel */
+
+ bool accum_start; /* has mouse been pressed */
float accum_col[3];
int accum_tot;
} Eyedropper;
@@ -139,9 +227,17 @@ static bool eyedropper_init(bContext *C, wmOperator *op)
if (RNA_property_subtype(eye->prop) == PROP_COLOR) {
const char *display_device;
+ float col[4];
display_device = scene->display_settings.display_device;
eye->display = IMB_colormanagement_display_get_named(display_device);
+
+ /* store inital color */
+ RNA_property_float_get_array(&eye->ptr, eye->prop, col);
+ if (eye->display) {
+ IMB_colormanagement_scene_linear_to_display_v3(col, eye->display);
+ }
+ copy_v3_v3(eye->init_col, col);
}
return true;
@@ -157,11 +253,6 @@ static void eyedropper_exit(bContext *C, wmOperator *op)
}
}
-static void eyedropper_cancel(bContext *C, wmOperator *op)
-{
- eyedropper_exit(C, op);
-}
-
/* *** eyedropper_color_ helper functions *** */
/**
@@ -268,18 +359,25 @@ static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx,
eye->accum_tot++;
}
+static void eyedropper_cancel(bContext *C, wmOperator *op)
+{
+ Eyedropper *eye = op->customdata;
+ eyedropper_color_set(C, eye, eye->init_col);
+ eyedropper_exit(C, op);
+}
+
/* main modal status check */
static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Eyedropper *eye = (Eyedropper *)op->customdata;
- switch (event->type) {
- case ESCKEY:
- case RIGHTMOUSE:
- eyedropper_cancel(C, op);
- return OPERATOR_CANCELLED;
- case LEFTMOUSE:
- if (event->val == KM_RELEASE) {
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ eyedropper_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_SAMPLE_CONFIRM:
if (eye->accum_tot == 0) {
eyedropper_color_sample(C, eye, event->x, event->y);
}
@@ -288,28 +386,25 @@ static int eyedropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
eyedropper_exit(C, op);
return OPERATOR_FINISHED;
- }
- else if (event->val == KM_PRESS) {
+ case EYE_MODAL_SAMPLE_BEGIN:
/* enable accum and make first sample */
eye->accum_start = true;
eyedropper_color_sample_accum(C, eye, event->x, event->y);
- }
- break;
- case MOUSEMOVE:
- if (eye->accum_start) {
- /* button is pressed so keep sampling */
- eyedropper_color_sample_accum(C, eye, event->x, event->y);
- eyedropper_color_set_accum(C, eye);
- }
- break;
- case SPACEKEY:
- if (event->val == KM_RELEASE) {
+ break;
+ case EYE_MODAL_SAMPLE_RESET:
eye->accum_tot = 0;
zero_v3(eye->accum_col);
eyedropper_color_sample_accum(C, eye, event->x, event->y);
eyedropper_color_set_accum(C, eye);
- }
- break;
+ break;
+ }
+ }
+ else if (event->type == MOUSEMOVE) {
+ if (eye->accum_start) {
+ /* button is pressed so keep sampling */
+ eyedropper_color_sample_accum(C, eye, event->x, event->y);
+ eyedropper_color_set_accum(C, eye);
+ }
}
return OPERATOR_RUNNING_MODAL;
@@ -362,7 +457,7 @@ void UI_OT_eyedropper_color(wmOperatorType *ot)
/* identifiers */
ot->name = "Eyedropper";
ot->idname = "UI_OT_eyedropper_color";
- ot->description = "Sample a data-block from the 3D view";
+ ot->description = "Sample a color from the Blender Window to store in a property";
/* api callbacks */
ot->invoke = eyedropper_invoke;
@@ -394,6 +489,8 @@ typedef struct DataDropper {
short idcode;
const char *idcode_name;
+ ID *init_id; /* for resetting on cancel */
+
ARegionType *art;
void *draw_handle_pixel;
char name[200];
@@ -440,6 +537,9 @@ static int datadropper_init(bContext *C, wmOperator *op)
/* Note we can translate here (instead of on draw time), because this struct has very short lifetime. */
ddr->idcode_name = TIP_(BKE_idcode_to_name(ddr->idcode));
+ PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
+ ddr->init_id = ptr.id.data;
+
return true;
}
@@ -462,11 +562,6 @@ static void datadropper_exit(bContext *C, wmOperator *op)
WM_event_add_mousemove(C);
}
-static void datadropper_cancel(bContext *C, wmOperator *op)
-{
- datadropper_exit(C, op);
-}
-
/* *** datadropper id helper functions *** */
/**
* \brief get the ID from the screen.
@@ -474,7 +569,6 @@ static void datadropper_cancel(bContext *C, wmOperator *op)
*/
static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
{
-
/* we could use some clever */
wmWindow *win = CTX_wm_window(C);
ScrArea *sa = BKE_screen_find_area_xy(win->screen, -1, mx, my);
@@ -555,18 +649,26 @@ static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my)
return datadropper_id_set(C, ddr, id);
}
+static void datadropper_cancel(bContext *C, wmOperator *op)
+{
+ DataDropper *ddr = op->customdata;
+ datadropper_id_set(C, ddr, ddr->init_id);
+ datadropper_exit(C, op);
+}
+
/* main modal status check */
static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
DataDropper *ddr = (DataDropper *)op->customdata;
- switch (event->type) {
- case ESCKEY:
- case RIGHTMOUSE:
- datadropper_cancel(C, op);
- return OPERATOR_CANCELLED;
- case LEFTMOUSE:
- if (event->val == KM_RELEASE) {
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ datadropper_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_SAMPLE_CONFIRM:
+ {
bool success;
success = datadropper_id_sample(C, ddr, event->x, event->y);
@@ -580,14 +682,12 @@ static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
}
- break;
- case MOUSEMOVE:
- {
- ID *id = NULL;
- datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
- break;
}
}
+ else if (event->type == MOUSEMOVE) {
+ ID *id = NULL;
+ datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
+ }
return OPERATOR_RUNNING_MODAL;
}
@@ -636,7 +736,7 @@ void UI_OT_eyedropper_id(wmOperatorType *ot)
/* identifiers */
ot->name = "Eyedropper Datablock";
ot->idname = "UI_OT_eyedropper_id";
- ot->description = "Sample a datablock from the Blender Window to store in a property";
+ ot->description = "Sample a datablock from the 3D View to store in a property";
/* api callbacks */
ot->invoke = datadropper_invoke;
@@ -666,6 +766,8 @@ typedef struct DepthDropper {
PointerRNA ptr;
PropertyRNA *prop;
+ float init_depth; /* for resetting on cancel */
+
bool accum_start; /* has mouse been presed */
float accum_depth;
int accum_tot;
@@ -720,6 +822,7 @@ static int depthdropper_init(bContext *C, wmOperator *op)
ddr->art = art;
ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, depthdropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
+ ddr->init_depth = RNA_property_float_get(&ddr->ptr, ddr->prop);
return true;
}
@@ -741,11 +844,6 @@ static void depthdropper_exit(bContext *C, wmOperator *op)
}
}
-static void depthdropper_cancel(bContext *C, wmOperator *op)
-{
- depthdropper_exit(C, op);
-}
-
/* *** depthdropper id helper functions *** */
/**
* \brief get the ID from the screen.
@@ -850,18 +948,25 @@ static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int
}
}
+static void depthdropper_cancel(bContext *C, wmOperator *op)
+{
+ DepthDropper *ddr = op->customdata;
+ depthdropper_depth_set(C, ddr, ddr->init_depth);
+ depthdropper_exit(C, op);
+}
+
/* main modal status check */
static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
DepthDropper *ddr = (DepthDropper *)op->customdata;
- switch (event->type) {
- case ESCKEY:
- case RIGHTMOUSE:
- depthdropper_cancel(C, op);
- return OPERATOR_CANCELLED;
- case LEFTMOUSE:
- if (event->val == KM_RELEASE) {
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ depthdropper_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_SAMPLE_CONFIRM:
if (ddr->accum_tot == 0) {
depthdropper_depth_sample(C, ddr, event->x, event->y);
}
@@ -870,28 +975,25 @@ static int depthdropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
depthdropper_exit(C, op);
return OPERATOR_FINISHED;
- }
- else if (event->val == KM_PRESS) {
+ case EYE_MODAL_SAMPLE_BEGIN:
/* enable accum and make first sample */
ddr->accum_start = true;
depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
- }
- break;
- case MOUSEMOVE:
- if (ddr->accum_start) {
- /* button is pressed so keep sampling */
- depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
- depthdropper_depth_set_accum(C, ddr);
- }
- break;
- case SPACEKEY:
- if (event->val == KM_RELEASE) {
+ break;
+ case EYE_MODAL_SAMPLE_RESET:
ddr->accum_tot = 0;
ddr->accum_depth = 0.0f;
depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
depthdropper_depth_set_accum(C, ddr);
- }
- break;
+ break;
+ }
+ }
+ else if (event->type == MOUSEMOVE) {
+ if (ddr->accum_start) {
+ /* button is pressed so keep sampling */
+ depthdropper_depth_sample_accum(C, ddr, event->x, event->y);
+ depthdropper_depth_set_accum(C, ddr);
+ }
}
return OPERATOR_RUNNING_MODAL;
@@ -957,3 +1059,191 @@ void UI_OT_eyedropper_depth(wmOperatorType *ot)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/* Eyedropper
+ */
+
+/* NOTE: This is here (instead of in drivers.c) because we need access the button internals,
+ * which we cannot access outside of the interface module
+ */
+
+/** \name Eyedropper (Driver Target)
+ * \{ */
+
+typedef struct DriverDropper {
+ /* Destination property (i.e. where we'll add a driver) */
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+ // TODO: new target?
+} DriverDropper;
+
+static bool driverdropper_init(bContext *C, wmOperator *op)
+{
+ DriverDropper *ddr;
+ uiBut *but;
+
+ op->customdata = ddr = MEM_callocN(sizeof(DriverDropper), "DriverDropper");
+
+ UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &ddr->index);
+ but = UI_context_active_but_get(C);
+
+ 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))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+static void driverdropper_exit(bContext *C, wmOperator *op)
+{
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ if (op->customdata) {
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+ }
+}
+
+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);
+
+ short mapping_type = RNA_enum_get(op->ptr, "mapping_type");
+ short flag = 0;
+
+ /* we can only add a driver if we know what RNA property it corresponds to */
+ if (but == NULL) {
+ return;
+ }
+ else {
+ /* Get paths for src... */
+ PointerRNA *target_ptr = &but->rnapoin;
+ PropertyRNA *target_prop = but->rnaprop;
+ 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.id.data, dst_path, ddr->index,
+ target_ptr->id.data, target_path, target_index,
+ flag, DRIVER_TYPE_PYTHON, mapping_type);
+
+ if (success) {
+ /* send updates */
+ UI_context_update_anim_flag(C);
+ DAG_relations_tag_update(CTX_data_main(C));
+ DAG_id_tag_update(ddr->ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA);
+ 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)
+{
+ /* 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:
+ driverdropper_sample(C, op, event);
+ driverdropper_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ }
+
+ 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)) {
+ WM_cursor_modal_set(CTX_wm_window(C), BC_EYEDROPPER_CURSOR);
+
+ /* add temp handler */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ driverdropper_exit(C, op);
+ 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;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int driverdropper_poll(bContext *C)
+{
+ if (!CTX_wm_window(C)) return 0;
+ else return 1;
+}
+
+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_BLOCKING | OPTYPE_INTERNAL | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_enum(ot->srna, "mapping_type", prop_driver_create_mapping_types, 0,
+ "Mapping Type", "Method used to match target and driven properties");
+}
+
+/** \} */