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')
-rw-r--r--source/blender/editors/interface/CMakeLists.txt5
-rw-r--r--source/blender/editors/interface/interface_draw.c6
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c1205
-rw-r--r--source/blender/editors/interface/interface_eyedropper_color.c356
-rw-r--r--source/blender/editors/interface/interface_eyedropper_colorband.c337
-rw-r--r--source/blender/editors/interface/interface_eyedropper_datablock.c351
-rw-r--r--source/blender/editors/interface/interface_eyedropper_depth.c391
-rw-r--r--source/blender/editors/interface/interface_eyedropper_driver.c234
-rw-r--r--source/blender/editors/interface/interface_eyedropper_intern.h54
-rw-r--r--source/blender/editors/interface/interface_handlers.c96
-rw-r--r--source/blender/editors/interface/interface_intern.h16
-rw-r--r--source/blender/editors/interface/interface_layout.c2
-rw-r--r--source/blender/editors/interface/interface_ops.c5
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c256
-rw-r--r--source/blender/editors/interface/interface_templates.c336
-rw-r--r--source/blender/editors/interface/interface_widgets.c6
-rw-r--r--source/blender/editors/interface/resources.c4
-rw-r--r--source/blender/editors/interface/view2d_ops.c3
18 files changed, 2268 insertions, 1395 deletions
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 03a2c1ec414..94f377fb35e 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -45,6 +45,11 @@ set(SRC
interface_anim.c
interface_draw.c
interface_eyedropper.c
+ interface_eyedropper_color.c
+ interface_eyedropper_colorband.c
+ interface_eyedropper_datablock.c
+ interface_eyedropper_depth.c
+ interface_eyedropper_driver.c
interface_handlers.c
interface_icons.c
interface_layout.c
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index e46c6a0e267..3ecb72353bc 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -40,9 +40,9 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_node.h"
-#include "BKE_texture.h"
#include "BKE_tracking.h"
@@ -1335,7 +1335,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
immBegin(GWN_PRIM_TRI_STRIP, (sizex + 1) * 2);
for (int a = 0; a <= sizex; a++) {
float pos = ((float)a) / sizex;
- do_colorband(coba, pos, colf);
+ BKE_colorband_evaluate(coba, pos, colf);
if (display)
IMB_colormanagement_scene_linear_to_display_v3(colf, display);
@@ -1354,7 +1354,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
immBegin(GWN_PRIM_TRI_STRIP, (sizex + 1) * 2);
for (int a = 0; a <= sizex; a++) {
float pos = ((float)a) / sizex;
- do_colorband(coba, pos, colf);
+ BKE_colorband_evaluate(coba, pos, colf);
if (display)
IMB_colormanagement_scene_linear_to_display_v3(colf, display);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index e92139ada0c..8cb55b724fb 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -27,55 +27,23 @@
* \ingroup edinterface
*/
-#include "MEM_guardedalloc.h"
-
-#include "DNA_anim_types.h"
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
-#include "DNA_object_types.h"
#include "BLI_blenlib.h"
#include "BLI_math_vector.h"
-#include "BLT_translation.h"
-
#include "BKE_context.h"
#include "BKE_screen.h"
-#include "BKE_report.h"
-#include "BKE_animsys.h"
-#include "BKE_idcode.h"
-#include "BKE_unit.h"
-
-#include "DEG_depsgraph.h"
-#include "DEG_depsgraph_build.h"
-
-#include "RNA_access.h"
-#include "RNA_define.h"
-
-#include "BIF_gl.h"
#include "UI_interface.h"
-#include "IMB_colormanagement.h"
-
#include "WM_api.h"
#include "WM_types.h"
#include "interface_intern.h"
-/* for HDR color sampling */
-#include "ED_image.h"
-#include "ED_node.h"
-#include "ED_clip.h"
-
-/* for ID data eyedropper */
-#include "ED_space_api.h"
-#include "ED_screen.h"
-#include "ED_view3d.h"
-
-/* for Driver eyedropper */
-#include "ED_keyframing.h"
-
+#include "interface_eyedropper_intern.h" /* own include */
/* -------------------------------------------------------------------- */
/* Keymap
@@ -83,12 +51,6 @@
/** \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)
{
@@ -118,6 +80,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
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_colorband");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_color");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_id");
WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_depth");
@@ -126,6 +89,37 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
return keymap;
}
+wmKeyMap *eyedropper_colorband_modal_keymap(wmKeyConfig *keyconf)
+{
+ static const EnumPropertyItem modal_items_point[] = {
+ {EYE_MODAL_POINT_CANCEL, "CANCEL", 0, "Cancel", ""},
+ {EYE_MODAL_POINT_SAMPLE, "SAMPLE_SAMPLE", 0, "Sample a point", ""},
+ {EYE_MODAL_POINT_CONFIRM, "SAMPLE_CONFIRM", 0, "Confirm Sampling", ""},
+ {EYE_MODAL_POINT_RESET, "SAMPLE_RESET", 0, "Reset Sampling", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Eyedropper ColorBand PointSampling Map");
+ if (keymap && keymap->modal_items)
+ return keymap;
+
+ keymap = WM_modalkeymap_add(keyconf, "Eyedropper ColorBand PointSampling Map", modal_items_point);
+
+ /* items for modal map */
+ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_CANCEL);
+ WM_modalkeymap_add_item(keymap, BACKSPACEKEY, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_REMOVE_LAST);
+ WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM);
+ WM_modalkeymap_add_item(keymap, RETKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM);
+ WM_modalkeymap_add_item(keymap, PADENTER, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_CONFIRM);
+ WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, EYE_MODAL_POINT_SAMPLE);
+ WM_modalkeymap_add_item(keymap, SPACEKEY, KM_RELEASE, KM_ANY, 0, EYE_MODAL_POINT_RESET);
+
+ /* assign to operators */
+ WM_modalkeymap_assign(keymap, "UI_OT_eyedropper_colorband_point");
+
+ return keymap;
+}
+
/** \} */
@@ -135,7 +129,7 @@ wmKeyMap *eyedropper_modal_keymap(wmKeyConfig *keyconf)
/** \name Generic Shared Functions
* \{ */
-static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, const char *name)
+void eyedropper_draw_cursor_text(const struct bContext *C, const ARegion *ar, const char *name)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
wmWindow *win = CTX_wm_window(C);
@@ -169,14 +163,14 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c
*
* \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)
+uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event)
{
bScreen *screen = CTX_wm_screen(C);
ScrArea *sa = BKE_screen_find_area_xy(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;
}
@@ -187,1128 +181,3 @@ static uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEv
/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Eyedropper
- */
-
-/** \name Eyedropper (RGB Color)
- * \{ */
-
-typedef struct Eyedropper {
- struct ColorManagedDisplay *display;
-
- PointerRNA ptr;
- PropertyRNA *prop;
- int index;
-
- float init_col[3]; /* for resetting on cancel */
-
- bool accum_start; /* has mouse been pressed */
- float accum_col[3];
- int accum_tot;
-} Eyedropper;
-
-static bool eyedropper_init(bContext *C, wmOperator *op)
-{
- Scene *scene = CTX_data_scene(C);
- Eyedropper *eye;
-
- op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper");
-
- UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
-
- if ((eye->ptr.data == NULL) ||
- (eye->prop == NULL) ||
- (RNA_property_editable(&eye->ptr, eye->prop) == false) ||
- (RNA_property_array_length(&eye->ptr, eye->prop) < 3) ||
- (RNA_property_type(eye->prop) != PROP_FLOAT))
- {
- return false;
- }
-
- 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_display_to_scene_linear_v3(col, eye->display);
- }
- copy_v3_v3(eye->init_col, col);
- }
-
- return true;
-}
-
-static void eyedropper_exit(bContext *C, wmOperator *op)
-{
- WM_cursor_modal_restore(CTX_wm_window(C));
-
- if (op->customdata) {
- MEM_freeN(op->customdata);
- op->customdata = NULL;
- }
-}
-
-/* *** eyedropper_color_ helper functions *** */
-
-/**
- * \brief get the color from the screen.
- *
- * Special check for image or nodes where we MAY have HDR pixels which don't display.
- */
-static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int mx, int my, float r_col[3])
-{
- /* we could use some clever */
- bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
- const char *display_device = CTX_data_scene(C)->display_settings.display_device;
- struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
-
- if (sa) {
- if (sa->spacetype == SPACE_IMAGE) {
- ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
- if (ar) {
- SpaceImage *sima = sa->spacedata.first;
- int mval[2] = {mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
-
- if (ED_space_image_color_sample(sima, ar, mval, r_col)) {
- return;
- }
- }
- }
- else if (sa->spacetype == SPACE_NODE) {
- ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
- if (ar) {
- SpaceNode *snode = sa->spacedata.first;
- int mval[2] = {mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
-
- if (ED_space_node_color_sample(snode, ar, mval, r_col)) {
- return;
- }
- }
- }
- else if (sa->spacetype == SPACE_CLIP) {
- ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
- if (ar) {
- SpaceClip *sc = sa->spacedata.first;
- int mval[2] = {mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
-
- if (ED_space_clip_color_sample(sc, ar, mval, r_col)) {
- return;
- }
- }
- }
- }
-
- /* fallback to simple opengl picker */
- glReadBuffer(GL_FRONT);
- glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col);
- glReadBuffer(GL_BACK);
-
- IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
-}
-
-/* sets the sample color RGB, maintaining A */
-static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3])
-{
- float col_conv[4];
-
- /* to maintain alpha */
- RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv);
-
- /* convert from linear rgb space to display space */
- if (eye->display) {
- copy_v3_v3(col_conv, col);
- IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
- }
- else {
- copy_v3_v3(col_conv, col);
- }
-
- RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv);
-
- RNA_property_update(C, &eye->ptr, eye->prop);
-}
-
-/* set sample from accumulated values */
-static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye)
-{
- float col[3];
- mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot);
- eyedropper_color_set(C, eye, col);
-}
-
-/* single point sample & set */
-static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my)
-{
- float col[3];
- eyedropper_color_sample_fl(C, eye, mx, my, col);
- eyedropper_color_set(C, eye, col);
-}
-
-static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my)
-{
- float col[3];
- eyedropper_color_sample_fl(C, eye, mx, my, col);
- /* delay linear conversion */
- add_v3_v3(eye->accum_col, col);
- 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;
-
- /* 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);
- }
- else {
- eyedropper_color_set_accum(C, eye);
- }
- eyedropper_exit(C, op);
- return OPERATOR_FINISHED;
- 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 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;
- }
- }
- 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;
-}
-
-/* Modal Operator init */
-static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- /* init */
- if (eyedropper_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 {
- eyedropper_exit(C, op);
- return OPERATOR_CANCELLED;
- }
-}
-
-/* Repeat operator */
-static int eyedropper_exec(bContext *C, wmOperator *op)
-{
- /* init */
- if (eyedropper_init(C, op)) {
-
- /* do something */
-
- /* cleanup */
- eyedropper_exit(C, op);
-
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static int eyedropper_poll(bContext *C)
-{
- PointerRNA ptr;
- PropertyRNA *prop;
- int index_dummy;
- uiBut *but;
-
- /* Only color buttons */
- if ((CTX_wm_window(C) != NULL) &&
- (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
- (but->type == UI_BTYPE_COLOR))
- {
- return 1;
- }
-
- return 0;
-}
-
-void UI_OT_eyedropper_color(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Eyedropper";
- ot->idname = "UI_OT_eyedropper_color";
- ot->description = "Sample a color from the Blender Window to store in a property";
-
- /* api callbacks */
- ot->invoke = eyedropper_invoke;
- ot->modal = eyedropper_modal;
- ot->cancel = eyedropper_cancel;
- ot->exec = eyedropper_exec;
- ot->poll = eyedropper_poll;
-
- /* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
-
- /* properties */
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-/* Data Dropper */
-
-/** \name Eyedropper (ID data-blocks)
- *
- * \note: datadropper is only internal name to avoid confusion in this file.
- * \{ */
-
-typedef struct DataDropper {
- PointerRNA ptr;
- PropertyRNA *prop;
- short idcode;
- const char *idcode_name;
-
- ID *init_id; /* for resetting on cancel */
-
- ARegionType *art;
- void *draw_handle_pixel;
- char name[200];
-} DataDropper;
-
-
-static void datadropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
-{
- DataDropper *ddr = arg;
- eyedropper_draw_cursor_text(C, ar, ddr->name);
-}
-
-
-static int datadropper_init(bContext *C, wmOperator *op)
-{
- DataDropper *ddr;
- int index_dummy;
- StructRNA *type;
-
- SpaceType *st;
- ARegionType *art;
-
- st = BKE_spacetype_from_id(SPACE_VIEW3D);
- art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW);
-
- op->customdata = ddr = MEM_callocN(sizeof(DataDropper), "DataDropper");
-
- UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
-
- if ((ddr->ptr.data == NULL) ||
- (ddr->prop == NULL) ||
- (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
- (RNA_property_type(ddr->prop) != PROP_POINTER))
- {
- return false;
- }
-
- ddr->art = art;
- ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
-
- type = RNA_property_pointer_type(&ddr->ptr, ddr->prop);
- ddr->idcode = RNA_type_to_ID_code(type);
- BLI_assert(ddr->idcode != 0);
- /* 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;
-}
-
-static void datadropper_exit(bContext *C, wmOperator *op)
-{
- WM_cursor_modal_restore(CTX_wm_window(C));
-
- if (op->customdata) {
- DataDropper *ddr = (DataDropper *)op->customdata;
-
- if (ddr->art) {
- ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
- }
-
- MEM_freeN(op->customdata);
-
- op->customdata = NULL;
- }
-
- WM_event_add_mousemove(C);
-}
-
-/* *** datadropper id helper functions *** */
-/**
- * \brief get the ID from the screen.
- *
- */
-static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
-{
- /* we could use some clever */
- bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
-
- ScrArea *area_prev = CTX_wm_area(C);
- ARegion *ar_prev = CTX_wm_region(C);
-
- ddr->name[0] = '\0';
-
- if (sa) {
- if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
- if (ar) {
- const int mval[2] = {
- mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
- Base *base;
-
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, ar);
-
- /* grr, always draw else we leave stale text */
- ED_region_tag_redraw(ar);
-
- base = ED_view3d_give_base_under_cursor(C, mval);
- if (base) {
- Object *ob = base->object;
- ID *id = NULL;
- if (ddr->idcode == ID_OB) {
- id = (ID *)ob;
- }
- else if (ob->data) {
- if (GS(((ID *)ob->data)->name) == ddr->idcode) {
- id = (ID *)ob->data;
- }
- else {
- BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s",
- ddr->idcode_name);
- }
- }
-
- if (id) {
- BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s",
- ddr->idcode_name, id->name + 2);
- *r_id = id;
- }
- }
- }
- }
- }
-
- CTX_wm_area_set(C, area_prev);
- CTX_wm_region_set(C, ar_prev);
-}
-
-/* sets the ID, returns success */
-static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id)
-{
- PointerRNA ptr_value;
-
- RNA_id_pointer_create(id, &ptr_value);
-
- RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value);
-
- RNA_property_update(C, &ddr->ptr, ddr->prop);
-
- ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
-
- return (ptr_value.id.data == id);
-}
-
-/* single point sample & set */
-static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my)
-{
- ID *id = NULL;
-
- datadropper_id_sample_pt(C, ddr, mx, my, &id);
- 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;
-
- /* 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);
- datadropper_exit(C, op);
-
- if (success) {
- return OPERATOR_FINISHED;
- }
- else {
- BKE_report(op->reports, RPT_WARNING, "Failed to set value");
- return OPERATOR_CANCELLED;
- }
- }
- }
- }
- else if (event->type == MOUSEMOVE) {
- ID *id = NULL;
- datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
- }
-
- return OPERATOR_RUNNING_MODAL;
-}
-
-/* Modal Operator init */
-static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- /* init */
- if (datadropper_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 {
- datadropper_exit(C, op);
- return OPERATOR_CANCELLED;
- }
-}
-
-/* Repeat operator */
-static int datadropper_exec(bContext *C, wmOperator *op)
-{
- /* init */
- if (datadropper_init(C, op)) {
- /* cleanup */
- datadropper_exit(C, op);
-
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static int datadropper_poll(bContext *C)
-{
- PointerRNA ptr;
- PropertyRNA *prop;
- int index_dummy;
- uiBut *but;
-
- /* data dropper only supports object data */
- if ((CTX_wm_window(C) != NULL) &&
- (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
- (but->type == UI_BTYPE_SEARCH_MENU) &&
- (but->flag & UI_BUT_VALUE_CLEAR))
- {
- if (prop && RNA_property_type(prop) == PROP_POINTER) {
- StructRNA *type = RNA_property_pointer_type(&ptr, prop);
- const short idcode = RNA_type_to_ID_code(type);
- if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-void UI_OT_eyedropper_id(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Eyedropper Data-Block";
- ot->idname = "UI_OT_eyedropper_id";
- ot->description = "Sample a data-block from the 3D View to store in a property";
-
- /* api callbacks */
- ot->invoke = datadropper_invoke;
- ot->modal = datadropper_modal;
- ot->cancel = datadropper_cancel;
- ot->exec = datadropper_exec;
- ot->poll = datadropper_poll;
-
- /* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
-
- /* properties */
-}
-
-/** \} */
-
-
-/* -------------------------------------------------------------------- */
-/* Depth Dropper */
-
-/** \name Eyedropper (Depth)
- *
- * \note: depthdropper is only internal name to avoid confusion in this file.
- * \{ */
-
-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;
-
- ARegionType *art;
- void *draw_handle_pixel;
- char name[200];
-} DepthDropper;
-
-
-static void depthdropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
-{
- DepthDropper *ddr = arg;
- eyedropper_draw_cursor_text(C, ar, ddr->name);
-}
-
-
-static int depthdropper_init(bContext *C, wmOperator *op)
-{
- DepthDropper *ddr;
- int index_dummy;
-
- SpaceType *st;
- ARegionType *art;
-
- st = BKE_spacetype_from_id(SPACE_VIEW3D);
- art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW);
-
- op->customdata = ddr = MEM_callocN(sizeof(DepthDropper), "DepthDropper");
-
- UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
-
- /* fallback to the active camera's dof */
- if (ddr->prop == NULL) {
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (rv3d && rv3d->persp == RV3D_CAMOB) {
- View3D *v3d = CTX_wm_view3d(C);
- if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) {
- RNA_id_pointer_create(v3d->camera->data, &ddr->ptr);
- ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance");
- }
- }
- }
-
- if ((ddr->ptr.data == NULL) ||
- (ddr->prop == NULL) ||
- (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
- (RNA_property_type(ddr->prop) != PROP_FLOAT))
- {
- return false;
- }
-
- 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;
-}
-
-static void depthdropper_exit(bContext *C, wmOperator *op)
-{
- WM_cursor_modal_restore(CTX_wm_window(C));
-
- if (op->customdata) {
- DepthDropper *ddr = (DepthDropper *)op->customdata;
-
- if (ddr->art) {
- ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
- }
-
- MEM_freeN(op->customdata);
-
- op->customdata = NULL;
- }
-}
-
-/* *** depthdropper id helper functions *** */
-/**
- * \brief get the ID from the screen.
- *
- */
-static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth)
-{
- /* we could use some clever */
- bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
- Scene *scene = CTX_data_scene(C);
- UnitSettings *unit = &scene->unit;
- const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
-
- ScrArea *area_prev = CTX_wm_area(C);
- ARegion *ar_prev = CTX_wm_region(C);
-
- ddr->name[0] = '\0';
-
- if (sa) {
- if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
- if (ar) {
- struct Depsgraph *graph = CTX_data_depsgraph(C);
- View3D *v3d = sa->spacedata.first;
- RegionView3D *rv3d = ar->regiondata;
- /* weak, we could pass in some reference point */
- const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3];
- const int mval[2] = {
- mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
- float co[3];
-
- EvaluationContext eval_ctx;
- CTX_data_eval_ctx(C, &eval_ctx);
-
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, ar);
-
- /* grr, always draw else we leave stale text */
- ED_region_tag_redraw(ar);
-
- view3d_operator_needs_opengl(C);
-
- if (ED_view3d_autodist(&eval_ctx, graph, ar, v3d, mval, co, true, NULL)) {
- const float mval_center_fl[2] = {
- (float)ar->winx / 2,
- (float)ar->winy / 2};
- float co_align[3];
-
- /* quick way to get view-center aligned point */
- ED_view3d_win_to_3d(v3d, ar, co, mval_center_fl, co_align);
-
- *r_depth = len_v3v3(view_co, co_align);
-
- bUnit_AsString(ddr->name, sizeof(ddr->name),
- (double)*r_depth,
- 4, unit->system, B_UNIT_LENGTH, do_split, false);
- }
- else {
- BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name));
- }
- }
- }
- }
-
- CTX_wm_area_set(C, area_prev);
- CTX_wm_region_set(C, ar_prev);
-}
-
-/* sets the sample depth RGB, maintaining A */
-static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth)
-{
- RNA_property_float_set(&ddr->ptr, ddr->prop, depth);
- RNA_property_update(C, &ddr->ptr, ddr->prop);
-}
-
-/* set sample from accumulated values */
-static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr)
-{
- float depth = ddr->accum_depth;
- if (ddr->accum_tot) {
- depth /= (float)ddr->accum_tot;
- }
- depthdropper_depth_set(C, ddr, depth);
-}
-
-/* single point sample & set */
-static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, int mx, int my)
-{
- float depth = -1.0f;
- if (depth != -1.0f) {
- depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
- depthdropper_depth_set(C, ddr, depth);
- }
-}
-
-static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int mx, int my)
-{
- float depth = -1.0f;
- depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
- if (depth != -1.0f) {
- ddr->accum_depth += depth;
- ddr->accum_tot++;
- }
-}
-
-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;
-
- /* 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);
- }
- else {
- depthdropper_depth_set_accum(C, ddr);
- }
- depthdropper_exit(C, op);
- return OPERATOR_FINISHED;
- 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 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;
- }
- }
- 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;
-}
-
-/* Modal Operator init */
-static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
-{
- /* init */
- if (depthdropper_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 {
- depthdropper_exit(C, op);
- return OPERATOR_CANCELLED;
- }
-}
-
-/* Repeat operator */
-static int depthdropper_exec(bContext *C, wmOperator *op)
-{
- /* init */
- if (depthdropper_init(C, op)) {
- /* cleanup */
- depthdropper_exit(C, op);
-
- return OPERATOR_FINISHED;
- }
- else {
- return OPERATOR_CANCELLED;
- }
-}
-
-static int depthdropper_poll(bContext *C)
-{
- PointerRNA ptr;
- PropertyRNA *prop;
- int index_dummy;
- uiBut *but;
-
- /* check if there's an active button taking depth value */
- if ((CTX_wm_window(C) != NULL) &&
- (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
- (but->type == UI_BTYPE_NUM) &&
- (prop != NULL))
- {
- if ((RNA_property_type(prop) == PROP_FLOAT) &&
- (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) &&
- (RNA_property_array_check(prop) == false))
- {
- return 1;
- }
- }
- else {
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- if (rv3d && rv3d->persp == RV3D_CAMOB) {
- View3D *v3d = CTX_wm_view3d(C);
- if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) {
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-void UI_OT_eyedropper_depth(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Eyedropper Depth";
- ot->idname = "UI_OT_eyedropper_depth";
- ot->description = "Sample depth from the 3D view";
-
- /* api callbacks */
- ot->invoke = depthdropper_invoke;
- ot->modal = depthdropper_modal;
- ot->cancel = depthdropper_cancel;
- ot->exec = depthdropper_exec;
- ot->poll = depthdropper_poll;
-
- /* flags */
- ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
-
- /* properties */
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* 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");
-
- 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))
- {
- 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);
- DEG_relations_tag_update(CTX_data_main(C));
- DEG_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");
-}
-
-/** \} */
diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c
new file mode 100644
index 00000000000..f3301d55284
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_color.c
@@ -0,0 +1,356 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_eyedropper_color.c
+ * \ingroup edinterface
+ *
+ * Eyedropper (RGB Color)
+ *
+ * Defines:
+ * - #UI_OT_eyedropper_color
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+
+#include "BLI_math_vector.h"
+
+#include "BKE_context.h"
+#include "BKE_screen.h"
+
+#include "RNA_access.h"
+
+#include "BIF_gl.h"
+
+#include "UI_interface.h"
+
+#include "IMB_colormanagement.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "interface_intern.h"
+
+#include "ED_image.h"
+#include "ED_node.h"
+#include "ED_clip.h"
+
+#include "interface_eyedropper_intern.h"
+
+typedef struct Eyedropper {
+ struct ColorManagedDisplay *display;
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+
+ float init_col[3]; /* for resetting on cancel */
+
+ bool accum_start; /* has mouse been pressed */
+ float accum_col[3];
+ int accum_tot;
+} Eyedropper;
+
+static bool eyedropper_init(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Eyedropper *eye;
+
+ op->customdata = eye = MEM_callocN(sizeof(Eyedropper), "Eyedropper");
+
+ UI_context_active_but_prop_get(C, &eye->ptr, &eye->prop, &eye->index);
+
+ if ((eye->ptr.data == NULL) ||
+ (eye->prop == NULL) ||
+ (RNA_property_editable(&eye->ptr, eye->prop) == false) ||
+ (RNA_property_array_length(&eye->ptr, eye->prop) < 3) ||
+ (RNA_property_type(eye->prop) != PROP_FLOAT))
+ {
+ return false;
+ }
+
+ 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_display_to_scene_linear_v3(col, eye->display);
+ }
+ copy_v3_v3(eye->init_col, col);
+ }
+
+ return true;
+}
+
+static void eyedropper_exit(bContext *C, wmOperator *op)
+{
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ if (op->customdata) {
+ MEM_freeN(op->customdata);
+ op->customdata = NULL;
+ }
+}
+
+/* *** eyedropper_color_ helper functions *** */
+
+/**
+ * \brief get the color from the screen.
+ *
+ * Special check for image or nodes where we MAY have HDR pixels which don't display.
+ *
+ * \note Exposed by 'interface_eyedropper_intern.h' for use with color band picking.
+ */
+void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3])
+{
+ /* we could use some clever */
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ const char *display_device = CTX_data_scene(C)->display_settings.display_device;
+ struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
+
+ if (sa) {
+ if (sa->spacetype == SPACE_IMAGE) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ SpaceImage *sima = sa->spacedata.first;
+ int mval[2] = {mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+
+ if (ED_space_image_color_sample(sima, ar, mval, r_col)) {
+ return;
+ }
+ }
+ }
+ else if (sa->spacetype == SPACE_NODE) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ SpaceNode *snode = sa->spacedata.first;
+ int mval[2] = {mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+
+ if (ED_space_node_color_sample(snode, ar, mval, r_col)) {
+ return;
+ }
+ }
+ }
+ else if (sa->spacetype == SPACE_CLIP) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ SpaceClip *sc = sa->spacedata.first;
+ int mval[2] = {mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+
+ if (ED_space_clip_color_sample(sc, ar, mval, r_col)) {
+ return;
+ }
+ }
+ }
+ }
+
+ /* fallback to simple opengl picker */
+ glReadBuffer(GL_FRONT);
+ glReadPixels(mx, my, 1, 1, GL_RGB, GL_FLOAT, r_col);
+ glReadBuffer(GL_BACK);
+
+ IMB_colormanagement_display_to_scene_linear_v3(r_col, display);
+}
+
+/* sets the sample color RGB, maintaining A */
+static void eyedropper_color_set(bContext *C, Eyedropper *eye, const float col[3])
+{
+ float col_conv[4];
+
+ /* to maintain alpha */
+ RNA_property_float_get_array(&eye->ptr, eye->prop, col_conv);
+
+ /* convert from linear rgb space to display space */
+ if (eye->display) {
+ copy_v3_v3(col_conv, col);
+ IMB_colormanagement_scene_linear_to_display_v3(col_conv, eye->display);
+ }
+ else {
+ copy_v3_v3(col_conv, col);
+ }
+
+ RNA_property_float_set_array(&eye->ptr, eye->prop, col_conv);
+
+ RNA_property_update(C, &eye->ptr, eye->prop);
+}
+
+/* set sample from accumulated values */
+static void eyedropper_color_set_accum(bContext *C, Eyedropper *eye)
+{
+ float col[3];
+ mul_v3_v3fl(col, eye->accum_col, 1.0f / (float)eye->accum_tot);
+ eyedropper_color_set(C, eye, col);
+}
+
+/* single point sample & set */
+static void eyedropper_color_sample(bContext *C, Eyedropper *eye, int mx, int my)
+{
+ float col[3];
+ eyedropper_color_sample_fl(C, mx, my, col);
+ eyedropper_color_set(C, eye, col);
+}
+
+static void eyedropper_color_sample_accum(bContext *C, Eyedropper *eye, int mx, int my)
+{
+ float col[3];
+ eyedropper_color_sample_fl(C, mx, my, col);
+ /* delay linear conversion */
+ add_v3_v3(eye->accum_col, col);
+ 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;
+
+ /* 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);
+ }
+ else {
+ eyedropper_color_set_accum(C, eye);
+ }
+ eyedropper_exit(C, op);
+ return OPERATOR_FINISHED;
+ 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 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;
+ }
+ }
+ 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;
+}
+
+/* Modal Operator init */
+static int eyedropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* init */
+ if (eyedropper_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 {
+ eyedropper_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+/* Repeat operator */
+static int eyedropper_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (eyedropper_init(C, op)) {
+
+ /* do something */
+
+ /* cleanup */
+ eyedropper_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int eyedropper_poll(bContext *C)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index_dummy;
+ uiBut *but;
+
+ /* Only color buttons */
+ if ((CTX_wm_window(C) != NULL) &&
+ (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
+ (but->type == UI_BTYPE_COLOR))
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+void UI_OT_eyedropper_color(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper";
+ ot->idname = "UI_OT_eyedropper_color";
+ ot->description = "Sample a color from the Blender Window to store in a property";
+
+ /* api callbacks */
+ ot->invoke = eyedropper_invoke;
+ ot->modal = eyedropper_modal;
+ ot->cancel = eyedropper_cancel;
+ ot->exec = eyedropper_exec;
+ ot->poll = eyedropper_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+
+ /* properties */
+}
diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c
new file mode 100644
index 00000000000..b13d552dbeb
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_colorband.c
@@ -0,0 +1,337 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_eyedropper_colorband.c
+ * \ingroup edinterface
+ *
+ * Eyedropper (Color Band).
+ *
+ * Operates by either:
+ * - Dragging a straight line, sampling pixels formed by the line to extract a gradient.
+ * - Clicking on points, adding each color to the end of the color-band.
+ *
+ * Defines:
+ * - #UI_OT_eyedropper_colorband
+ * - #UI_OT_eyedropper_colorband_point
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_screen_types.h"
+
+#include "BLI_bitmap_draw_2d.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_context.h"
+#include "BKE_colorband.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "interface_intern.h"
+
+#include "interface_eyedropper_intern.h"
+
+typedef struct Colorband_RNAUpdateCb {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+} Colorband_RNAUpdateCb;
+
+typedef struct EyedropperColorband {
+ int last_x, last_y;
+ /* Alpha is currently fixed at 1.0, may support in future. */
+ float (*color_buffer)[4];
+ int color_buffer_alloc;
+ int color_buffer_len;
+ bool sample_start;
+ ColorBand init_color_band;
+ ColorBand *color_band;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+} EyedropperColorband;
+
+/* For user-data only. */
+struct EyedropperColorband_Context {
+ bContext *context;
+ EyedropperColorband *eye;
+};
+
+static bool eyedropper_colorband_init(bContext *C, wmOperator *op)
+{
+ ColorBand *band = NULL;
+ EyedropperColorband *eye;
+
+ uiBut *but = UI_context_active_but_get(C);
+
+ if (but == NULL) {
+ /* pass */
+ }
+ else if (but->type == UI_BTYPE_COLORBAND) {
+ /* When invoked with a hotkey, we can find the band in 'but->poin'. */
+ band = (ColorBand *)but->poin;
+ }
+ else {
+ /* When invoked from a button it's in custom_data field. */
+ band = (ColorBand *)but->custom_data;
+ }
+
+ if (!band)
+ return false;
+
+ op->customdata = eye = MEM_callocN(sizeof(EyedropperColorband), __func__);
+ eye->color_buffer_alloc = 16;
+ eye->color_buffer = MEM_mallocN(sizeof(*eye->color_buffer) * eye->color_buffer_alloc, __func__);
+ eye->color_buffer_len = 0;
+ eye->color_band = band;
+ eye->init_color_band = *eye->color_band;
+ eye->ptr = ((Colorband_RNAUpdateCb *)but->func_argN)->ptr;
+ eye->prop = ((Colorband_RNAUpdateCb *)but->func_argN)->prop;
+
+ return true;
+}
+
+static void eyedropper_colorband_sample_point(bContext *C, EyedropperColorband *eye, int mx, int my)
+{
+ if (eye->last_x != mx || eye->last_y != my) {
+ float col[4];
+ col[3] = 1.0f; /* TODO: sample alpha */
+ eyedropper_color_sample_fl(C, mx, my, col);
+ if (eye->color_buffer_len + 1 == eye->color_buffer_alloc) {
+ eye->color_buffer_alloc *= 2;
+ eye->color_buffer = MEM_reallocN(eye->color_buffer, sizeof(*eye->color_buffer) * eye->color_buffer_alloc);
+ }
+ copy_v4_v4(eye->color_buffer[eye->color_buffer_len], col);
+ eye->color_buffer_len += 1;
+ eye->last_x = mx;
+ eye->last_y = my;
+ }
+}
+
+static bool eyedropper_colorband_sample_callback(int mx, int my, void *userdata)
+{
+ struct EyedropperColorband_Context *data = userdata;
+ bContext *C = data->context;
+ EyedropperColorband *eye = data->eye;
+ eyedropper_colorband_sample_point(C, eye, mx, my);
+ return true;
+}
+
+static void eyedropper_colorband_sample_segment(bContext *C, EyedropperColorband *eye, int mx, int my)
+{
+ /* Since the mouse tends to move rather rapidly we use #BLI_bitmap_draw_2d_line_v2v2i
+ * to interpolate between the reported coordinates */
+ struct EyedropperColorband_Context userdata = {C, eye};
+ int p1[2] = {eye->last_x, eye->last_y};
+ int p2[2] = {mx, my};
+ BLI_bitmap_draw_2d_line_v2v2i(p1, p2, eyedropper_colorband_sample_callback, &userdata);
+}
+
+static void eyedropper_colorband_exit(bContext *C, wmOperator *op)
+{
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ if (op->customdata) {
+ EyedropperColorband *eye = op->customdata;
+ MEM_freeN(eye->color_buffer);
+ MEM_freeN(eye);
+ op->customdata = NULL;
+ }
+}
+
+static void eyedropper_colorband_apply(bContext *C, wmOperator *op)
+{
+ EyedropperColorband *eye = op->customdata;
+ /* Always filter, avoids noise in resulting color-band. */
+ bool filter_samples = true;
+ BKE_colorband_init_from_table_rgba(eye->color_band, eye->color_buffer, eye->color_buffer_len, filter_samples);
+ RNA_property_update(C, &eye->ptr, eye->prop);
+}
+
+static void eyedropper_colorband_cancel(bContext *C, wmOperator *op)
+{
+ EyedropperColorband *eye = op->customdata;
+ *eye->color_band = eye->init_color_band;
+ RNA_property_update(C, &eye->ptr, eye->prop);
+ eyedropper_colorband_exit(C, op);
+}
+
+/* main modal status check */
+static int eyedropper_colorband_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ EyedropperColorband *eye = op->customdata;
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_CANCEL:
+ eyedropper_colorband_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_SAMPLE_CONFIRM:
+ eyedropper_colorband_sample_segment(C, eye, event->x, event->y);
+ eyedropper_colorband_apply(C, op);
+ eyedropper_colorband_exit(C, op);
+ return OPERATOR_FINISHED;
+ case EYE_MODAL_SAMPLE_BEGIN:
+ /* enable accum and make first sample */
+ eye->sample_start = true;
+ eyedropper_colorband_sample_point(C, eye, event->x, event->y);
+ eyedropper_colorband_apply(C, op);
+ eye->last_x = event->x;
+ eye->last_y = event->y;
+ break;
+ case EYE_MODAL_SAMPLE_RESET:
+ break;
+ }
+ }
+ else if (event->type == MOUSEMOVE) {
+ if (eye->sample_start) {
+ eyedropper_colorband_sample_segment(C, eye, event->x, event->y);
+ eyedropper_colorband_apply(C, op);
+ }
+ }
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int eyedropper_colorband_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ EyedropperColorband *eye = op->customdata;
+ /* handle modal keymap */
+ if (event->type == EVT_MODAL_MAP) {
+ switch (event->val) {
+ case EYE_MODAL_POINT_CANCEL:
+ eyedropper_colorband_cancel(C, op);
+ return OPERATOR_CANCELLED;
+ case EYE_MODAL_POINT_CONFIRM:
+ eyedropper_colorband_apply(C, op);
+ eyedropper_colorband_exit(C, op);
+ return OPERATOR_FINISHED;
+ case EYE_MODAL_POINT_REMOVE_LAST:
+ if (eye->color_buffer_len > 0) {
+ eye->color_buffer_len -= 1;
+ eyedropper_colorband_apply(C, op);
+ }
+ break;
+ case EYE_MODAL_POINT_SAMPLE:
+ eyedropper_colorband_sample_point(C, eye, event->x, event->y);
+ eyedropper_colorband_apply(C, op);
+ if (eye->color_buffer_len == MAXCOLORBAND ) {
+ eyedropper_colorband_exit(C, op);
+ return OPERATOR_FINISHED;
+ }
+ break;
+ case EYE_MODAL_SAMPLE_RESET:
+ *eye->color_band = eye->init_color_band;
+ RNA_property_update(C, &eye->ptr, eye->prop);
+ eye->color_buffer_len = 0;
+ break;
+ }
+ }
+ return OPERATOR_RUNNING_MODAL;
+}
+
+
+/* Modal Operator init */
+static int eyedropper_colorband_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* init */
+ if (eyedropper_colorband_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 {
+ eyedropper_colorband_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+/* Repeat operator */
+static int eyedropper_colorband_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (eyedropper_colorband_init(C, op)) {
+
+ /* do something */
+
+ /* cleanup */
+ eyedropper_colorband_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int eyedropper_colorband_poll(bContext *C)
+{
+ uiBut *but = UI_context_active_but_get(C);
+ return (but && but->type == UI_BTYPE_COLORBAND);
+}
+
+
+void UI_OT_eyedropper_colorband(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper colorband";
+ ot->idname = "UI_OT_eyedropper_colorband";
+ ot->description = "Sample a color band";
+
+ /* api callbacks */
+ ot->invoke = eyedropper_colorband_invoke;
+ ot->modal = eyedropper_colorband_modal;
+ ot->cancel = eyedropper_colorband_cancel;
+ ot->exec = eyedropper_colorband_exec;
+ ot->poll = eyedropper_colorband_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+
+ /* properties */
+}
+
+void UI_OT_eyedropper_colorband_point(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper colorband (points)";
+ ot->idname = "UI_OT_eyedropper_colorband_point";
+ ot->description = "Pointsample a color band";
+
+ /* api callbacks */
+ ot->invoke = eyedropper_colorband_invoke;
+ ot->modal = eyedropper_colorband_point_modal;
+ ot->cancel = eyedropper_colorband_cancel;
+ ot->exec = eyedropper_colorband_exec;
+ ot->poll = eyedropper_colorband_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+
+ /* properties */
+}
diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c
new file mode 100644
index 00000000000..f814048c0c0
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_datablock.c
@@ -0,0 +1,351 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_eyedropper_datablock.c
+ * \ingroup edinterface
+ *
+ * Eyedropper (ID data-blocks)
+ *
+ * Defines:
+ * - #UI_OT_eyedropper_id
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_string.h"
+#include "BLI_math_vector.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_context.h"
+#include "BKE_screen.h"
+#include "BKE_report.h"
+#include "BKE_idcode.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_space_api.h"
+#include "ED_screen.h"
+#include "ED_view3d.h"
+
+#include "interface_intern.h"
+#include "interface_eyedropper_intern.h"
+
+/**
+ * \note #DataDropper is only internal name to avoid confusion with other kinds of eye-droppers.
+ */
+typedef struct DataDropper {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ short idcode;
+ const char *idcode_name;
+
+ ID *init_id; /* for resetting on cancel */
+
+ ARegionType *art;
+ void *draw_handle_pixel;
+ char name[200];
+} DataDropper;
+
+
+static void datadropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
+{
+ DataDropper *ddr = arg;
+ eyedropper_draw_cursor_text(C, ar, ddr->name);
+}
+
+
+static int datadropper_init(bContext *C, wmOperator *op)
+{
+ DataDropper *ddr;
+ int index_dummy;
+ StructRNA *type;
+
+ SpaceType *st;
+ ARegionType *art;
+
+ st = BKE_spacetype_from_id(SPACE_VIEW3D);
+ art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW);
+
+ op->customdata = ddr = MEM_callocN(sizeof(DataDropper), "DataDropper");
+
+ UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
+
+ if ((ddr->ptr.data == NULL) ||
+ (ddr->prop == NULL) ||
+ (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
+ (RNA_property_type(ddr->prop) != PROP_POINTER))
+ {
+ return false;
+ }
+
+ ddr->art = art;
+ ddr->draw_handle_pixel = ED_region_draw_cb_activate(art, datadropper_draw_cb, ddr, REGION_DRAW_POST_PIXEL);
+
+ type = RNA_property_pointer_type(&ddr->ptr, ddr->prop);
+ ddr->idcode = RNA_type_to_ID_code(type);
+ BLI_assert(ddr->idcode != 0);
+ /* 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;
+}
+
+static void datadropper_exit(bContext *C, wmOperator *op)
+{
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ if (op->customdata) {
+ DataDropper *ddr = (DataDropper *)op->customdata;
+
+ if (ddr->art) {
+ ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
+ }
+
+ MEM_freeN(op->customdata);
+
+ op->customdata = NULL;
+ }
+
+ WM_event_add_mousemove(C);
+}
+
+/* *** datadropper id helper functions *** */
+/**
+ * \brief get the ID from the screen.
+ *
+ */
+static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
+{
+ /* we could use some clever */
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, -1, mx, my);
+
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *ar_prev = CTX_wm_region(C);
+
+ ddr->name[0] = '\0';
+
+ if (sa) {
+ if (sa->spacetype == SPACE_VIEW3D) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ const int mval[2] = {
+ mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+ Base *base;
+
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
+
+ /* grr, always draw else we leave stale text */
+ ED_region_tag_redraw(ar);
+
+ base = ED_view3d_give_base_under_cursor(C, mval);
+ if (base) {
+ Object *ob = base->object;
+ ID *id = NULL;
+ if (ddr->idcode == ID_OB) {
+ id = (ID *)ob;
+ }
+ else if (ob->data) {
+ if (GS(((ID *)ob->data)->name) == ddr->idcode) {
+ id = (ID *)ob->data;
+ }
+ else {
+ BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s",
+ ddr->idcode_name);
+ }
+ }
+
+ if (id) {
+ BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s",
+ ddr->idcode_name, id->name + 2);
+ *r_id = id;
+ }
+ }
+ }
+ }
+ }
+
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, ar_prev);
+}
+
+/* sets the ID, returns success */
+static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id)
+{
+ PointerRNA ptr_value;
+
+ RNA_id_pointer_create(id, &ptr_value);
+
+ RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value);
+
+ RNA_property_update(C, &ddr->ptr, ddr->prop);
+
+ ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
+
+ return (ptr_value.id.data == id);
+}
+
+/* single point sample & set */
+static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my)
+{
+ ID *id = NULL;
+
+ datadropper_id_sample_pt(C, ddr, mx, my, &id);
+ 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;
+
+ /* 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);
+ datadropper_exit(C, op);
+
+ if (success) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "Failed to set value");
+ return OPERATOR_CANCELLED;
+ }
+ }
+ }
+ }
+ else if (event->type == MOUSEMOVE) {
+ ID *id = NULL;
+ datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Modal Operator init */
+static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* init */
+ if (datadropper_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 {
+ datadropper_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+/* Repeat operator */
+static int datadropper_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (datadropper_init(C, op)) {
+ /* cleanup */
+ datadropper_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int datadropper_poll(bContext *C)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index_dummy;
+ uiBut *but;
+
+ /* data dropper only supports object data */
+ if ((CTX_wm_window(C) != NULL) &&
+ (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
+ (but->type == UI_BTYPE_SEARCH_MENU) &&
+ (but->flag & UI_BUT_VALUE_CLEAR))
+ {
+ if (prop && RNA_property_type(prop) == PROP_POINTER) {
+ StructRNA *type = RNA_property_pointer_type(&ptr, prop);
+ const short idcode = RNA_type_to_ID_code(type);
+ if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void UI_OT_eyedropper_id(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper Data-Block";
+ ot->idname = "UI_OT_eyedropper_id";
+ ot->description = "Sample a data-block from the 3D View to store in a property";
+
+ /* api callbacks */
+ ot->invoke = datadropper_invoke;
+ ot->modal = datadropper_modal;
+ ot->cancel = datadropper_cancel;
+ ot->exec = datadropper_exec;
+ ot->poll = datadropper_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+
+ /* properties */
+}
diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c
new file mode 100644
index 00000000000..6e85d091fdb
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_depth.c
@@ -0,0 +1,391 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_eyedropper_depth.c
+ * \ingroup edinterface
+ *
+ * This file defines an eyedropper for picking 3D depth value (primary use is depth-of-field).
+ *
+ * Defines:
+ * - #UI_OT_eyedropper_depth
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_object_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_string.h"
+#include "BLI_math_vector.h"
+
+#include "BKE_context.h"
+#include "BKE_screen.h"
+#include "BKE_unit.h"
+
+#include "DEG_depsgraph.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+#include "ED_view3d.h"
+
+#include "interface_intern.h"
+#include "interface_eyedropper_intern.h"
+
+/**
+ * \note #DepthDropper is only internal name to avoid confusion with other kinds of eye-droppers.
+ */
+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;
+
+ ARegionType *art;
+ void *draw_handle_pixel;
+ char name[200];
+} DepthDropper;
+
+
+static void depthdropper_draw_cb(const struct bContext *C, ARegion *ar, void *arg)
+{
+ DepthDropper *ddr = arg;
+ eyedropper_draw_cursor_text(C, ar, ddr->name);
+}
+
+
+static int depthdropper_init(bContext *C, wmOperator *op)
+{
+ DepthDropper *ddr;
+ int index_dummy;
+
+ SpaceType *st;
+ ARegionType *art;
+
+ st = BKE_spacetype_from_id(SPACE_VIEW3D);
+ art = BKE_regiontype_from_id(st, RGN_TYPE_WINDOW);
+
+ op->customdata = ddr = MEM_callocN(sizeof(DepthDropper), "DepthDropper");
+
+ UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
+
+ /* fallback to the active camera's dof */
+ if (ddr->prop == NULL) {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d && rv3d->persp == RV3D_CAMOB) {
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) {
+ RNA_id_pointer_create(v3d->camera->data, &ddr->ptr);
+ ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance");
+ }
+ }
+ }
+
+ if ((ddr->ptr.data == NULL) ||
+ (ddr->prop == NULL) ||
+ (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
+ (RNA_property_type(ddr->prop) != PROP_FLOAT))
+ {
+ return false;
+ }
+
+ 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;
+}
+
+static void depthdropper_exit(bContext *C, wmOperator *op)
+{
+ WM_cursor_modal_restore(CTX_wm_window(C));
+
+ if (op->customdata) {
+ DepthDropper *ddr = (DepthDropper *)op->customdata;
+
+ if (ddr->art) {
+ ED_region_draw_cb_exit(ddr->art, ddr->draw_handle_pixel);
+ }
+
+ MEM_freeN(op->customdata);
+
+ op->customdata = NULL;
+ }
+}
+
+/* *** depthdropper id helper functions *** */
+/**
+ * \brief get the ID from the screen.
+ *
+ */
+static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth)
+{
+ /* we could use some clever */
+ bScreen *screen = CTX_wm_screen(C);
+ ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
+ Scene *scene = CTX_data_scene(C);
+
+ UnitSettings *unit = &scene->unit;
+ const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
+
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *ar_prev = CTX_wm_region(C);
+
+ ddr->name[0] = '\0';
+
+ if (sa) {
+ if (sa->spacetype == SPACE_VIEW3D) {
+ ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
+ if (ar) {
+ struct Depsgraph *graph = CTX_data_depsgraph(C);
+ View3D *v3d = sa->spacedata.first;
+ RegionView3D *rv3d = ar->regiondata;
+ /* weak, we could pass in some reference point */
+ const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3];
+ const int mval[2] = {
+ mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+ float co[3];
+
+ EvaluationContext eval_ctx;
+ CTX_data_eval_ctx(C, &eval_ctx);
+
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
+
+ /* grr, always draw else we leave stale text */
+ ED_region_tag_redraw(ar);
+
+ view3d_operator_needs_opengl(C);
+
+ if (ED_view3d_autodist(&eval_ctx, graph, ar, v3d, mval, co, true, NULL)) {
+ const float mval_center_fl[2] = {
+ (float)ar->winx / 2,
+ (float)ar->winy / 2};
+ float co_align[3];
+
+ /* quick way to get view-center aligned point */
+ ED_view3d_win_to_3d(v3d, ar, co, mval_center_fl, co_align);
+
+ *r_depth = len_v3v3(view_co, co_align);
+
+ bUnit_AsString(ddr->name, sizeof(ddr->name),
+ (double)*r_depth,
+ 4, unit->system, B_UNIT_LENGTH, do_split, false);
+ }
+ else {
+ BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name));
+ }
+ }
+ }
+ }
+
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, ar_prev);
+}
+
+/* sets the sample depth RGB, maintaining A */
+static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float depth)
+{
+ RNA_property_float_set(&ddr->ptr, ddr->prop, depth);
+ RNA_property_update(C, &ddr->ptr, ddr->prop);
+}
+
+/* set sample from accumulated values */
+static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr)
+{
+ float depth = ddr->accum_depth;
+ if (ddr->accum_tot) {
+ depth /= (float)ddr->accum_tot;
+ }
+ depthdropper_depth_set(C, ddr, depth);
+}
+
+/* single point sample & set */
+static void depthdropper_depth_sample(bContext *C, DepthDropper *ddr, int mx, int my)
+{
+ float depth = -1.0f;
+ if (depth != -1.0f) {
+ depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
+ depthdropper_depth_set(C, ddr, depth);
+ }
+}
+
+static void depthdropper_depth_sample_accum(bContext *C, DepthDropper *ddr, int mx, int my)
+{
+ float depth = -1.0f;
+ depthdropper_depth_sample_pt(C, ddr, mx, my, &depth);
+ if (depth != -1.0f) {
+ ddr->accum_depth += depth;
+ ddr->accum_tot++;
+ }
+}
+
+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;
+
+ /* 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);
+ }
+ else {
+ depthdropper_depth_set_accum(C, ddr);
+ }
+ depthdropper_exit(C, op);
+ return OPERATOR_FINISHED;
+ 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 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;
+ }
+ }
+ 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;
+}
+
+/* Modal Operator init */
+static int depthdropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ /* init */
+ if (depthdropper_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 {
+ depthdropper_exit(C, op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+/* Repeat operator */
+static int depthdropper_exec(bContext *C, wmOperator *op)
+{
+ /* init */
+ if (depthdropper_init(C, op)) {
+ /* cleanup */
+ depthdropper_exit(C, op);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int depthdropper_poll(bContext *C)
+{
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index_dummy;
+ uiBut *but;
+
+ /* check if there's an active button taking depth value */
+ if ((CTX_wm_window(C) != NULL) &&
+ (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
+ (but->type == UI_BTYPE_NUM) &&
+ (prop != NULL))
+ {
+ if ((RNA_property_type(prop) == PROP_FLOAT) &&
+ (RNA_property_subtype(prop) & PROP_UNIT_LENGTH) &&
+ (RNA_property_array_check(prop) == false))
+ {
+ return 1;
+ }
+ }
+ else {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ if (rv3d && rv3d->persp == RV3D_CAMOB) {
+ View3D *v3d = CTX_wm_view3d(C);
+ if (v3d->camera && v3d->camera->data && !ID_IS_LINKED(v3d->camera->data)) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void UI_OT_eyedropper_depth(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Eyedropper Depth";
+ ot->idname = "UI_OT_eyedropper_depth";
+ ot->description = "Sample depth from the 3D view";
+
+ /* api callbacks */
+ ot->invoke = depthdropper_invoke;
+ ot->modal = depthdropper_modal;
+ ot->cancel = depthdropper_cancel;
+ ot->exec = depthdropper_exec;
+ ot->poll = depthdropper_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_BLOCKING | OPTYPE_INTERNAL;
+
+ /* properties */
+}
diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c
new file mode 100644
index 00000000000..50a8473135a
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_driver.c
@@ -0,0 +1,234 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * Contributor(s): Blender Foundation, Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_eyedropper_driver.c
+ * \ingroup edinterface
+ *
+ * Eyedropper (Animation Driver Targets).
+ *
+ * Defines:
+ * - #UI_OT_eyedropper_driver
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_math_vector.h"
+
+#include "BKE_context.h"
+#include "BKE_animsys.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_intern.h"
+#include "interface_eyedropper_intern.h"
+
+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");
+
+ 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))
+ {
+ 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);
+ DEG_relations_tag_update(CTX_data_main(C));
+ DEG_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");
+}
diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/interface_eyedropper_intern.h
new file mode 100644
index 00000000000..18935c6cc9f
--- /dev/null
+++ b/source/blender/editors/interface/interface_eyedropper_intern.h
@@ -0,0 +1,54 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * 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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/interface/interface_eyedropper_intern.h
+ * \ingroup edinterface
+ *
+ * Share between interface_eyedropper_*.c files.
+ */
+
+#ifndef __INTERFACE_EYEDROPPER_INTERN_H__
+#define __INTERFACE_EYEDROPPER_INTERN_H__
+
+/* interface_eyedropper.c */
+void eyedropper_draw_cursor_text(const struct bContext *C, const struct ARegion *ar, const char *name);
+uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event);
+
+/* interface_eyedropper_color.c (expose for color-band picker) */
+void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]);
+
+/* Used for most eye-dropper operators. */
+enum {
+ EYE_MODAL_CANCEL = 1,
+ EYE_MODAL_SAMPLE_CONFIRM,
+ EYE_MODAL_SAMPLE_BEGIN,
+ EYE_MODAL_SAMPLE_RESET,
+};
+
+/* Color-band point sample. */
+enum {
+ EYE_MODAL_POINT_CANCEL = 1,
+ EYE_MODAL_POINT_SAMPLE,
+ EYE_MODAL_POINT_CONFIRM,
+ EYE_MODAL_POINT_RESET,
+ EYE_MODAL_POINT_REMOVE_LAST,
+};
+
+#endif /* __INTERFACE_EYEDROPPER_INTERN_H__ */
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 53505fc39a4..9ccb47938d2 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -61,6 +61,7 @@
#include "PIL_time.h"
+#include "BKE_colorband.h"
#include "BKE_blender_undo.h"
#include "BKE_brush.h"
#include "BKE_colortools.h"
@@ -68,7 +69,6 @@
#include "BKE_idprop.h"
#include "BKE_report.h"
#include "BKE_screen.h"
-#include "BKE_texture.h"
#include "BKE_tracking.h"
#include "BKE_unit.h"
#include "BKE_paint.h"
@@ -130,7 +130,6 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve
/***************** structs and defines ****************/
-#define BUTTON_TOOLTIP_DELAY 0.500
#define BUTTON_FLASH_DELAY 0.020
#define MENU_SCROLL_INTERVAL 0.1
#define PIE_MENU_INTERVAL 0.01
@@ -297,8 +296,6 @@ typedef struct uiHandleButtonData {
ColorBand *coba;
/* tooltip */
- ARegion *tooltip;
- wmTimer *tooltiptimer;
unsigned int tooltip_force : 1;
/* auto open */
@@ -2295,7 +2292,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
char buf_copy[UI_MAX_DRAW_STR];
if (array_length == 4) {
- values[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
+ values[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
}
else {
values[3] = 0.0f;
@@ -5971,7 +5968,7 @@ static bool ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int m
data->dragcbd->pos += dx;
CLAMP(data->dragcbd->pos, 0.0f, 1.0f);
- colorband_update_sort(data->coba);
+ BKE_colorband_update_sort(data->coba);
data->dragcbd = data->coba->data + data->coba->cur; /* because qsort */
data->draglastx = mx;
@@ -6001,7 +5998,7 @@ static int ui_do_but_COLORBAND(
if (event->ctrl) {
/* insert new key on mouse location */
float pos = ((float)(mx - but->rect.xmin)) / BLI_rctf_size_x(&but->rect);
- colorband_element_add(coba, pos);
+ BKE_colorband_element_add(coba, pos);
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
else {
@@ -6022,6 +6019,7 @@ static int ui_do_but_COLORBAND(
}
data->dragcbd = coba->data + coba->cur;
+ data->dragfstart = data->dragcbd->pos;
button_activate_state(C, but, BUTTON_STATE_NUM_EDITING);
}
@@ -6038,7 +6036,15 @@ static int ui_do_but_COLORBAND(
else if (event->type == LEFTMOUSE && event->val != KM_PRESS) {
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
-
+ else if (ELEM(event->type, ESCKEY, RIGHTMOUSE)) {
+ if (event->val == KM_PRESS) {
+ data->dragcbd->pos = data->dragfstart;
+ BKE_colorband_update_sort(data->coba);
+ data->cancel = true;
+ data->escapecancel = true;
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ }
+ }
return WM_UI_HANDLER_BREAK;
}
@@ -6047,8 +6053,8 @@ static int ui_do_but_COLORBAND(
static bool ui_numedit_but_CURVE(
uiBlock *block, uiBut *but, uiHandleButtonData *data,
- int evtx, int evty,
- bool snap, const bool shift)
+ int evtx, int evty,
+ bool snap, const bool shift)
{
CurveMapping *cumap = (CurveMapping *)but->poin;
CurveMap *cuma = cumap->cm + cumap->cur;
@@ -7733,12 +7739,12 @@ static bool button_modal_state(uiHandleButtonState state)
*/
void UI_but_tooltip_refresh(bContext *C, uiBut *but)
{
- uiHandleButtonData *data;
-
- data = but->active;
- if (data && data->tooltip) {
- ui_tooltip_free(C, data->tooltip);
- data->tooltip = ui_tooltip_create(C, data->region, but);
+ uiHandleButtonData *data = but->active;
+ if (data) {
+ bScreen *sc = WM_window_get_active_screen(data->window);
+ if (sc->tool_tip && sc->tool_tip->region) {
+ WM_tooltip_refresh(C, data->window);
+ }
}
}
@@ -7749,39 +7755,38 @@ void UI_but_tooltip_timer_remove(bContext *C, uiBut *but)
data = but->active;
if (data) {
-
- if (data->tooltiptimer) {
- WM_event_remove_timer(data->wm, data->window, data->tooltiptimer);
- data->tooltiptimer = NULL;
- }
- if (data->tooltip) {
- ui_tooltip_free(C, data->tooltip);
- data->tooltip = NULL;
- }
-
if (data->autoopentimer) {
WM_event_remove_timer(data->wm, data->window, data->autoopentimer);
data->autoopentimer = NULL;
}
+
+ if (data->window) {
+ WM_tooltip_clear(C, data->window);
+ }
}
}
+static ARegion *ui_but_tooltip_init(bContext *C, ARegion *ar, bool *r_exit_on_event)
+{
+ uiBut *but = UI_region_active_but_get(ar);
+ *r_exit_on_event = false;
+ if (but) {
+ return UI_tooltip_create_from_button(C, ar, but);
+ }
+ return NULL;
+}
+
static void button_tooltip_timer_reset(bContext *C, uiBut *but)
{
wmWindowManager *wm = CTX_wm_manager(C);
- uiHandleButtonData *data;
-
- data = but->active;
+ uiHandleButtonData *data = but->active;
- if (data->tooltiptimer) {
- WM_event_remove_timer(data->wm, data->window, data->tooltiptimer);
- data->tooltiptimer = NULL;
- }
+ WM_tooltip_timer_clear(C, data->window);
if ((U.flag & USER_TOOLTIPS) || (data->tooltip_force)) {
if (!but->block->tooltipdisabled) {
if (!wm->drags.first) {
- data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_TOOLTIP_DELAY);
+ WM_tooltip_timer_init(C, data->window, data->region, ui_but_tooltip_init);
}
}
}
@@ -8141,12 +8146,10 @@ void ui_but_active_free(const bContext *C, uiBut *but)
}
/* returns the active button with an optional checking function */
-static uiBut *ui_context_button_active(const bContext *C, bool (*but_check_cb)(uiBut *))
+static uiBut *ui_context_button_active(ARegion *ar, bool (*but_check_cb)(uiBut *))
{
uiBut *but_found = NULL;
- ARegion *ar = CTX_wm_region(C);
-
while (ar) {
uiBlock *block;
uiBut *but, *activebut = NULL;
@@ -8189,12 +8192,17 @@ static bool ui_context_rna_button_active_test(uiBut *but)
}
static uiBut *ui_context_rna_button_active(const bContext *C)
{
- return ui_context_button_active(C, ui_context_rna_button_active_test);
+ return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test);
}
uiBut *UI_context_active_but_get(const struct bContext *C)
{
- return ui_context_button_active(C, NULL);
+ return ui_context_button_active(CTX_wm_region(C), NULL);
+}
+
+uiBut *UI_region_active_but_get(ARegion *ar)
+{
+ return ui_context_button_active(ar, NULL);
}
/**
@@ -8477,16 +8485,8 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
}
case TIMER:
{
- /* handle tooltip timer */
- if (event->customdata == data->tooltiptimer) {
- WM_event_remove_timer(data->wm, data->window, data->tooltiptimer);
- data->tooltiptimer = NULL;
-
- if (!data->tooltip)
- data->tooltip = ui_tooltip_create(C, data->region, but);
- }
/* handle menu auto open timer */
- else if (event->customdata == data->autoopentimer) {
+ if (event->customdata == data->autoopentimer) {
WM_event_remove_timer(data->wm, data->window, data->autoopentimer);
data->autoopentimer = NULL;
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 6f450093d30..b2f7d400254 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -595,8 +595,7 @@ struct uiPopupBlockHandle {
/* interface_region_*.c */
/* interface_region_tooltip.c */
-struct ARegion *ui_tooltip_create(struct bContext *C, struct ARegion *butregion, uiBut *but);
-void ui_tooltip_free(struct bContext *C, struct ARegion *ar);
+/* exposed as public API in UI_interface.h */
/* interface_region_color_picker.c */
void ui_rgb_to_color_picker_compat_v(const float rgb[3], float r_cp[3]);
@@ -764,9 +763,22 @@ void ui_but_anim_autokey(struct bContext *C, uiBut *but, struct Scene *scene, fl
/* interface_eyedropper.c */
struct wmKeyMap *eyedropper_modal_keymap(struct wmKeyConfig *keyconf);
+struct wmKeyMap *eyedropper_colorband_modal_keymap(struct wmKeyConfig *keyconf);
+
+/* interface_eyedropper_color.c */
void UI_OT_eyedropper_color(struct wmOperatorType *ot);
+
+/* interface_eyedropper_colorband.c */
+void UI_OT_eyedropper_colorband(struct wmOperatorType *ot);
+void UI_OT_eyedropper_colorband_point(struct wmOperatorType *ot);
+
+/* interface_eyedropper_datablock.c */
void UI_OT_eyedropper_id(struct wmOperatorType *ot);
+
+/* interface_eyedropper_depth.c */
void UI_OT_eyedropper_depth(struct wmOperatorType *ot);
+
+/* interface_eyedropper_driver.c */
void UI_OT_eyedropper_driver(struct wmOperatorType *ot);
/* interface_util.c */
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 645afc03603..27d58c3be1b 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -1746,7 +1746,7 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN
}
else if (but->type == UI_BTYPE_SEARCH_MENU) {
/* In case we fail to find proper searchprop, so other code might have already set but->type to search menu... */
- but->type = UI_BTYPE_LABEL;
+ but->flag |= UI_BUT_DISABLED;
}
}
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index bbcd10270d5..16525dfbc9e 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1466,6 +1466,8 @@ void ED_operatortypes_ui(void)
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);
+ WM_operatortype_append(UI_OT_eyedropper_colorband);
+ WM_operatortype_append(UI_OT_eyedropper_colorband_point);
WM_operatortype_append(UI_OT_eyedropper_id);
WM_operatortype_append(UI_OT_eyedropper_depth);
WM_operatortype_append(UI_OT_eyedropper_driver);
@@ -1482,6 +1484,8 @@ void ED_keymap_ui(wmKeyConfig *keyconf)
/* eyedroppers - notice they all have the same shortcut, but pass the event
* through until a suitable eyedropper for the active button is found */
WM_keymap_add_item(keymap, "UI_OT_eyedropper_color", EKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband", EKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "UI_OT_eyedropper_colorband_point", EKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "UI_OT_eyedropper_id", EKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "UI_OT_eyedropper_depth", EKEY, KM_PRESS, 0, 0);
@@ -1504,4 +1508,5 @@ void ED_keymap_ui(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "ANIM_OT_keyingset_button_remove", KKEY, KM_PRESS, KM_ALT, 0);
eyedropper_modal_keymap(keyconf);
+ eyedropper_colorband_modal_keymap(keyconf);
}
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index f71b71fce43..07fbefa42e1 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -29,6 +29,14 @@
* ToolTip Region and Construction
*/
+/* TODO(campbell):
+ * We may want to have a higher level API that initializes a timer,
+ * checks for mouse motion and clears the tool-tip afterwards.
+ * We never want multiple tool-tips at once so this could be handled on the window / window-manager level.
+ *
+ * For now it's not a priority, so leave as-is.
+ */
+
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
@@ -97,7 +105,6 @@ typedef struct uiTooltipField {
} uiTooltipField;
-#define MAX_TOOLTIP_LINES 8
typedef struct uiTooltipData {
rcti bbox;
uiTooltipField *fields;
@@ -314,8 +321,6 @@ static uiTooltipData *ui_tooltip_data_from_keymap(bContext *C, wmKeyMap *keymap)
/* create tooltip data */
uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
- BLI_assert(data->fields_len < MAX_TOOLTIP_LINES);
-
for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
wmOperatorType *ot = WM_operatortype_find(kmi->idname, true);
if (ot != NULL) {
@@ -609,8 +614,6 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
if (rna_prop.strinfo)
MEM_freeN(rna_prop.strinfo);
- BLI_assert(data->fields_len < MAX_TOOLTIP_LINES);
-
if (data->fields_len == 0) {
MEM_freeN(data);
return NULL;
@@ -620,13 +623,116 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
}
}
-/** \} */
+static uiTooltipData *ui_tooltip_data_from_manipulator(bContext *C, wmManipulator *mpr)
+{
+ uiTooltipData *data = MEM_callocN(sizeof(uiTooltipData), "uiTooltipData");
-/* -------------------------------------------------------------------- */
-/** \name ToolTip Public API
- * \{ */
+ /* TODO(campbell): a way for manipulators to have their own descriptions (low priority). */
+
+ /* Operator Actions */
+ {
+ bool use_drag = mpr->drag_part != -1 && mpr->highlight_part != mpr->drag_part;
+
+ const struct {
+ int part;
+ const char *prefix;
+ } mpop_actions[] = {
+ {
+ .part = mpr->highlight_part,
+ .prefix = use_drag ? TIP_("Click") : NULL,
+ }, {
+ .part = use_drag ? mpr->drag_part : -1,
+ .prefix = use_drag ? TIP_("Drag") : NULL,
+ },
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(mpop_actions); i++) {
+ wmManipulatorOpElem *mpop = (mpop_actions[i].part != -1) ? WM_manipulator_operator_get(mpr, mpop_actions[i].part) : NULL;
+ if (mpop != NULL) {
+ /* Description */
+ const char *info = RNA_struct_ui_description(mpop->type->srna);
+ if (!(info && info[0])) {
+ info = RNA_struct_ui_name(mpop->type->srna);
+ }
-ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
+ if (info && info[0]) {
+ char *text = NULL;
+ if (mpop_actions[i].prefix != NULL) {
+ text = BLI_sprintfN("%s: %s", mpop_actions[i].prefix, info);
+ }
+ else {
+ text = BLI_strdup(info);
+ }
+
+ if (text != NULL) {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_HEADER,
+ .color_id = UI_TIP_LC_VALUE,
+ .is_pad = true,
+ });
+ field->text = text;
+ }
+ }
+
+ /* Shortcut */
+ {
+ bool found = false;
+ IDProperty *prop = mpop->ptr.data;
+ char buf[128];
+ if (WM_key_event_operator_string(
+ C, mpop->type->idname, WM_OP_INVOKE_DEFAULT, prop, true,
+ buf, ARRAY_SIZE(buf)))
+ {
+ found = true;
+ }
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_VALUE,
+ .is_pad = true,
+ });
+ field->text = BLI_sprintfN(TIP_("Shortcut: %s"), found ? buf : "None");
+ }
+ }
+ }
+ }
+
+ /* Property Actions */
+ if (mpr->type->target_property_defs_len) {
+ wmManipulatorProperty *mpr_prop_array = WM_manipulator_target_property_array(mpr);
+ for (int i = 0; i < mpr->type->target_property_defs_len; i++) {
+ /* TODO(campbell): function callback descriptions. */
+ wmManipulatorProperty *mpr_prop = &mpr_prop_array[i];
+ if (mpr_prop->prop != NULL) {
+ const char *info = RNA_property_ui_description(mpr_prop->prop);
+ if (info && info[0]) {
+ uiTooltipField *field = text_field_add(
+ data, &(uiTooltipFormat){
+ .style = UI_TIP_STYLE_NORMAL,
+ .color_id = UI_TIP_LC_VALUE,
+ .is_pad = true,
+ });
+ field->text = BLI_strdup(info);
+ }
+ }
+ }
+ }
+
+ if (data->fields_len == 0) {
+ MEM_freeN(data);
+ return NULL;
+ }
+ else {
+ return data;
+ }
+}
+
+
+static ARegion *ui_tooltip_create_with_data(
+ bContext *C, uiTooltipData *data,
+ const float init_position[2],
+ const float aspect)
{
const float pad_px = UI_TIP_PADDING;
wmWindow *win = CTX_wm_window(C);
@@ -634,43 +740,12 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
uiStyle *style = UI_style_get();
static ARegionType type;
ARegion *ar;
-/* IDProperty *prop;*/
- /* aspect values that shrink text are likely unreadable */
- const float aspect = min_ff(1.0f, but->block->aspect);
int fonth, fontw;
- int ofsx, ofsy, h, i;
+ int h, i;
rctf rect_fl;
rcti rect_i;
int font_flag = 0;
- if (but->drawflag & UI_BUT_NO_TOOLTIP) {
- return NULL;
- }
- uiTooltipData *data = NULL;
-
- /* custom tips for pre-defined operators */
- if (but->optype) {
- if (STREQ(but->optype->idname, "WM_OT_tool_set")) {
- char keymap[64] = "";
- RNA_string_get(but->opptr, "keymap", keymap);
- if (keymap[0]) {
- ScrArea *sa = CTX_wm_area(C);
- wmKeyMap *km = WM_keymap_find_all(C, keymap, sa->spacetype, RGN_TYPE_WINDOW);
- if (km != NULL) {
- data = ui_tooltip_data_from_keymap(C, km);
- }
- }
- }
- }
- /* toolsystem exception */
-
- if (data == NULL) {
- data = ui_tooltip_data_from_button(C, but);
- }
- if (data == NULL) {
- return NULL;
- }
-
/* create area region */
ar = ui_region_temp_add(CTX_wm_screen(C));
@@ -748,31 +823,12 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
data->lineh = h;
/* compute position */
- ofsx = 0; //(but->block->panel) ? but->block->panel->ofsx : 0;
- ofsy = 0; //(but->block->panel) ? but->block->panel->ofsy : 0;
- rect_fl.xmin = BLI_rctf_cent_x(&but->rect) + ofsx - TIP_BORDER_X;
+ rect_fl.xmin = init_position[0] - TIP_BORDER_X;
rect_fl.xmax = rect_fl.xmin + fontw + pad_px;
- rect_fl.ymax = but->rect.ymin + ofsy - TIP_BORDER_Y;
+ rect_fl.ymax = init_position[1] - TIP_BORDER_Y;
rect_fl.ymin = rect_fl.ymax - fonth - TIP_BORDER_Y;
- /* since the text has beens caled already, the size of tooltips is defined now */
- /* here we try to figure out the right location */
- if (butregion) {
- float mx, my;
- float ofsx_fl = rect_fl.xmin, ofsy_fl = rect_fl.ymax;
- ui_block_to_window_fl(butregion, but->block, &ofsx_fl, &ofsy_fl);
-
-#if 1
- /* use X mouse location */
- mx = (win->eventstate->x + (TIP_BORDER_X * 2)) - BLI_rctf_cent_x(&but->rect);
-#else
- mx = ofsx_fl - rect_fl.xmin;
-#endif
- my = ofsy_fl - rect_fl.ymax;
-
- BLI_rctf_translate(&rect_fl, mx, my);
- }
BLI_rcti_rctf_copy(&rect_i, &rect_fl);
#undef TIP_BORDER_X
@@ -827,9 +883,79 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
return ar;
}
-void ui_tooltip_free(bContext *C, ARegion *ar)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name ToolTip Public API
+ * \{ */
+
+
+ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *but)
+{
+ wmWindow *win = CTX_wm_window(C);
+ /* aspect values that shrink text are likely unreadable */
+ const float aspect = min_ff(1.0f, but->block->aspect);
+ float init_position[2];
+
+ if (but->drawflag & UI_BUT_NO_TOOLTIP) {
+ return NULL;
+ }
+ uiTooltipData *data = NULL;
+
+ /* custom tips for pre-defined operators */
+ if (but->optype) {
+ if (STREQ(but->optype->idname, "WM_OT_tool_set")) {
+ char keymap[64] = "";
+ RNA_string_get(but->opptr, "keymap", keymap);
+ if (keymap[0]) {
+ ScrArea *sa = CTX_wm_area(C);
+ wmKeyMap *km = WM_keymap_find_all(C, keymap, sa->spacetype, RGN_TYPE_WINDOW);
+ if (km != NULL) {
+ data = ui_tooltip_data_from_keymap(C, km);
+ }
+ }
+ }
+ }
+ /* toolsystem exception */
+
+ if (data == NULL) {
+ data = ui_tooltip_data_from_button(C, but);
+ }
+ if (data == NULL) {
+ return NULL;
+ }
+
+ init_position[0] = BLI_rctf_cent_x(&but->rect);
+ init_position[1] = but->rect.ymin;
+
+ if (butregion) {
+ ui_block_to_window_fl(butregion, but->block, &init_position[0], &init_position[1]);
+ init_position[0] = win->eventstate->x;
+ }
+
+ return ui_tooltip_create_with_data(C, data, init_position, aspect);
+}
+
+ARegion *UI_tooltip_create_from_manipulator(bContext *C, wmManipulator *mpr)
+{
+ wmWindow *win = CTX_wm_window(C);
+ const float aspect = 1.0f;
+ float init_position[2];
+
+ uiTooltipData *data = ui_tooltip_data_from_manipulator(C, mpr);
+ if (data == NULL) {
+ return NULL;
+ }
+
+ init_position[0] = win->eventstate->x;
+ init_position[1] = win->eventstate->y;
+
+ return ui_tooltip_create_with_data(C, data, init_position, aspect);
+}
+
+void UI_tooltip_free(bContext *C, bScreen *sc, ARegion *ar)
{
- ui_region_temp_remove(C, CTX_wm_screen(C), ar);
+ ui_region_temp_remove(C, sc, ar);
}
/** \} */
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 78874076b92..ce2d3bebb97 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -53,6 +53,7 @@
#include "BLF_api.h"
#include "BLT_translation.h"
+#include "BKE_colorband.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -60,6 +61,7 @@
#include "BKE_idprop.h"
#include "BKE_layer.h"
#include "BKE_library.h"
+#include "BKE_library_override.h"
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
@@ -70,7 +72,6 @@
#include "BKE_report.h"
#include "BKE_sca.h"
#include "BKE_screen.h"
-#include "BKE_texture.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
@@ -233,6 +234,8 @@ typedef struct TemplateID {
PropertyRNA *prop;
ListBase *idlb;
+ short idcode;
+ short filter;
int prv_rows, prv_cols;
bool preview;
} TemplateID;
@@ -240,73 +243,147 @@ typedef struct TemplateID {
/* Search browse menu, assign */
static void template_ID_set_property_cb(bContext *C, void *arg_template, void *item)
{
- TemplateID *template = (TemplateID *)arg_template;
+ TemplateID *template_ui = (TemplateID *)arg_template;
/* ID */
if (item) {
PointerRNA idptr;
RNA_id_pointer_create(item, &idptr);
- RNA_property_pointer_set(&template->ptr, template->prop, idptr);
- RNA_property_update(C, &template->ptr, template->prop);
+ RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr);
+ RNA_property_update(C, &template_ui->ptr, template_ui->prop);
}
}
+static bool id_search_add(
+ const bContext *C, TemplateID *template_ui,
+ const int flag, const char *str, uiSearchItems *items,
+ ID *id)
+{
+ ID *id_from = template_ui->ptr.id.data;
+
+ if (!((flag & PROP_ID_SELF_CHECK) && id == id_from)) {
+
+ /* use filter */
+ if (RNA_property_type(template_ui->prop) == PROP_POINTER) {
+ PointerRNA ptr;
+ RNA_id_pointer_create(id, &ptr);
+ if (RNA_property_pointer_poll(&template_ui->ptr, template_ui->prop, &ptr) == 0) {
+ return true;
+ }
+ }
+
+ /* hide dot-datablocks, but only if filter does not force it visible */
+ if (U.uiflag & USER_HIDE_DOT) {
+ if ((id->name[2] == '.') && (str[0] != '.')) {
+ return true;
+ }
+ }
+
+ if (*str == '\0' || BLI_strcasestr(id->name + 2, str)) {
+ /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix
+ * followed by ID_NAME-2 characters from id->name
+ */
+ char name_ui[MAX_ID_NAME + 1];
+ BKE_id_ui_prefix(name_ui, id);
+
+ int iconid = ui_id_icon_get(C, id, template_ui->preview);
+
+ if (false == UI_search_item_add(items, name_ui, id, iconid)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
/* ID Search browse menu, do the search */
static void id_search_cb(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
{
- TemplateID *template = (TemplateID *)arg_template;
- ListBase *lb = template->idlb;
- ID *id, *id_from = template->ptr.id.data;
- int iconid;
- int flag = RNA_property_flag(template->prop);
+ TemplateID *template_ui = (TemplateID *)arg_template;
+ ListBase *lb = template_ui->idlb;
+ ID *id;
+ int flag = RNA_property_flag(template_ui->prop);
/* ID listbase */
for (id = lb->first; id; id = id->next) {
- if (!((flag & PROP_ID_SELF_CHECK) && id == id_from)) {
-
- /* use filter */
- if (RNA_property_type(template->prop) == PROP_POINTER) {
- PointerRNA ptr;
- RNA_id_pointer_create(id, &ptr);
- if (RNA_property_pointer_poll(&template->ptr, template->prop, &ptr) == 0)
- continue;
+ if (!id_search_add(C, template_ui, flag, str, items, id)) {
+ break;
+ }
+ }
+}
+
+/**
+ * Use id tags for filtering.
+ */
+static void id_search_cb_tagged(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
+{
+ TemplateID *template_ui = (TemplateID *)arg_template;
+ ListBase *lb = template_ui->idlb;
+ ID *id;
+ int flag = RNA_property_flag(template_ui->prop);
+
+ /* ID listbase */
+ for (id = lb->first; id; id = id->next) {
+ if (id->tag & LIB_TAG_DOIT) {
+ if (!id_search_add(C, template_ui, flag, str, items, id)) {
+ break;
}
+ id->tag &= ~LIB_TAG_DOIT;
+ }
+ }
+}
- /* hide dot-datablocks, but only if filter does not force it visible */
- if (U.uiflag & USER_HIDE_DOT)
- if ((id->name[2] == '.') && (str[0] != '.'))
- continue;
+/**
+ * A version of 'id_search_cb' that lists scene objects.
+ */
+static void id_search_cb_objects_from_scene(const bContext *C, void *arg_template, const char *str, uiSearchItems *items)
+{
+ TemplateID *template_ui = (TemplateID *)arg_template;
+ ListBase *lb = template_ui->idlb;
+ Scene *scene = NULL;
+ ID *id_from = template_ui->ptr.id.data;
- if (*str == '\0' || BLI_strcasestr(id->name + 2, str)) {
- /* +1 is needed because BKE_id_ui_prefix used 3 letter prefix
- * followed by ID_NAME-2 characters from id->name
- */
- char name_ui[MAX_ID_NAME + 1];
- BKE_id_ui_prefix(name_ui, id);
+ if (id_from && GS(id_from->name) == ID_SCE) {
+ scene = (Scene *)id_from;
+ }
+ else {
+ scene = CTX_data_scene(C);
+ }
- iconid = ui_id_icon_get(C, id, template->preview);
+ BKE_main_id_flag_listbase(lb, LIB_TAG_DOIT, false);
- if (false == UI_search_item_add(items, name_ui, id, iconid))
- break;
- }
- }
+ FOREACH_SCENE_OBJECT(scene, ob_iter)
+ {
+ ob_iter->id.tag |= LIB_TAG_DOIT;
}
+ FOREACH_SCENE_OBJECT_END
+ id_search_cb_tagged(C, arg_template, str, items);
}
/* ID Search browse menu, open */
static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
{
- static TemplateID template;
+ static TemplateID template_ui;
PointerRNA active_item_ptr;
+ void (*id_search_cb_p)(const bContext *, void *, const char *, uiSearchItems *) = id_search_cb;
/* arg_litem is malloced, can be freed by parent button */
- template = *((TemplateID *)arg_litem);
- active_item_ptr = RNA_property_pointer_get(&template.ptr, template.prop);
+ template_ui = *((TemplateID *)arg_litem);
+ active_item_ptr = RNA_property_pointer_get(&template_ui.ptr, template_ui.prop);
+
+ if (template_ui.filter) {
+ /* Currently only used for objects. */
+ if (template_ui.idcode == ID_OB) {
+ if (template_ui.filter == UI_TEMPLATE_ID_FILTER_AVAILABLE) {
+ id_search_cb_p = id_search_cb_objects_from_scene;
+ }
+ }
+ }
return template_common_search_menu(
- C, ar, id_search_cb, &template, template_ID_set_property_cb, active_item_ptr.data,
- template.prv_rows, template.prv_cols);
+ C, ar, id_search_cb_p, &template_ui, template_ID_set_property_cb, active_item_ptr.data,
+ template_ui.prv_rows, template_ui.prv_cols);
}
/************************ ID Template ***************************/
@@ -317,7 +394,7 @@ void UI_context_active_but_prop_get_templateID(
bContext *C,
PointerRNA *r_ptr, PropertyRNA **r_prop)
{
- TemplateID *template;
+ TemplateID *template_ui;
ARegion *ar = CTX_wm_region(C);
uiBlock *block;
uiBut *but;
@@ -333,9 +410,9 @@ void UI_context_active_but_prop_get_templateID(
/* find the button before the active one */
if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) {
if (but->func_argN) {
- template = but->func_argN;
- *r_ptr = template->ptr;
- *r_prop = template->prop;
+ template_ui = but->func_argN;
+ *r_ptr = template_ui->ptr;
+ *r_prop = template_ui->prop;
return;
}
}
@@ -346,8 +423,8 @@ void UI_context_active_but_prop_get_templateID(
static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
{
- TemplateID *template = (TemplateID *)arg_litem;
- PointerRNA idptr = RNA_property_pointer_get(&template->ptr, template->prop);
+ TemplateID *template_ui = (TemplateID *)arg_litem;
+ PointerRNA idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
ID *id = idptr.data;
int event = GET_INT_FROM_POINTER(arg_event);
@@ -362,8 +439,8 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
break;
case UI_ID_DELETE:
memset(&idptr, 0, sizeof(idptr));
- RNA_property_pointer_set(&template->ptr, template->prop, idptr);
- RNA_property_update(C, &template->ptr, template->prop);
+ RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr);
+ RNA_property_update(C, &template_ui->ptr, template_ui->prop);
if (id && CTX_wm_window(C)->eventstate->shift) {
/* only way to force-remove data (on save) */
@@ -384,20 +461,40 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
case UI_ID_LOCAL:
if (id) {
Main *bmain = CTX_data_main(C);
- if (id_make_local(bmain, id, false, false)) {
- BKE_main_id_clear_newpoins(bmain);
+ if (CTX_wm_window(C)->eventstate->shift) {
+ ID *override_id = BKE_override_static_create_from_id(bmain, id);
+ if (override_id != NULL) {
+ BKE_main_id_clear_newpoins(bmain);
- /* reassign to get get proper updates/notifiers */
- idptr = RNA_property_pointer_get(&template->ptr, template->prop);
- RNA_property_pointer_set(&template->ptr, template->prop, idptr);
- RNA_property_update(C, &template->ptr, template->prop);
+ /* Assign new pointer, takes care of updates/notifiers */
+ RNA_id_pointer_create(override_id, &idptr);
+ }
}
+ else {
+ if (id_make_local(bmain, id, false, false)) {
+ BKE_main_id_clear_newpoins(bmain);
+
+ /* reassign to get get proper updates/notifiers */
+ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
+ }
+ }
+ RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr);
+ RNA_property_update(C, &template_ui->ptr, template_ui->prop);
+ }
+ break;
+ case UI_ID_OVERRIDE:
+ if (id && id->override_static) {
+ BKE_override_static_free(&id->override_static);
+ /* reassign to get get proper updates/notifiers */
+ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
+ RNA_property_pointer_set(&template_ui->ptr, template_ui->prop, idptr);
+ RNA_property_update(C, &template_ui->ptr, template_ui->prop);
}
break;
case UI_ID_ALONE:
if (id) {
const bool do_scene_obj = (GS(id->name) == ID_OB) &&
- (template->ptr.type == &RNA_SceneObjects);
+ (template_ui->ptr.type == &RNA_SceneObjects);
/* make copy */
if (do_scene_obj) {
@@ -410,7 +507,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
else {
if (id) {
Main *bmain = CTX_data_main(C);
- id_single_user(C, id, &template->ptr, template->prop);
+ id_single_user(C, id, &template_ui->ptr, template_ui->prop);
DEG_relations_tag_update(bmain);
}
}
@@ -477,10 +574,10 @@ static const char *template_id_context(StructRNA *type)
#endif
static uiBut *template_id_def_new_but(
- uiBlock *block, const ID *id, const TemplateID *template, StructRNA *type,
+ uiBlock *block, const ID *id, const TemplateID *template_ui, StructRNA *type,
const char * const newop, const bool editable, const bool id_open, const bool use_tab_but)
{
- ID *idfrom = template->ptr.id.data;
+ ID *idfrom = template_ui->ptr.id.data;
uiBut *but;
const int w = id ? UI_UNIT_X : id_open ? UI_UNIT_X * 3 : UI_UNIT_X * 6;
const int but_type = use_tab_but ? UI_BTYPE_TAB : UI_BTYPE_BUT;
@@ -518,12 +615,12 @@ static uiBut *template_id_def_new_but(
if (newop) {
but = uiDefIconTextButO(block, but_type, newop, WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN,
(id) ? "" : CTX_IFACE_(template_id_context(type), "New"), 0, 0, w, UI_UNIT_Y, NULL);
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
}
else {
but = uiDefIconTextBut(block, but_type, 0, ICON_ZOOMIN, (id) ? "" : CTX_IFACE_(template_id_context(type), "New"),
0, 0, w, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_ADD_NEW));
}
if ((idfrom && idfrom->lib) || !editable) {
@@ -538,7 +635,7 @@ static uiBut *template_id_def_new_but(
}
static void template_ID(
- bContext *C, uiLayout *layout, TemplateID *template, StructRNA *type, short idcode, int flag,
+ bContext *C, uiLayout *layout, TemplateID *template_ui, StructRNA *type, int flag,
const char *newop, const char *openop, const char *unlinkop)
{
uiBut *but;
@@ -546,13 +643,13 @@ static void template_ID(
PointerRNA idptr;
// ListBase *lb; // UNUSED
ID *id, *idfrom;
- const bool editable = RNA_property_editable(&template->ptr, template->prop);
- const bool use_previews = template->preview = (flag & UI_ID_PREVIEWS) != 0;
+ const bool editable = RNA_property_editable(&template_ui->ptr, template_ui->prop);
+ const bool use_previews = template_ui->preview = (flag & UI_ID_PREVIEWS) != 0;
- idptr = RNA_property_pointer_get(&template->ptr, template->prop);
+ idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
id = idptr.data;
- idfrom = template->ptr.id.data;
- // lb = template->idlb;
+ idfrom = template_ui->ptr.id.data;
+ // lb = template_ui->idlb;
block = uiLayoutGetBlock(layout);
UI_block_align_begin(block);
@@ -562,8 +659,8 @@ static void template_ID(
if (flag & UI_ID_BROWSE) {
template_add_button_search_menu(
- C, layout, block, &template->ptr, template->prop,
- id_search_menu, MEM_dupallocN(template), TIP_(template_id_browse_tip(type)),
+ C, layout, block, &template_ui->ptr, template_ui->prop,
+ id_search_menu, MEM_dupallocN(template_ui), TIP_(template_id_browse_tip(type)),
use_previews, editable);
}
@@ -577,7 +674,7 @@ static void template_ID(
but = uiDefButR(
block, UI_BTYPE_TEXT, 0, name, 0, 0, TEMPLATE_SEARCH_TEXTBUT_WIDTH, TEMPLATE_SEARCH_TEXTBUT_HEIGHT,
&idptr, "name", -1, 0, 0, -1, -1, RNA_struct_ui_description(type));
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_RENAME));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_RENAME));
if (user_alert) UI_but_flag_enable(but, UI_BUT_REDALERT);
if (id->lib) {
@@ -587,13 +684,25 @@ static void template_ID(
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
else {
+ const bool disabled = (!id_make_local(CTX_data_main(C), id, true /* test */, false) ||
+ (idfrom && idfrom->lib));
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y,
- NULL, 0, 0, 0, 0, TIP_("Direct linked library data-block, click to make local"));
- if (!id_make_local(CTX_data_main(C), id, true /* test */, false) || (idfrom && idfrom->lib))
+ NULL, 0, 0, 0, 0,
+ TIP_("Direct linked library data-block, click to make local, "
+ "Shift + Click to create a static override"));
+ if (disabled) {
UI_but_flag_enable(but, UI_BUT_DISABLED);
+ }
+ else {
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_LOCAL));
+ }
}
-
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_LOCAL));
+ }
+ else if (ID_IS_STATIC_OVERRIDE(id)) {
+ but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_OVERRIDE, 0, 0, UI_UNIT_X, UI_UNIT_Y,
+ NULL, 0, 0, 0, 0,
+ TIP_("Static override of linked library data-block, click to make fully local"));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OVERRIDE));
}
if (id->us > 1) {
@@ -607,7 +716,7 @@ static void template_ID(
TIP_("Display number of users of this data (click to make a single-user copy)"));
but->flag |= UI_BUT_UNDO;
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_ALONE));
if (/* test only */
(id_copy(CTX_data_main(C), id, NULL, true) == false) ||
(idfrom && idfrom->lib) ||
@@ -627,7 +736,7 @@ static void template_ID(
}
if (flag & UI_ID_ADD_NEW) {
- template_id_def_new_but(block, id, template, type, newop, editable, flag & UI_ID_OPEN, false);
+ template_id_def_new_but(block, id, template_ui, type, newop, editable, flag & UI_ID_OPEN, false);
}
/* Due to space limit in UI - skip the "open" icon for packed data, and allow to unpack.
@@ -647,12 +756,12 @@ static void template_ID(
if (openop) {
but = uiDefIconTextButO(block, UI_BTYPE_BUT, openop, WM_OP_INVOKE_DEFAULT, ICON_FILESEL, (id) ? "" : IFACE_("Open"),
0, 0, w, UI_UNIT_Y, NULL);
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OPEN));
}
else {
but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_FILESEL, (id) ? "" : IFACE_("Open"), 0, 0, w, UI_UNIT_Y,
NULL, 0, 0, 0, 0, NULL);
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_OPEN));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_OPEN));
}
if ((idfrom && idfrom->lib) || !editable)
@@ -668,16 +777,16 @@ static void template_ID(
if (unlinkop) {
but = uiDefIconButO(block, UI_BTYPE_BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
/* so we can access the template from operators, font unlinking needs this */
- UI_but_funcN_set(but, NULL, MEM_dupallocN(template), NULL);
+ UI_but_funcN_set(but, NULL, MEM_dupallocN(template_ui), NULL);
}
else {
- if ((RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) {
+ if ((RNA_property_flag(template_ui->prop) & PROP_NEVER_UNLINK) == 0) {
but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
TIP_("Unlink data-block "
"(Shift + Click to set users to zero, data will then not be saved)"));
- UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
+ UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template_ui), SET_INT_IN_POINTER(UI_ID_DELETE));
- if (RNA_property_flag(template->prop) & PROP_NEVER_NULL) {
+ if (RNA_property_flag(template_ui->prop) & PROP_NEVER_NULL) {
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
}
@@ -690,9 +799,9 @@ static void template_ID(
}
}
- if (idcode == ID_TE)
- uiTemplateTextureShow(layout, C, &template->ptr, template->prop);
-
+ if (template_ui->idcode == ID_TE) {
+ uiTemplateTextureShow(layout, C, &template_ui->ptr, template_ui->prop);
+ }
UI_block_align_end(block);
}
@@ -746,9 +855,9 @@ static void ui_template_id(
uiLayout *layout, bContext *C,
PointerRNA *ptr, const char *propname,
const char *newop, const char *openop, const char *unlinkop,
- int flag, int prv_rows, int prv_cols, bool use_tabs)
+ int flag, int prv_rows, int prv_cols, int filter, bool use_tabs)
{
- TemplateID *template;
+ TemplateID *template_ui;
PropertyRNA *prop;
StructRNA *type;
short idcode;
@@ -760,11 +869,18 @@ static void ui_template_id(
return;
}
- template = MEM_callocN(sizeof(TemplateID), "TemplateID");
- template->ptr = *ptr;
- template->prop = prop;
- template->prv_rows = prv_rows;
- template->prv_cols = prv_cols;
+ template_ui = MEM_callocN(sizeof(TemplateID), "TemplateID");
+ template_ui->ptr = *ptr;
+ template_ui->prop = prop;
+ template_ui->prv_rows = prv_rows;
+ template_ui->prv_cols = prv_cols;
+
+ if ((flag & UI_ID_PIN) == 0) {
+ template_ui->filter = filter;
+ }
+ else {
+ template_ui->filter = 0;
+ }
if (newop)
flag |= UI_ID_ADD_NEW;
@@ -773,56 +889,57 @@ static void ui_template_id(
type = RNA_property_pointer_type(ptr, prop);
idcode = RNA_type_to_ID_code(type);
- template->idlb = which_libbase(CTX_data_main(C), idcode);
-
+ template_ui->idcode = idcode;
+ template_ui->idlb = which_libbase(CTX_data_main(C), idcode);
+
/* create UI elements for this template
* - template_ID makes a copy of the template data and assigns it to the relevant buttons
*/
- if (template->idlb) {
+ if (template_ui->idlb) {
if (use_tabs) {
uiLayoutRow(layout, false);
- template_ID_tabs(C, layout, template, type, flag, newop, openop, unlinkop);
+ template_ID_tabs(C, layout, template_ui, type, flag, newop, openop, unlinkop);
}
else {
uiLayoutRow(layout, true);
- template_ID(C, layout, template, type, idcode, flag, newop, openop, unlinkop);
+ template_ID(C, layout, template_ui, type, flag, newop, openop, unlinkop);
}
}
- MEM_freeN(template);
+ MEM_freeN(template_ui);
}
void uiTemplateID(
uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop)
+ const char *openop, const char *unlinkop, int filter)
{
ui_template_id(
layout, C, ptr, propname,
newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE,
- 0, 0, false);
+ 0, 0, filter, false);
}
void uiTemplateIDBrowse(
uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop)
+ const char *openop, const char *unlinkop, int filter)
{
ui_template_id(
layout, C, ptr, propname,
newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME,
- 0, 0, false);
+ 0, 0, filter, false);
}
void uiTemplateIDPreview(
uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, const char *newop,
- const char *openop, const char *unlinkop, int rows, int cols)
+ const char *openop, const char *unlinkop, int rows, int cols, int filter)
{
ui_template_id(
layout, C, ptr, propname,
newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE | UI_ID_PREVIEWS,
- rows, cols, false);
+ rows, cols, filter, false);
}
/**
@@ -831,13 +948,14 @@ void uiTemplateIDPreview(
void uiTemplateIDTabs(
uiLayout *layout, bContext *C,
PointerRNA *ptr, const char *propname,
- const char *newop, const char *openop, const char *unlinkop)
+ const char *newop, const char *openop, const char *unlinkop,
+ int filter)
{
ui_template_id(
layout, C, ptr, propname,
newop, openop, unlinkop,
UI_ID_BROWSE | UI_ID_RENAME | UI_ID_DELETE,
- 0, 0, true);
+ 0, 0, filter, true);
}
/************************ ID Chooser Template ***************************/
@@ -1868,7 +1986,7 @@ static void colorband_add_cb(bContext *C, void *cb_v, void *coba_v)
else pos = (coba->data[coba->cur + 1].pos + coba->data[coba->cur].pos) * 0.5f;
}
- if (colorband_element_add(coba, pos)) {
+ if (BKE_colorband_element_add(coba, pos)) {
rna_update_cb(C, cb_v, NULL);
ED_undo_push(C, "Add colorband");
}
@@ -1878,7 +1996,7 @@ static void colorband_del_cb(bContext *C, void *cb_v, void *coba_v)
{
ColorBand *coba = coba_v;
- if (colorband_element_remove(coba, coba->cur)) {
+ if (BKE_colorband_element_remove(coba, coba->cur)) {
ED_undo_push(C, "Delete colorband");
rna_update_cb(C, cb_v, NULL);
}
@@ -1914,7 +2032,7 @@ static void colorband_update_cb(bContext *UNUSED(C), void *bt_v, void *coba_v)
/* sneaky update here, we need to sort the colorband points to be in order,
* however the RNA pointer then is wrong, so we update it */
- colorband_update_sort(coba);
+ BKE_colorband_update_sort(coba);
bt->rnapoin.data = coba->data + coba->cur;
}
@@ -1949,6 +2067,11 @@ static void colorband_buttons_layout(
bt = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_ARROW_LEFTRIGHT, "", xs + 4.0f * unit, ys + UI_UNIT_Y, 2.0f * unit, UI_UNIT_Y,
NULL, 0, 0, 0, 0, TIP_("Flip the color ramp"));
UI_but_funcN_set(bt, colorband_flip_cb, MEM_dupallocN(cb), coba);
+
+ bt = uiDefIconButO(block, UI_BTYPE_BUT, "UI_OT_eyedropper_colorband", WM_OP_INVOKE_DEFAULT, ICON_EYEDROPPER, xs + 6.0f * unit, ys + UI_UNIT_Y, UI_UNIT_X, UI_UNIT_Y, NULL);
+ bt->custom_data = coba;
+ bt->func_argN = MEM_dupallocN(cb);
+
UI_block_align_end(block);
UI_block_emboss_set(block, UI_EMBOSS);
@@ -3902,6 +4025,7 @@ eAutoPropButsReturn uiTemplateOperatorPropertyButs(
uiLayout *col; /* needed to avoid alignment errors with previous buttons */
col = uiLayoutColumn(layout, false);
+ block = uiLayoutGetBlock(col);
but = uiDefIconTextBut(block, UI_BTYPE_BUT, 0, ICON_FILE_REFRESH, IFACE_("Reset"), 0, 0, UI_UNIT_X, UI_UNIT_Y,
NULL, 0.0, 0.0, 0.0, 0.0, TIP_("Reset operator defaults"));
UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL);
@@ -4493,7 +4617,7 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c
uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr);
- uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, propname, NULL, "CACHEFILE_OT_open", NULL, UI_TEMPLATE_ID_FILTER_ALL);
if (!file) {
return;
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 8c894c7852e..a9c3f973569 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -707,6 +707,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
/* backdrop non AA */
if (wtb->draw_inner) {
+ BLI_assert(wtb->totvert != 0);
if (wcol->shaded == 0) {
if (wcol->alpha_check) {
float inner_v_half[WIDGET_SIZE_MAX][2];
@@ -784,6 +785,7 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
/* for each AA step */
if (wtb->draw_outline) {
+ BLI_assert(wtb->totvert != 0);
float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
float triangle_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */
@@ -2784,6 +2786,10 @@ static void widget_numbut_draw(uiWidgetColors *wcol, rcti *rect, int state, int
if (!emboss) {
round_box_edges(&wtb, roundboxalign, rect, rad);
}
+ else {
+ wtb.draw_inner = false;
+ wtb.draw_outline = false;
+ }
/* decoration */
if (!(state & UI_STATE_TEXT_INPUT)) {
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index cd90da24951..ac5fb3e40cb 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -46,10 +46,10 @@
#include "BLI_math.h"
#include "BKE_appdir.h"
+#include "BKE_colorband.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_main.h"
-#include "BKE_texture.h"
#include "BIF_gl.h"
@@ -2011,7 +2011,7 @@ void init_userdef_do_versions(void)
rgba_char_args_set(btheme->tv3d.editmesh_active, 255, 255, 255, 128);
}
if (U.coba_weight.tot == 0)
- init_colorband(&U.coba_weight, true);
+ BKE_colorband_init(&U.coba_weight, true);
}
if (!USER_VERSION_ATLEAST(245, 3)) {
bTheme *btheme;
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index b271b0b5bc6..dc68c8b58de 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -1509,6 +1509,9 @@ static int view2d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), const w
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), v2d->smooth_timer);
v2d->smooth_timer = NULL;
+
+ /* Event handling won't know if a UI item has been moved under the pointer. */
+ WM_event_add_mousemove(C);
}
else {
/* ease in/out */