Blender V4.3
eyedropper_datablock.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
14#include "MEM_guardedalloc.h"
15
16#include "DNA_object_types.h"
17#include "DNA_screen_types.h"
18#include "DNA_space_types.h"
19
20#include "BLI_math_vector.h"
21#include "BLI_string.h"
22
23#include "BLT_translation.hh"
24
25#include "BKE_context.hh"
26#include "BKE_idtype.hh"
27#include "BKE_report.hh"
28#include "BKE_screen.hh"
29
30#include "RNA_access.hh"
31
32#include "UI_interface.hh"
33
34#include "WM_api.hh"
35#include "WM_types.hh"
36
37#include "ED_outliner.hh"
38#include "ED_screen.hh"
39#include "ED_space_api.hh"
40#include "ED_view3d.hh"
41
42#include "eyedropper_intern.hh"
43#include "interface_intern.hh"
44
51 short idcode;
52 const char *idcode_name;
53 bool is_undo;
54
55 ID *init_id; /* for resetting on cancel */
56
57 ScrArea *cursor_area; /* Area under the cursor */
60 int name_pos[2];
61 char name[200];
62};
63
64static void datadropper_draw_cb(const bContext * /*C*/, ARegion * /*region*/, void *arg)
65{
66 DataDropper *ddr = static_cast<DataDropper *>(arg);
68}
69
71{
72 int index_dummy;
73 StructRNA *type;
74
75 SpaceType *st;
76 ARegionType *art;
77
80
81 DataDropper *ddr = MEM_new<DataDropper>(__func__);
82
83 uiBut *but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
84
85 if ((ddr->ptr.data == nullptr) || (ddr->prop == nullptr) ||
86 (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
88 {
89 MEM_delete(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);
102 ddr->idcode = RNA_type_to_ID_code(type);
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 = static_cast<DataDropper *>(op->customdata);
122
123 if (ddr->art) {
125 }
126 op->customdata = nullptr;
127 MEM_delete(ddr);
128 }
129
131}
132
133/* *** datadropper id helper functions *** */
138 bContext *C, wmWindow *win, ScrArea *area, DataDropper *ddr, const int event_xy[2], ID **r_id)
139{
140 wmWindow *win_prev = CTX_wm_window(C);
141 ScrArea *area_prev = CTX_wm_area(C);
142 ARegion *region_prev = CTX_wm_region(C);
143
144 ddr->name[0] = '\0';
145
146 if (area) {
147 if (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) {
148 ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, event_xy);
149 if (region) {
150 const int mval[2] = {event_xy[0] - region->winrct.xmin, event_xy[1] - region->winrct.ymin};
151 Base *base;
152
153 CTX_wm_window_set(C, win);
154 CTX_wm_area_set(C, area);
155 CTX_wm_region_set(C, region);
156
157 /* Unfortunately it's necessary to always draw else we leave stale text. */
158 ED_region_tag_redraw(region);
159
160 if (area->spacetype == SPACE_VIEW3D) {
161 base = ED_view3d_give_base_under_cursor(C, mval);
162 }
163 else {
165 }
166
167 if (base) {
168 Object *ob = base->object;
169 ID *id = nullptr;
170 if (ddr->idcode == ID_OB) {
171 id = (ID *)ob;
172 }
173 else if (ob->data) {
174 if (GS(((ID *)ob->data)->name) == ddr->idcode) {
175 id = (ID *)ob->data;
176 }
177 else {
178 SNPRINTF(ddr->name, "Incompatible, expected a %s", ddr->idcode_name);
179 }
180 }
181
183
184 if (id && RNA_property_pointer_poll(&ddr->ptr, ddr->prop, &idptr)) {
185 SNPRINTF(ddr->name, "%s: %s", ddr->idcode_name, id->name + 2);
186 *r_id = id;
187 }
188
189 copy_v2_v2_int(ddr->name_pos, mval);
190 }
191 }
192 }
193 }
194
195 CTX_wm_window_set(C, win_prev);
196 CTX_wm_area_set(C, area_prev);
197 CTX_wm_region_set(C, region_prev);
198}
199
200/* sets the ID, returns success */
201static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id)
202{
203 PointerRNA ptr_value = RNA_id_pointer_create(id);
204
205 RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value, nullptr);
206
207 RNA_property_update(C, &ddr->ptr, ddr->prop);
208
209 ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
210
211 return (ptr_value.owner_id == id);
212}
213
214/* single point sample & set */
215static bool datadropper_id_sample(bContext *C, DataDropper *ddr, const int event_xy[2])
216{
217 ID *id = nullptr;
218
219 int event_xy_win[2];
220 wmWindow *win;
221 ScrArea *area;
222 eyedropper_win_area_find(C, event_xy, event_xy_win, &win, &area);
223
224 datadropper_id_sample_pt(C, win, area, ddr, event_xy_win, &id);
225 return datadropper_id_set(C, ddr, id);
226}
227
229{
230 DataDropper *ddr = static_cast<DataDropper *>(op->customdata);
231 datadropper_id_set(C, ddr, ddr->init_id);
232 datadropper_exit(C, op);
233}
234
235/* To switch the draw callback when region under mouse event changes */
237{
238 if (area) {
239 /* If spacetype changed */
240 if (area->spacetype != ddr->cursor_area->spacetype) {
241 /* Remove old callback */
243
244 /* Redraw old area */
246 ED_region_tag_redraw(region);
247
248 /* Set draw callback in new region */
250
251 ddr->cursor_area = area;
252 ddr->art = art;
255 }
256 }
257}
258
259/* main modal status check */
260static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
261{
262 DataDropper *ddr = (DataDropper *)op->customdata;
263
264 /* handle modal keymap */
265 if (event->type == EVT_MODAL_MAP) {
266 switch (event->val) {
267 case EYE_MODAL_CANCEL:
268 datadropper_cancel(C, op);
269 return OPERATOR_CANCELLED;
271 const bool is_undo = ddr->is_undo;
272 const bool success = datadropper_id_sample(C, ddr, event->xy);
273 datadropper_exit(C, op);
274 if (success) {
275 /* Could support finished & undo-skip. */
276 return is_undo ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
277 }
278 BKE_report(op->reports, RPT_WARNING, "Failed to set value");
279 return OPERATOR_CANCELLED;
280 }
281 }
282 }
283 else if (event->type == MOUSEMOVE) {
284 ID *id = nullptr;
285
286 int event_xy_win[2];
287 wmWindow *win;
288 ScrArea *area;
289 eyedropper_win_area_find(C, event->xy, event_xy_win, &win, &area);
290
291 /* Set the region for eyedropper cursor text drawing */
293
294 datadropper_id_sample_pt(C, win, area, ddr, event_xy_win, &id);
295 }
296
298}
299
300/* Modal Operator init */
301static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
302{
303 /* init */
304 if (datadropper_init(C, op)) {
305 wmWindow *win = CTX_wm_window(C);
306 /* Workaround for de-activating the button clearing the cursor, see #76794 */
309
310 /* add temp handler */
312
314 }
315 return OPERATOR_CANCELLED;
316}
317
318/* Repeat operator */
320{
321 /* init */
322 if (datadropper_init(C, op)) {
323 /* cleanup */
324 datadropper_exit(C, op);
325
326 return OPERATOR_FINISHED;
327 }
328 return OPERATOR_CANCELLED;
329}
330
332{
334 PropertyRNA *prop;
335 int index_dummy;
336 uiBut *but;
337
338 /* data dropper only supports object data */
339 if ((CTX_wm_window(C) != nullptr) &&
340 (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
341 (but->type == UI_BTYPE_SEARCH_MENU) && (but->flag & UI_BUT_VALUE_CLEAR))
342 {
343 if (prop && RNA_property_type(prop) == PROP_POINTER) {
345 const short idcode = RNA_type_to_ID_code(type);
346 if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
347 return true;
348 }
349 }
350 }
351
352 return false;
353}
354
356{
357 /* identifiers */
358 ot->name = "Eyedropper Data-Block";
359 ot->idname = "UI_OT_eyedropper_id";
360 ot->description = "Sample a data-block from the 3D View to store in a property";
361
362 /* api callbacks */
368
369 /* flags */
371
372 /* properties */
373}
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
void CTX_wm_window_set(bContext *C, wmWindow *win)
void CTX_wm_area_set(bContext *C, ScrArea *area)
void CTX_wm_region_set(bContext *C, ARegion *region)
ARegion * CTX_wm_region(const bContext *C)
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:168
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
ARegion * BKE_area_find_region_xy(const ScrArea *area, int regiontype, const int xy[2]) ATTR_NONNULL(3)
Definition screen.cc:844
SpaceType * BKE_spacetype_from_id(int spaceid)
Definition screen.cc:243
ARegionType * BKE_regiontype_from_id(const SpaceType *st, int regionid)
Definition screen.cc:253
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:815
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
#define ELEM(...)
#define TIP_(msgid)
@ ID_OB
Object is a sort of wrapper for general info.
#define OB_DATA_SUPPORT_ID(_id_type)
@ RGN_TYPE_WINDOW
@ SPACE_OUTLINER
@ SPACE_VIEW3D
@ OPERATOR_RUNNING_MODAL
Base * ED_outliner_give_base_under_cursor(bContext *C, const int mval[2])
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
void * ED_region_draw_cb_activate(ARegionType *art, void(*draw)(const bContext *, ARegion *, void *), void *customdata, int type)
bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
#define REGION_DRAW_POST_PIXEL
Base * ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
Read Guarded memory(de)allocation.
short RNA_type_to_ID_code(const StructRNA *type)
@ PROP_POINTER
Definition RNA_types.hh:70
uiBut * UI_context_active_but_prop_get(const bContext *C, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
void UI_context_active_but_clear(bContext *C, wmWindow *win, ARegion *region)
@ UI_BTYPE_SEARCH_MENU
bool UI_but_flag_is_set(uiBut *but, int flag)
@ UI_BUT_UNDO
@ UI_BUT_VALUE_CLEAR
@ OPTYPE_INTERNAL
Definition WM_types.hh:182
@ OPTYPE_BLOCKING
Definition WM_types.hh:164
@ OPTYPE_UNDO
Definition WM_types.hh:162
static int datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void datadropper_set_draw_callback_region(ScrArea *area, DataDropper *ddr)
static bool datadropper_id_sample(bContext *C, DataDropper *ddr, const int event_xy[2])
static bool datadropper_id_set(bContext *C, DataDropper *ddr, ID *id)
static void datadropper_exit(bContext *C, wmOperator *op)
static void datadropper_id_sample_pt(bContext *C, wmWindow *win, ScrArea *area, DataDropper *ddr, const int event_xy[2], ID **r_id)
get the ID from the 3D view or outliner.
static bool datadropper_poll(bContext *C)
static void datadropper_draw_cb(const bContext *, ARegion *, void *arg)
static int datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *)
void UI_OT_eyedropper_id(wmOperatorType *ot)
static int datadropper_exec(bContext *C, wmOperator *op)
static int datadropper_init(bContext *C, wmOperator *op)
static void datadropper_cancel(bContext *C, wmOperator *op)
void eyedropper_win_area_find(const bContext *C, const int event_xy[2], int r_event_xy[2], wmWindow **r_win, ScrArea **r_area)
@ EYE_MODAL_CANCEL
@ EYE_MODAL_SAMPLE_CONFIRM
void eyedropper_draw_cursor_text_region(const int xy[2], const char *name)
#define GS(x)
Definition iris.cc:202
StructRNA * RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value, ReportList *reports)
PropertyType RNA_property_type(PropertyRNA *prop)
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_pointer_poll(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *value)
bool RNA_property_editable(const PointerRNA *ptr, PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
struct Object * object
ARegionType * art
PropertyRNA * prop
const char * idcode_name
Definition DNA_ID.h:413
ID * owner_id
Definition RNA_types.hh:40
void * data
Definition RNA_types.hh:42
eButType type
short val
Definition WM_types.hh:724
int xy[2]
Definition WM_types.hh:726
short type
Definition WM_types.hh:722
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
int(* exec)(bContext *C, wmOperator *op) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1006
const char * description
Definition WM_types.hh:996
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct ReportList * reports
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_modal_restore(wmWindow *win)
@ WM_CURSOR_EYEDROPPER
Definition wm_cursors.hh: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.cc:4126
wmOperatorType * ot
Definition wm_files.cc:4125