Blender  V3.3
eyedropper_datablock.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2009 Blender Foundation. All rights reserved. */
3 
13 #include "MEM_guardedalloc.h"
14 
15 #include "DNA_object_types.h"
16 #include "DNA_screen_types.h"
17 #include "DNA_space_types.h"
18 
19 #include "BLI_math_vector.h"
20 #include "BLI_string.h"
21 
22 #include "BLT_translation.h"
23 
24 #include "BKE_context.h"
25 #include "BKE_idtype.h"
26 #include "BKE_report.h"
27 #include "BKE_screen.h"
28 
29 #include "RNA_access.h"
30 
31 #include "UI_interface.h"
32 
33 #include "WM_api.h"
34 #include "WM_types.h"
35 
36 #include "ED_outliner.h"
37 #include "ED_screen.h"
38 #include "ED_space_api.h"
39 #include "ED_view3d.h"
40 
41 #include "eyedropper_intern.h"
42 #include "interface_intern.h"
43 
47 typedef struct DataDropper {
50  short idcode;
51  const char *idcode_name;
52  bool is_undo;
53 
54  ID *init_id; /* for resetting on cancel */
55 
56  ScrArea *cursor_area; /* Area under the cursor */
59  int name_pos[2];
60  char name[200];
62 
63 static void datadropper_draw_cb(const struct bContext *UNUSED(C),
64  ARegion *UNUSED(region),
65  void *arg)
66 {
67  DataDropper *ddr = arg;
69 }
70 
72 {
73  int index_dummy;
74  StructRNA *type;
75 
76  SpaceType *st;
77  ARegionType *art;
78 
81 
82  DataDropper *ddr = MEM_callocN(sizeof(DataDropper), __func__);
83 
84  uiBut *but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
85 
86  if ((ddr->ptr.data == NULL) || (ddr->prop == NULL) ||
87  (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
88  (RNA_property_type(ddr->prop) != PROP_POINTER)) {
89  MEM_freeN(ddr);
90  return false;
91  }
92  op->customdata = ddr;
93 
95 
96  ddr->cursor_area = CTX_wm_area(C);
97  ddr->art = art;
100 
101  type = RNA_property_pointer_type(&ddr->ptr, ddr->prop);
103  BLI_assert(ddr->idcode != 0);
104  /* Note we can translate here (instead of on draw time),
105  * because this struct has very short lifetime. */
107 
108  const PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
109  ddr->init_id = ptr.owner_id;
110 
111  return true;
112 }
113 
115 {
116  wmWindow *win = CTX_wm_window(C);
117 
119 
120  if (op->customdata) {
121  DataDropper *ddr = (DataDropper *)op->customdata;
122 
123  if (ddr->art) {
125  }
126 
127  MEM_freeN(op->customdata);
128 
129  op->customdata = NULL;
130  }
131 
133 }
134 
135 /* *** datadropper id helper functions *** */
140  bContext *C, wmWindow *win, ScrArea *area, DataDropper *ddr, const int m_xy[2], ID **r_id)
141 {
142  wmWindow *win_prev = CTX_wm_window(C);
143  ScrArea *area_prev = CTX_wm_area(C);
144  ARegion *region_prev = CTX_wm_region(C);
145 
146  ddr->name[0] = '\0';
147 
148  if (area) {
149  if (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
151  if (region) {
152  const int mval[2] = {m_xy[0] - region->winrct.xmin, m_xy[1] - region->winrct.ymin};
153  Base *base;
154 
155  CTX_wm_window_set(C, win);
157  CTX_wm_region_set(C, region);
158 
159  /* Unfortunately it's necessary to always draw else we leave stale text. */
160  ED_region_tag_redraw(region);
161 
162  if (area->spacetype == SPACE_VIEW3D) {
163  base = ED_view3d_give_base_under_cursor(C, mval);
164  }
165  else {
167  }
168 
169  if (base) {
170  Object *ob = base->object;
171  ID *id = NULL;
172  if (ddr->idcode == ID_OB) {
173  id = (ID *)ob;
174  }
175  else if (ob->data) {
176  if (GS(((ID *)ob->data)->name) == ddr->idcode) {
177  id = (ID *)ob->data;
178  }
179  else {
180  BLI_snprintf(
181  ddr->name, sizeof(ddr->name), "Incompatible, expected a %s", ddr->idcode_name);
182  }
183  }
184 
185  PointerRNA idptr;
186  RNA_id_pointer_create(id, &idptr);
187 
188  if (id && RNA_property_pointer_poll(&ddr->ptr, ddr->prop, &idptr)) {
189  BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s", ddr->idcode_name, id->name + 2);
190  *r_id = id;
191  }
192 
193  copy_v2_v2_int(ddr->name_pos, mval);
194  }
195  }
196  }
197  }
198 
199  CTX_wm_window_set(C, win_prev);
200  CTX_wm_area_set(C, area_prev);
201  CTX_wm_region_set(C, region_prev);
202 }
203 
204 /* sets the ID, returns success */
205 static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id)
206 {
207  PointerRNA ptr_value;
208 
209  RNA_id_pointer_create(id, &ptr_value);
210 
211  RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value, NULL);
212 
213  RNA_property_update(C, &ddr->ptr, ddr->prop);
214 
215  ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
216 
217  return (ptr_value.owner_id == id);
218 }
219 
220 /* single point sample & set */
221 static bool datadropper_id_sample(bContext *C, DataDropper *ddr, const int m_xy[2])
222 {
223  ID *id = NULL;
224 
225  int mval[2];
226  wmWindow *win;
227  ScrArea *area;
228  datadropper_win_area_find(C, m_xy, mval, &win, &area);
229 
230  datadropper_id_sample_pt(C, win, area, ddr, mval, &id);
231  return datadropper_id_set(C, ddr, id);
232 }
233 
235 {
236  DataDropper *ddr = op->customdata;
237  datadropper_id_set(C, ddr, ddr->init_id);
238  datadropper_exit(C, op);
239 }
240 
241 /* To switch the draw callback when region under mouse event changes */
243 {
244  if (area) {
245  /* If spacetype changed */
246  if (area->spacetype != ddr->cursor_area->spacetype) {
247  /* Remove old callback */
249 
250  /* Redraw old area */
252  ED_region_tag_redraw(region);
253 
254  /* Set draw callback in new region */
256 
257  ddr->cursor_area = area;
258  ddr->art = art;
261  }
262  }
263 }
264 
265 /* main modal status check */
266 static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
267 {
268  DataDropper *ddr = (DataDropper *)op->customdata;
269 
270  /* handle modal keymap */
271  if (event->type == EVT_MODAL_MAP) {
272  switch (event->val) {
273  case EYE_MODAL_CANCEL:
274  datadropper_cancel(C, op);
275  return OPERATOR_CANCELLED;
277  const bool is_undo = ddr->is_undo;
278  const bool success = datadropper_id_sample(C, ddr, event->xy);
279  datadropper_exit(C, op);
280  if (success) {
281  /* Could support finished & undo-skip. */
282  return is_undo ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
283  }
284  BKE_report(op->reports, RPT_WARNING, "Failed to set value");
285  return OPERATOR_CANCELLED;
286  }
287  }
288  }
289  else if (event->type == MOUSEMOVE) {
290  ID *id = NULL;
291 
292  int mval[2];
293  wmWindow *win;
294  ScrArea *area;
295  datadropper_win_area_find(C, event->xy, mval, &win, &area);
296 
297  /* Set the region for eyedropper cursor text drawing */
299 
300  datadropper_id_sample_pt(C, win, area, ddr, mval, &id);
301  }
302 
303  return OPERATOR_RUNNING_MODAL;
304 }
305 
306 /* Modal Operator init */
307 static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
308 {
309  /* init */
310  if (datadropper_init(C, op)) {
311  wmWindow *win = CTX_wm_window(C);
312  /* Workaround for de-activating the button clearing the cursor, see T76794 */
315 
316  /* add temp handler */
318 
319  return OPERATOR_RUNNING_MODAL;
320  }
321  return OPERATOR_CANCELLED;
322 }
323 
324 /* Repeat operator */
326 {
327  /* init */
328  if (datadropper_init(C, op)) {
329  /* cleanup */
330  datadropper_exit(C, op);
331 
332  return OPERATOR_FINISHED;
333  }
334  return OPERATOR_CANCELLED;
335 }
336 
338 {
339  PointerRNA ptr;
340  PropertyRNA *prop;
341  int index_dummy;
342  uiBut *but;
343 
344  /* data dropper only supports object data */
345  if ((CTX_wm_window(C) != NULL) &&
346  (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
347  (but->type == UI_BTYPE_SEARCH_MENU) && (but->flag & UI_BUT_VALUE_CLEAR)) {
348  if (prop && RNA_property_type(prop) == PROP_POINTER) {
350  const short idcode = RNA_type_to_ID_code(type);
351  if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
352  return true;
353  }
354  }
355  }
356 
357  return false;
358 }
359 
361 {
362  /* identifiers */
363  ot->name = "Eyedropper Data-Block";
364  ot->idname = "UI_OT_eyedropper_id";
365  ot->description = "Sample a data-block from the 3D View to store in a property";
366 
367  /* api callbacks */
373 
374  /* flags */
376 
377  /* properties */
378 }
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
void CTX_wm_region_set(bContext *C, struct ARegion *region)
Definition: context.c:1009
void CTX_wm_window_set(bContext *C, struct wmWindow *win)
Definition: context.c:966
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
void CTX_wm_area_set(bContext *C, struct ScrArea *area)
Definition: context.c:997
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
const char * BKE_idtype_idcode_to_name(short idcode)
Definition: idtype.c:142
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
struct ARegion * BKE_area_find_region_type(const struct ScrArea *area, int type)
struct ARegion * BKE_area_find_region_xy(struct ScrArea *area, int regiontype, const int xy[2]) ATTR_NONNULL(3)
Definition: screen.c:898
struct SpaceType * BKE_spacetype_from_id(int spaceid)
Definition: screen.c:353
struct ARegionType * BKE_regiontype_from_id(const struct SpaceType *st, int regionid)
#define BLI_assert(a)
Definition: BLI_assert.h:46
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define UNUSED(x)
#define ELEM(...)
#define TIP_(msgid)
@ ID_OB
Definition: DNA_ID_enums.h:47
Object is a sort of wrapper for general info.
#define OB_DATA_SUPPORT_ID(_id_type)
@ RGN_TYPE_WINDOW
@ SPACE_OUTLINER
@ SPACE_VIEW3D
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
struct Base * ED_outliner_give_base_under_cursor(struct bContext *C, const int mval[2])
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
void * ED_region_draw_cb_activate(struct ARegionType *art, void(*draw)(const struct bContext *, struct ARegion *, void *), void *customdata, int type)
Definition: spacetypes.c:226
#define REGION_DRAW_POST_PIXEL
Definition: ED_space_api.h:63
bool ED_region_draw_cb_exit(struct ARegionType *art, void *handle)
Definition: spacetypes.c:241
struct Base * ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2])
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
short RNA_type_to_ID_code(const StructRNA *type)
@ PROP_POINTER
Definition: RNA_types.h:64
#define C
Definition: RandGen.cpp:25
@ UI_BUT_UNDO
Definition: UI_interface.h:205
@ UI_BUT_VALUE_CLEAR
Definition: UI_interface.h:228
void UI_context_active_but_clear(struct bContext *C, struct wmWindow *win, struct ARegion *region)
uiBut * UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index)
@ UI_BTYPE_SEARCH_MENU
Definition: UI_interface.h:372
bool UI_but_flag_is_set(uiBut *but, int flag)
Definition: interface.cc:5868
@ OPTYPE_INTERNAL
Definition: WM_types.h:168
@ OPTYPE_BLOCKING
Definition: WM_types.h:150
@ OPTYPE_UNDO
Definition: WM_types.h:148
static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void datadropper_set_draw_callback_region(ScrArea *area, DataDropper *ddr)
static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id)
static void datadropper_exit(bContext *C, wmOperator *op)
static bool datadropper_poll(bContext *C)
void UI_OT_eyedropper_id(wmOperatorType *ot)
static void datadropper_draw_cb(const struct bContext *UNUSED(C), ARegion *UNUSED(region), void *arg)
static void datadropper_id_sample_pt(bContext *C, wmWindow *win, ScrArea *area, DataDropper *ddr, const int m_xy[2], ID **r_id)
get the ID from the 3D view or outliner.
static int datadropper_exec(bContext *C, wmOperator *op)
static int datadropper_init(bContext *C, wmOperator *op)
static bool datadropper_id_sample(bContext *C, DataDropper *ddr, const int m_xy[2])
struct DataDropper DataDropper
static void datadropper_cancel(bContext *C, wmOperator *op)
@ EYE_MODAL_CANCEL
@ EYE_MODAL_SAMPLE_CONFIRM
void datadropper_win_area_find(const struct bContext *C, const int mval[2], int r_mval[2], struct wmWindow **r_win, struct ScrArea **r_area)
void eyedropper_draw_cursor_text_region(const int xy[2], const char *name)
#define GS(x)
Definition: iris.c:225
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
static void area(int d1, int d2, int e1, int e2, float weights[2])
static const pxr::TfToken st("st", pxr::TfToken::Immortal)
bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:1966
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:112
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
Definition: rna_access.c:3532
PropertyType RNA_property_type(PropertyRNA *prop)
Definition: rna_access.c:1010
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3493
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2138
StructRNA * RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:1405
bool RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *value)
Definition: rna_access.c:1431
struct Object * object
ARegionType * art
PropertyRNA * prop
ScrArea * cursor_area
const char * idcode_name
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
void * data
void * data
Definition: RNA_types.h:38
struct ID * owner_id
Definition: RNA_types.h:36
int ymin
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
eButType type
short val
Definition: WM_types.h:680
int xy[2]
Definition: WM_types.h:682
short type
Definition: WM_types.h:678
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
void WM_cursor_modal_set(wmWindow *win, int val)
Definition: wm_cursors.c:191
void WM_cursor_modal_restore(wmWindow *win)
Definition: wm_cursors.c:200
@ WM_CURSOR_EYEDROPPER
Definition: wm_cursors.h:35
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_mousemove(wmWindow *win)
@ EVT_MODAL_MAP
@ MOUSEMOVE
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479