Blender V5.0
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_utf8.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 "WM_api.hh"
33#include "WM_types.hh"
34
35#include "ED_outliner.hh"
36#include "ED_screen.hh"
37#include "ED_space_api.hh"
38#include "ED_view3d.hh"
39
40#include "eyedropper_intern.hh"
41#include "interface_intern.hh"
42
48 PropertyRNA *prop = nullptr;
49 short idcode = 0;
50 const char *idcode_name = nullptr;
51 bool is_undo = false;
52
53 ID *init_id = nullptr; /* for resetting on cancel */
54
55 ScrArea *cursor_area = nullptr; /* Area under the cursor */
56 ARegionType *art = nullptr;
57 void *draw_handle_pixel = nullptr;
58 int name_pos[2] = {};
59 char name[200] = {};
60};
61
62static void datadropper_draw_cb(const bContext * /*C*/, ARegion * /*region*/, void *arg)
63{
64 DataDropper *ddr = static_cast<DataDropper *>(arg);
66 ddr->name[0] = '\0';
67}
68
70{
71 int index_dummy;
72 StructRNA *type;
73
74 SpaceType *st;
75 ARegionType *art;
76
79
80 DataDropper *ddr = MEM_new<DataDropper>(__func__);
81
82 uiBut *but = UI_context_active_but_prop_get(C, &ddr->ptr, &ddr->prop, &index_dummy);
83
84 if ((ddr->ptr.data == nullptr) || (ddr->prop == nullptr) ||
85 (RNA_property_editable(&ddr->ptr, ddr->prop) == false) ||
87 {
88 MEM_delete(ddr);
89 return false;
90 }
91 op->customdata = ddr;
92
94
96 ddr->art = art;
99
100 type = RNA_property_pointer_type(&ddr->ptr, ddr->prop);
101 ddr->idcode = RNA_type_to_ID_code(type);
102 BLI_assert(ddr->idcode != 0);
103 /* Note we can translate here (instead of on draw time),
104 * because this struct has very short lifetime. */
106
107 const PointerRNA ptr = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
108 ddr->init_id = ptr.owner_id;
109
110 return true;
111}
112
114{
115 wmWindow *win = CTX_wm_window(C);
116
118
119 if (op->customdata) {
120 DataDropper *ddr = static_cast<DataDropper *>(op->customdata);
121
122 if (ddr->art) {
124 }
125 op->customdata = nullptr;
126 MEM_delete(ddr);
127 }
128
130}
131
132/* *** datadropper id helper functions *** */
137 bContext *C, wmWindow *win, ScrArea *area, DataDropper *ddr, const int event_xy[2], ID **r_id)
138{
139 wmWindow *win_prev = CTX_wm_window(C);
140 ScrArea *area_prev = CTX_wm_area(C);
141 ARegion *region_prev = CTX_wm_region(C);
142
143 if (area) {
145 ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, event_xy);
146 if (region) {
147 const int mval[2] = {event_xy[0] - region->winrct.xmin, event_xy[1] - region->winrct.ymin};
148 Base *base;
149
150 CTX_wm_window_set(C, win);
151 CTX_wm_area_set(C, area);
152 CTX_wm_region_set(C, region);
153
154 /* Unfortunately it's necessary to always draw else we leave stale text. */
155 ED_region_tag_redraw(region);
156
157 if (area->spacetype == SPACE_VIEW3D) {
159 }
160 else {
162 }
163
164 if (base) {
165 Object *ob = base->object;
166 ID *id = nullptr;
167 if (ddr->idcode == ID_OB) {
168 id = (ID *)ob;
169 }
170 else if (ob->data) {
171 if (GS(((ID *)ob->data)->name) == ddr->idcode) {
172 id = (ID *)ob->data;
173 }
174 else {
175 SNPRINTF_UTF8(ddr->name, "Incompatible, expected a %s", ddr->idcode_name);
176 }
177 }
178
180
181 if (id && RNA_property_pointer_poll(&ddr->ptr, ddr->prop, &idptr)) {
182 SNPRINTF_UTF8(ddr->name, "%s: %s", ddr->idcode_name, id->name + 2);
183 *r_id = id;
184 }
185
186 copy_v2_v2_int(ddr->name_pos, mval);
187 }
188 }
189 }
190 }
191
192 CTX_wm_window_set(C, win_prev);
193 CTX_wm_area_set(C, area_prev);
194 CTX_wm_region_set(C, region_prev);
195}
196
197/* sets the ID, returns success */
199{
200 PointerRNA ptr_value = RNA_id_pointer_create(id);
201
202 RNA_property_pointer_set(&ddr->ptr, ddr->prop, ptr_value, nullptr);
203
204 RNA_property_update(C, &ddr->ptr, ddr->prop);
205
206 ptr_value = RNA_property_pointer_get(&ddr->ptr, ddr->prop);
207
208 return (ptr_value.owner_id == id);
209}
210
211/* single point sample & set */
212static bool datadropper_id_sample(bContext *C, DataDropper *ddr, const int event_xy[2])
213{
214 ID *id = nullptr;
215
216 int event_xy_win[2];
217 wmWindow *win;
218 ScrArea *area;
219 eyedropper_win_area_find(C, event_xy, event_xy_win, &win, &area);
220
221 datadropper_id_sample_pt(C, win, area, ddr, event_xy_win, &id);
222 return datadropper_id_set(C, ddr, id);
223}
224
226{
227 DataDropper *ddr = static_cast<DataDropper *>(op->customdata);
228 datadropper_id_set(C, ddr, ddr->init_id);
229 datadropper_exit(C, op);
230}
231
232/* To switch the draw callback when region under mouse event changes */
234{
235 if (area) {
236 /* If spacetype changed */
237 if (area != ddr->cursor_area) {
238 /* Redraw old area */
240 ED_region_tag_redraw(region);
241
242 /* Remove old callback */
244 /* Set draw callback in new region */
246
247 ddr->cursor_area = area;
248 ddr->art = art;
251 }
252 }
253}
254
255/* main modal status check */
257{
258 DataDropper *ddr = (DataDropper *)op->customdata;
259
260 /* handle modal keymap */
261 if (event->type == EVT_MODAL_MAP) {
262 switch (event->val) {
263 case EYE_MODAL_CANCEL:
265 return OPERATOR_CANCELLED;
267 const bool is_undo = ddr->is_undo;
268 const bool success = datadropper_id_sample(C, ddr, event->xy);
269 datadropper_exit(C, op);
270 if (success) {
271 /* Could support finished & undo-skip. */
272 return is_undo ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
273 }
274 BKE_report(op->reports, RPT_WARNING, "Failed to set value");
275 return OPERATOR_CANCELLED;
276 }
277 }
278 }
279 else if (event->type == MOUSEMOVE) {
280 ID *id = nullptr;
281
282 int event_xy_win[2];
283 wmWindow *win;
284 ScrArea *area;
285 eyedropper_win_area_find(C, event->xy, event_xy_win, &win, &area);
286
287 /* Set the region for eyedropper cursor text drawing */
289
290 datadropper_id_sample_pt(C, win, area, ddr, event_xy_win, &id);
291 }
292
294}
295
296/* Modal Operator init */
298{
299 /* init */
300 if (datadropper_init(C, op)) {
301 wmWindow *win = CTX_wm_window(C);
302 /* Workaround for de-activating the button clearing the cursor, see #76794 */
305
306 /* add temp handler */
308
310 }
311 return OPERATOR_CANCELLED;
312}
313
314/* Repeat operator */
316{
317 /* init */
318 if (datadropper_init(C, op)) {
319 /* cleanup */
320 datadropper_exit(C, op);
321
322 return OPERATOR_FINISHED;
323 }
324 return OPERATOR_CANCELLED;
325}
326
328{
330 PropertyRNA *prop;
331 int index_dummy;
332 uiBut *but;
333
334 /* data dropper only supports object data */
335 if ((CTX_wm_window(C) != nullptr) &&
336 (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) &&
337 (but->type == ButType::SearchMenu) && (but->flag & UI_BUT_VALUE_CLEAR))
338 {
339 if (prop && RNA_property_type(prop) == PROP_POINTER) {
341 const short idcode = RNA_type_to_ID_code(type);
342 if ((idcode == ID_OB) || OB_DATA_SUPPORT_ID(idcode)) {
343 return true;
344 }
345 }
346 }
347
348 return false;
349}
350
352{
353 /* identifiers */
354 ot->name = "Eyedropper Data-Block";
355 ot->idname = "UI_OT_eyedropper_id";
356 ot->description = "Sample a data-block from the 3D View to store in a property";
357
358 /* API callbacks. */
359 ot->invoke = datadropper_invoke;
360 ot->modal = datadropper_modal;
361 ot->cancel = datadropper_cancel;
362 ot->exec = datadropper_exec;
363 ot->poll = datadropper_poll;
364
365 /* flags */
367
368 /* properties */
369}
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:164
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
ARegion * BKE_area_find_region_xy(const ScrArea *area, int regiontype, const int xy[2]) ATTR_NONNULL(3)
Definition screen.cc:875
SpaceType * BKE_spacetype_from_id(int spaceid)
Definition screen.cc:257
ARegionType * BKE_regiontype_from_id(const SpaceType *st, int regionid)
Definition screen.cc:267
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:846
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
#define SNPRINTF_UTF8(dst, format,...)
#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:618
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:167
#define C
Definition RandGen.cpp:29
@ UI_BUT_UNDO
@ UI_BUT_VALUE_CLEAR
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)
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)
@ EYE_MODAL_CANCEL
@ EYE_MODAL_SAMPLE_CONFIRM
void eyedropper_draw_cursor_text_region(const int xy[2], const char *name)
#define GS(x)
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:414
char name[258]
Definition DNA_ID.h:432
ID * owner_id
Definition RNA_types.hh:51
void * data
Definition RNA_types.hh:53
struct SpaceType * type
int ymin
int xmin
ButType type
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
int xy[2]
Definition WM_types.hh:761
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:4238
wmOperatorType * ot
Definition wm_files.cc:4237