Blender V4.5
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
13
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
50 PropertyRNA *prop = nullptr;
51 short idcode = 0;
52 const char *idcode_name = nullptr;
53 bool is_undo = false;
54
55 ID *init_id = nullptr; /* for resetting on cancel */
56
57 ScrArea *cursor_area = nullptr; /* Area under the cursor */
58 ARegionType *art = nullptr;
59 void *draw_handle_pixel = nullptr;
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 ddr->name[0] = '\0';
69}
70
72{
73 int index_dummy;
74 StructRNA *type;
75
76 SpaceType *st;
77 ARegionType *art;
78
81
82 DataDropper *ddr = MEM_new<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 == nullptr) || (ddr->prop == nullptr) ||
87 (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
89 {
90 MEM_delete(ddr);
91 return false;
92 }
93 op->customdata = ddr;
94
96
98 ddr->art = art;
101
102 type = RNA_property_pointer_type(&ddr->ptr, ddr->prop);
103 ddr->idcode = RNA_type_to_ID_code(type);
104 BLI_assert(ddr->idcode != 0);
105 /* Note we can translate here (instead of on draw time),
106 * because this struct has very short lifetime. */
108
109 const PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
110 ddr->init_id = ptr.owner_id;
111
112 return true;
113}
114
116{
117 wmWindow *win = CTX_wm_window(C);
118
120
121 if (op->customdata) {
122 DataDropper *ddr = static_cast<DataDropper *>(op->customdata);
123
124 if (ddr->art) {
126 }
127 op->customdata = nullptr;
128 MEM_delete(ddr);
129 }
130
132}
133
134/* *** datadropper id helper functions *** */
139 bContext *C, wmWindow *win, ScrArea *area, DataDropper *ddr, const int event_xy[2], ID **r_id)
140{
141 wmWindow *win_prev = CTX_wm_window(C);
142 ScrArea *area_prev = CTX_wm_area(C);
143 ARegion *region_prev = CTX_wm_region(C);
144
145 if (area) {
147 ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, event_xy);
148 if (region) {
149 const int mval[2] = {event_xy[0] - region->winrct.xmin, event_xy[1] - region->winrct.ymin};
150 Base *base;
151
152 CTX_wm_window_set(C, win);
153 CTX_wm_area_set(C, area);
154 CTX_wm_region_set(C, region);
155
156 /* Unfortunately it's necessary to always draw else we leave stale text. */
157 ED_region_tag_redraw(region);
158
159 if (area->spacetype == SPACE_VIEW3D) {
161 }
162 else {
164 }
165
166 if (base) {
167 Object *ob = base->object;
168 ID *id = nullptr;
169 if (ddr->idcode == ID_OB) {
170 id = (ID *)ob;
171 }
172 else if (ob->data) {
173 if (GS(((ID *)ob->data)->name) == ddr->idcode) {
174 id = (ID *)ob->data;
175 }
176 else {
177 SNPRINTF(ddr->name, "Incompatible, expected a %s", ddr->idcode_name);
178 }
179 }
180
182
183 if (id && RNA_property_pointer_poll(&ddr->ptr, ddr->prop, &idptr)) {
184 SNPRINTF(ddr->name, "%s: %s", ddr->idcode_name, id->name + 2);
185 *r_id = id;
186 }
187
188 copy_v2_v2_int(ddr->name_pos, mval);
189 }
190 }
191 }
192 }
193
194 CTX_wm_window_set(C, win_prev);
195 CTX_wm_area_set(C, area_prev);
196 CTX_wm_region_set(C, region_prev);
197}
198
199/* sets the ID, returns success */
201{
202 PointerRNA ptr_value = RNA_id_pointer_create(id);
203
204 RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value, nullptr);
205
206 RNA_property_update(C, &ddr->ptr, ddr->prop);
207
208 ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
209
210 return (ptr_value.owner_id == id);
211}
212
213/* single point sample & set */
214static bool datadropper_id_sample(bContext *C, DataDropper *ddr, const int event_xy[2])
215{
216 ID *id = nullptr;
217
218 int event_xy_win[2];
219 wmWindow *win;
220 ScrArea *area;
221 eyedropper_win_area_find(C, event_xy, event_xy_win, &win, &area);
222
223 datadropper_id_sample_pt(C, win, area, ddr, event_xy_win, &id);
224 return datadropper_id_set(C, ddr, id);
225}
226
228{
229 DataDropper *ddr = static_cast<DataDropper *>(op->customdata);
230 datadropper_id_set(C, ddr, ddr->init_id);
231 datadropper_exit(C, op);
232}
233
234/* To switch the draw callback when region under mouse event changes */
236{
237 if (area) {
238 /* If spacetype changed */
239 if (area != ddr->cursor_area) {
240 /* Redraw old area */
242 ED_region_tag_redraw(region);
243
244 /* Remove old callback */
246 /* Set draw callback in new region */
248
249 ddr->cursor_area = area;
250 ddr->art = art;
253 }
254 }
255}
256
257/* main modal status check */
259{
260 DataDropper *ddr = (DataDropper *)op->customdata;
261
262 /* handle modal keymap */
263 if (event->type == EVT_MODAL_MAP) {
264 switch (event->val) {
265 case EYE_MODAL_CANCEL:
267 return OPERATOR_CANCELLED;
269 const bool is_undo = ddr->is_undo;
270 const bool success = datadropper_id_sample(C, ddr, event->xy);
271 datadropper_exit(C, op);
272 if (success) {
273 /* Could support finished & undo-skip. */
274 return is_undo ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
275 }
276 BKE_report(op->reports, RPT_WARNING, "Failed to set value");
277 return OPERATOR_CANCELLED;
278 }
279 }
280 }
281 else if (event->type == MOUSEMOVE) {
282 ID *id = nullptr;
283
284 int event_xy_win[2];
285 wmWindow *win;
286 ScrArea *area;
287 eyedropper_win_area_find(C, event->xy, event_xy_win, &win, &area);
288
289 /* Set the region for eyedropper cursor text drawing */
291
292 datadropper_id_sample_pt(C, win, area, ddr, event_xy_win, &id);
293 }
294
296}
297
298/* Modal Operator init */
300{
301 /* init */
302 if (datadropper_init(C, op)) {
303 wmWindow *win = CTX_wm_window(C);
304 /* Workaround for de-activating the button clearing the cursor, see #76794 */
307
308 /* add temp handler */
310
312 }
313 return OPERATOR_CANCELLED;
314}
315
316/* Repeat operator */
318{
319 /* init */
320 if (datadropper_init(C, op)) {
321 /* cleanup */
322 datadropper_exit(C, op);
323
324 return OPERATOR_FINISHED;
325 }
326 return OPERATOR_CANCELLED;
327}
328
330{
332 PropertyRNA *prop;
333 int index_dummy;
334 uiBut *but;
335
336 /* data dropper only supports object data */
337 if ((CTX_wm_window(C) != nullptr) &&
338 (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
339 (but->type == UI_BTYPE_SEARCH_MENU) && (but->flag & UI_BUT_VALUE_CLEAR))
340 {
341 if (prop && RNA_property_type(prop) == PROP_POINTER) {
343 const short idcode = RNA_type_to_ID_code(type);
344 if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
345 return true;
346 }
347 }
348 }
349
350 return false;
351}
352
354{
355 /* identifiers */
356 ot->name = "Eyedropper Data-Block";
357 ot->idname = "UI_OT_eyedropper_id";
358 ot->description = "Sample a data-block from the 3D View to store in a property";
359
360 /* API callbacks. */
361 ot->invoke = datadropper_invoke;
362 ot->modal = datadropper_modal;
363 ot->cancel = datadropper_cancel;
364 ot->exec = datadropper_exec;
365 ot->poll = datadropper_poll;
366
367 /* flags */
369
370 /* properties */
371}
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:165
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
ARegion * BKE_area_find_region_xy(const ScrArea *area, int regiontype, const int xy[2]) ATTR_NONNULL(3)
Definition screen.cc:869
SpaceType * BKE_spacetype_from_id(int spaceid)
Definition screen.cc:251
ARegionType * BKE_regiontype_from_id(const SpaceType *st, int regionid)
Definition screen.cc:261
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:840
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
#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_CANCELLED
@ OPERATOR_FINISHED
@ 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:639
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:155
#define C
Definition RandGen.cpp:29
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
@ UI_BUT_UNDO
@ UI_BUT_VALUE_CLEAR
bool UI_but_flag_is_set(uiBut *but, int flag)
@ OPTYPE_INTERNAL
Definition WM_types.hh:202
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
@ OPTYPE_UNDO
Definition WM_types.hh:182
static wmOperatorStatus datadropper_invoke(bContext *C, wmOperator *op, const wmEvent *)
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)
void UI_OT_eyedropper_id(wmOperatorType *ot)
static wmOperatorStatus datadropper_modal(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus 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)
void eyedropper_draw_cursor_text_region(const int xy[2], const char *name)
@ EYE_MODAL_CANCEL
@ EYE_MODAL_SAMPLE_CONFIRM
#define GS(a)
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:404
char name[66]
Definition DNA_ID.h:415
ID * owner_id
Definition RNA_types.hh:51
void * data
Definition RNA_types.hh:53
struct SpaceType * type
int ymin
int xmin
eButType type
wmEventType type
Definition WM_types.hh:754
short val
Definition WM_types.hh:756
int xy[2]
Definition WM_types.hh:758
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:36
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:4226
wmOperatorType * ot
Definition wm_files.cc:4225