Blender  V2.93
interface_eyedropper_datablock.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation.
17  * All rights reserved.
18  */
19 
29 #include "MEM_guardedalloc.h"
30 
31 #include "DNA_object_types.h"
32 #include "DNA_screen_types.h"
33 #include "DNA_space_types.h"
34 
35 #include "BLI_string.h"
36 
37 #include "BLT_translation.h"
38 
39 #include "BKE_context.h"
40 #include "BKE_idtype.h"
41 #include "BKE_report.h"
42 #include "BKE_screen.h"
43 
44 #include "RNA_access.h"
45 
46 #include "UI_interface.h"
47 
48 #include "WM_api.h"
49 #include "WM_types.h"
50 
51 #include "ED_outliner.h"
52 #include "ED_screen.h"
53 #include "ED_space_api.h"
54 #include "ED_view3d.h"
55 
57 #include "interface_intern.h"
58 
62 typedef struct DataDropper {
65  short idcode;
66  const char *idcode_name;
67  bool is_undo;
68 
69  ID *init_id; /* for resetting on cancel */
70 
71  ScrArea *cursor_area; /* Area under the cursor */
74  char name[200];
76 
77 static void datadropper_draw_cb(const struct bContext *C, ARegion *region, void *arg)
78 {
79  DataDropper *ddr = arg;
81 }
82 
84 {
85  int index_dummy;
86  StructRNA *type;
87 
88  SpaceType *st;
89  ARegionType *art;
90 
93 
94  DataDropper *ddr = MEM_callocN(sizeof(DataDropper), __func__);
95 
96  uiBut *but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
97 
98  if ((ddr->ptr.data == NULL) || (ddr->prop == NULL) ||
99  (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
100  (RNA_property_type(ddr->prop) != PROP_POINTER)) {
101  MEM_freeN(ddr);
102  return false;
103  }
104  op->customdata = ddr;
105 
107 
108  ddr->cursor_area = CTX_wm_area(C);
109  ddr->art = art;
112 
113  type = RNA_property_pointer_type(&ddr->ptr, ddr->prop);
115  BLI_assert(ddr->idcode != 0);
116  /* Note we can translate here (instead of on draw time),
117  * because this struct has very short lifetime. */
119 
120  const PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
121  ddr->init_id = ptr.owner_id;
122 
123  return true;
124 }
125 
127 {
128  wmWindow *win = CTX_wm_window(C);
129 
131 
132  if (op->customdata) {
133  DataDropper *ddr = (DataDropper *)op->customdata;
134 
135  if (ddr->art) {
137  }
138 
139  MEM_freeN(op->customdata);
140 
141  op->customdata = NULL;
142  }
143 
145 }
146 
147 /* *** datadropper id helper functions *** */
151 static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
152 {
153  /* we could use some clever */
154  bScreen *screen = CTX_wm_screen(C);
155  ScrArea *area = BKE_screen_find_area_xy(screen, -1, mx, my);
156 
157  ScrArea *area_prev = CTX_wm_area(C);
158  ARegion *region_prev = CTX_wm_region(C);
159 
160  ddr->name[0] = '\0';
161 
162  if (area) {
163  if (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
165  if (region) {
166  const int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin};
167  Base *base;
168 
170  CTX_wm_region_set(C, region);
171 
172  /* grr, always draw else we leave stale text */
173  ED_region_tag_redraw(region);
174 
175  if (area->spacetype == SPACE_VIEW3D) {
176  base = ED_view3d_give_base_under_cursor(C, mval);
177  }
178  else {
180  }
181 
182  if (base) {
183  Object *ob = base->object;
184  ID *id = NULL;
185  if (ddr->idcode == ID_OB) {
186  id = (ID *)ob;
187  }
188  else if (ob->data) {
189  if (GS(((ID *)ob->data)->name) == ddr->idcode) {
190  id = (ID *)ob->data;
191  }
192  else {
193  BLI_snprintf(
194  ddr->name, sizeof(ddr->name), "Incompatible, expected a %s", ddr->idcode_name);
195  }
196  }
197 
198  PointerRNA idptr;
199  RNA_id_pointer_create(id, &idptr);
200 
201  if (id && RNA_property_pointer_poll(&ddr->ptr, ddr->prop, &idptr)) {
202  BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s", ddr->idcode_name, id->name + 2);
203  *r_id = id;
204  }
205  }
206  }
207  }
208  }
209 
210  CTX_wm_area_set(C, area_prev);
211  CTX_wm_region_set(C, region_prev);
212 }
213 
214 /* sets the ID, returns success */
215 static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id)
216 {
217  PointerRNA ptr_value;
218 
219  RNA_id_pointer_create(id, &ptr_value);
220 
221  RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value, NULL);
222 
223  RNA_property_update(C, &ddr->ptr, ddr->prop);
224 
225  ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
226 
227  return (ptr_value.owner_id == id);
228 }
229 
230 /* single point sample & set */
231 static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my)
232 {
233  ID *id = NULL;
234 
235  datadropper_id_sample_pt(C, ddr, mx, my, &id);
236  return datadropper_id_set(C, ddr, id);
237 }
238 
240 {
241  DataDropper *ddr = op->customdata;
242  datadropper_id_set(C, ddr, ddr->init_id);
243  datadropper_exit(C, op);
244 }
245 
246 /* To switch the draw callback when region under mouse event changes */
248  DataDropper *ddr,
249  const int mx,
250  const int my)
251 {
252  bScreen *screen = CTX_wm_screen(C);
253  ScrArea *area = BKE_screen_find_area_xy(screen, -1, mx, my);
254 
255  if (area) {
256  /* If spacetype changed */
257  if (area->spacetype != ddr->cursor_area->spacetype) {
258  /* Remove old callback */
260 
261  /* Redraw old area */
263  ED_region_tag_redraw(region);
264 
265  /* Set draw callback in new region */
267 
268  ddr->cursor_area = area;
269  ddr->art = art;
272  }
273  }
274 }
275 
276 /* main modal status check */
277 static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
278 {
279  DataDropper *ddr = (DataDropper *)op->customdata;
280 
281  /* handle modal keymap */
282  if (event->type == EVT_MODAL_MAP) {
283  switch (event->val) {
284  case EYE_MODAL_CANCEL:
285  datadropper_cancel(C, op);
286  return OPERATOR_CANCELLED;
288  const bool is_undo = ddr->is_undo;
289  const bool success = datadropper_id_sample(C, ddr, event->x, event->y);
290  datadropper_exit(C, op);
291  if (success) {
292  /* Could support finished & undo-skip. */
293  return is_undo ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
294  }
295  BKE_report(op->reports, RPT_WARNING, "Failed to set value");
296  return OPERATOR_CANCELLED;
297  }
298  }
299  }
300  else if (event->type == MOUSEMOVE) {
301  ID *id = NULL;
302 
303  /* Set the region for eyedropper cursor text drawing */
304  datadropper_set_draw_callback_region(C, ddr, event->x, event->y);
305 
306  datadropper_id_sample_pt(C, ddr, event->x, event->y, &id);
307  }
308 
309  return OPERATOR_RUNNING_MODAL;
310 }
311 
312 /* Modal Operator init */
313 static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
314 {
315  /* init */
316  if (datadropper_init(C, op)) {
317  wmWindow *win = CTX_wm_window(C);
318  /* Workaround for de-activating the button clearing the cursor, see T76794 */
321 
322  /* add temp handler */
324 
325  return OPERATOR_RUNNING_MODAL;
326  }
327  return OPERATOR_CANCELLED;
328 }
329 
330 /* Repeat operator */
332 {
333  /* init */
334  if (datadropper_init(C, op)) {
335  /* cleanup */
336  datadropper_exit(C, op);
337 
338  return OPERATOR_FINISHED;
339  }
340  return OPERATOR_CANCELLED;
341 }
342 
344 {
345  PointerRNA ptr;
346  PropertyRNA *prop;
347  int index_dummy;
348  uiBut *but;
349 
350  /* data dropper only supports object data */
351  if ((CTX_wm_window(C) != NULL) &&
352  (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
353  (but->type == UI_BTYPE_SEARCH_MENU) && (but->flag & UI_BUT_VALUE_CLEAR)) {
354  if (prop && RNA_property_type(prop) == PROP_POINTER) {
356  const short idcode = RNA_type_to_ID_code(type);
357  if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
358  return true;
359  }
360  }
361  }
362 
363  return false;
364 }
365 
367 {
368  /* identifiers */
369  ot->name = "Eyedropper Data-Block";
370  ot->idname = "UI_OT_eyedropper_id";
371  ot->description = "Sample a data-block from the 3D View to store in a property";
372 
373  /* api callbacks */
379 
380  /* flags */
382 
383  /* properties */
384 }
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
void CTX_wm_region_set(bContext *C, struct ARegion *region)
Definition: context.c:985
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:709
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
void CTX_wm_area_set(bContext *C, struct ScrArea *area)
Definition: context.c:973
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
const char * BKE_idtype_idcode_to_name(const short idcode)
Definition: idtype.c:168
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
struct ScrArea * BKE_screen_find_area_xy(struct bScreen *screen, const int spacetype, int x, int y)
Definition: screen.c:1018
struct ARegion * BKE_area_find_region_type(const struct ScrArea *area, int type)
struct ARegion * BKE_area_find_region_xy(struct ScrArea *area, const int regiontype, int x, int y)
Definition: screen.c:933
struct SpaceType * BKE_spacetype_from_id(int spaceid)
Definition: screen.c:382
struct ARegionType * BKE_regiontype_from_id(const struct SpaceType *st, int regionid)
#define BLI_assert(a)
Definition: BLI_assert.h:58
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:59
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:667
void * ED_region_draw_cb_activate(struct ARegionType *art, void(*draw)(const struct bContext *, struct ARegion *, void *), void *customdata, int type)
Definition: spacetypes.c:238
#define REGION_DRAW_POST_PIXEL
Definition: ED_space_api.h:67
void ED_region_draw_cb_exit(struct ARegionType *, void *)
Definition: spacetypes.c:253
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:78
#define C
Definition: RandGen.cpp:39
@ UI_BUT_UNDO
Definition: UI_interface.h:208
@ UI_BUT_VALUE_CLEAR
Definition: UI_interface.h:231
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:376
bool UI_but_flag_is_set(uiBut *but, int flag)
Definition: interface.c:6087
@ OPTYPE_INTERNAL
Definition: WM_types.h:175
@ OPTYPE_BLOCKING
Definition: WM_types.h:157
@ OPTYPE_UNDO
Definition: WM_types.h:155
void eyedropper_draw_cursor_text_region(const struct bContext *C, const ARegion *region, const char *name)
static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
static bool datadropper_id_sample(bContext *C, DataDropper *ddr, int mx, int my)
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 int datadropper_exec(bContext *C, wmOperator *op)
static void datadropper_set_draw_callback_region(bContext *C, DataDropper *ddr, const int mx, const int my)
static int datadropper_init(bContext *C, wmOperator *op)
struct DataDropper DataDropper
static void datadropper_draw_cb(const struct bContext *C, ARegion *region, void *arg)
static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int my, ID **r_id)
get the ID from the 3D view or outliner.
static void datadropper_cancel(bContext *C, wmOperator *op)
@ EYE_MODAL_SAMPLE_CONFIRM
#define GS(x)
Definition: iris.c:241
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static void area(int d1, int d2, int e1, int e2, float weights[2])
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:122
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
Definition: rna_access.c:3673
PropertyType RNA_property_type(PropertyRNA *prop)
Definition: rna_access.c:1155
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:3641
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2317
StructRNA * RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:1567
bool RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *value)
Definition: rna_access.c:1593
bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop_orig)
Definition: rna_access.c:2073
struct Object * object
Definition: DNA_ID.h:273
char name[66]
Definition: DNA_ID.h:283
void * data
void * data
Definition: RNA_types.h:52
struct ID * owner_id
Definition: RNA_types.h:50
int ymin
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
eButType type
int y
Definition: WM_types.h:581
short val
Definition: WM_types.h:579
int x
Definition: WM_types.h:581
short type
Definition: WM_types.h:577
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:760
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct ReportList * reports
void WM_cursor_modal_set(wmWindow *win, int val)
Definition: wm_cursors.c:207
void WM_cursor_modal_restore(wmWindow *win)
Definition: wm_cursors.c:216
@ WM_CURSOR_EYEDROPPER
Definition: wm_cursors.h:51
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:3157
wmOperatorType * ot
Definition: wm_files.c:3156